3.1类的声明
和Java一样,类的声明使用class关键字,如果声明一个空类,Kotlin和Java没有任何区别。
|
|
3.2构造器
类允许定义一个主构造器和若干个第二构造器。
主构造器
主构造器是类头的一部分,紧跟在类名后面,构造器参数是可选的。
|
|
如果主构造器没有任何注释和修饰器,constructor关键字可省略
|
|
主构造器需要在init块中进行初始化,在init块中可以直接使用主构造器的参数。
|
|
主构造器的参数不仅可以用在init块中,还可以用于对类属性进行初始化。
|
|
注意:即使在构造器内部使用var声明变量,修改参数变量值后,并不会把修改的值传到对象外部。
第二构造器
Kotlin可以声明若干个第二构造器。第二构造器需要在类中声明,前面必须要加constructor关键字。
如果类中声明了主构造器,那么所有的第二构造器都需要在声明后面调用主构造器,或者通过另外一个第二构造器间接地调用主构造器。
|
|
调用QACommunity类的每个构造器:
|
|
运行结果:
|
|
注意:在主构造器参数中可以使用可以使用var和val,但在第二构造器参数中不能使用var和val。这就意味着第二构造器的参数都是只读的,不能在构造器内部改变参数的值。
Kotlin中的Singleton模式
|
|
执行下面代码,访问Singleton类:
|
|
运行结果:
|
|
执行这段代码后,会输出如下内容,我们会发现。obj1和obj2的输出结果完全一样。这就证明了obj1和obj2是完全一样的。
Kotlin函数中的默认参数
Kotlin函数支持默认参数,例子:
|
|
如果创建Customer的实例,可以直接使用Customer()。customerName和value的参数值就会使用Bill和20.4。
创建类的实例
在Kotlin中创建类的实例不需要使用new关键字。因此,调用函数和创建类的实例在语法上没有区别。只能通过上下文来区分。
3.3类成员
属性的基本用法
|
|
在属性语法中,只有var/val和propertyName(属性名)是必须的,其他都是可选的。如果要引用属性,就行引用变量一样。
|
|
属性的getter和setter形式
如果属性是只读的,需要将属性声明为val,并只添加一个getter形式,如果属性是读写的,需要使用var是声明属性,并添加getter和vsetter形式。如果getter和setter中只有一行实现代码。直接用=分割getter和代码即可。如果包含多行代码需要使用{……}处理。
|
|
保存属性值的字段
在属性的getter和setter中,可以将field当做成员变量使用,也就是通过field读写属性值。
|
|
修改Customer4的value值:
|
|
运行结果:
|
|
函数
函数既可以在类外部定义,也可以在类内部定义。如果是前者是全局函数,如果是后者是类成员函数。
函数也支持默认参数值。要注意的是,带默认值的参数必须是最后几个参数,也就是说,如果某个参数带默认值。那么该参数后面的所有参数都必须有默认值。
|
|
执行代码:
|
|
运行结果:
|
|
如果我们想为下面的函数按顺序传入参数值,很简单
|
|
|
|
如果我们只想修改最后 一个参数的值,安装之前的思路必须每个参数的值都传一遍,很麻烦。为了解决这个问题,Kotlin允许使用命名参数传递参数值。例如:
|
|
如果传入参数的参数个数不固定,就要使用可变参数了,可变参数用vararg关键字声明:
|
|
调用addPersons方法:
|
|
函数单行表达式:如果Kotlin函数体只有一行代码,可以直接在函数声明后面加等号=,后面直接跟代码,这种表达方式可以省略函数返回值类型。
|
|
本地函数:在函数体内定义函数,作用域就是包含本地函数的函数体
|
|
嵌套类
嵌套类就是类中定义的类。
|
|
调用foo方法:
|
|
嵌套类还可以使用inner关键字声明,这样可以通过外部类的实例引用嵌套类
|
|
3.4修饰符(Modifiers)
Kotlin中有private、protected、internal、public 4个修饰符。
- private:仅仅在类的内部可以访问
- protected:类似private,但在子类中也可以访问
- internal:在任何模块内部类都可以访问
- public:任何类都可以访问
如果不指定任何修饰符,默认是public。
|
|
|
|
3.5类的继承
类如何继承
Kotlin类的继承需要使用冒号(:),冒号后需要调用父类的构造器,与Java一样,都是单继承的。要注意的是,Kotlin默认时class是final的,也就是说,默认时class不允许继承,需要显式的使用open关键字允许继承class。
|
|
重写方法
如果要在子类中重写方法,就需要在父类相应的方法前面加open关键字,而且要在子类重写的方法前面加override关键字。
|
|
现在调用Child2l类的getName方法,实际上执行的是Child2自身的getName方法,而不是Parent2类的getName方法。
如果一个方法前加了override,那么这个方法就可以被重写了,例如Child2类的getName方法在子类中是可以被再次重写的。
|
|
如果想阻止getName方法被子类重写,需要在override前面加final
|
|
重写属性
属性的重写方式与方法类似,被重写的属性必须使用open声明,子类中重写的属性必须使用overr声明。注意的是,val属性可以被重写为var属性,但反过来不可以。
|
|
运行结果:
|
|
3.6接口
接口使用interface关键字声明,一个类可以实现多个接口。实现的方法和类继承相似。而且接口中的属性和方法都是open的。
|
|
在Kotlin中,允许接口的方法包含默认的方法体。对于有方法体的接口方法。并不要求一定重写该方法。也就是说getName方法可以在MyClass2中不重写。
3.7抽象类
抽象类不能被实例化,需要使用abstract关键字声明,抽象类实现接口后,接口中没有函数体的函数可以不重写(override),接口中的这些方法就自动被继承到实现接口的抽象类中,称为抽象方法。
|
|
抽象方法不需要使用open声明,因为抽象类本身就是可继承的。