定义类

类使用class关键字定义,类的定义分为三个部分,类名、类头部、类主体,其中类头包括类的类型参数、主构造器等,如下面定义的类:


/** * 定义一个学生类,继承自Person类 */ class Student constructor(grade: String, id: Long) : Person() { fun exam() {//考试方法    } }



构造器

类中可以有一个主构造器和多个可选的次构造器,主构造器位于类名后面,使用关键字constructor标识,如上面的constructor(grade:String,id:Long),如果主构造器没有任何注解和修饰符,constructor关键词可以省略。如果有次构造器,次构造器需要使用this关键字委托给主构造器初始化。构造器里面不能含有任何代码,可以给构造器里面的参数设置一个默认的值,初始化代码可以放在初始化代码段中,主构造器里面的参数只能在初始化代码段中或者全局变量初始化时使用。在JVM中,如果主构造器所有的参数都指定了默认值,那么编译器会自动生成一个没有参数的默认构造器。示例如下:


open class Person constructor(sex: String = "男", age: Int) {//sex参数定义了默认值 constructor(age: Int) : this("男", age)//直接使用主构造器代理 constructor() : this(18)//通过次构造器间接使用主构造器代理 }

如果需要定义一个与构造方法中的参数一样的全局变量,可以使用更加简洁的写法:

class Student constructor(var grade: String, var id: Long) : Person() { fun exam() {//考试方法        //因为构造方法中参数添加了var关键字,所以参数已经是一个全局变量了,所以能在这里使用        print("grade:" + grade + ",id:" + id) } }




初始化代码段

Kotlin中使用init关键字定义一个初始化代码段,类似于Java中的静态代码块,如下所示:

init { //这里可以做初始化的操作,可以使用构造方法中的参数    print("age:" + age + ",sex:" + sex) }




创建类的实例

Kotlin中没有new关键字,创建类的实例直接使用类名和构造器就可以,如下:

var student = Student("三年级", 102017)




继承

Kotlin中不管是实现接口还是继承类都是使用":"号来表示,多继承使用逗号隔开。

所有的类默认继承Any,Any类似于Java中的Object,是所有类的祖先类,其有toString、hashcode、equals三个方法。

如果子类有主构造器,必须使用主构造器的参数初始化基类,如果没有主构造器,则在次构造器中使用super关键字来初始化基类,这里不同的次构造器可以调用基类不同的构造方法。

被继承的基类必须是open修饰的,默认的类都不是open修饰的,所以默认类是无法被继承的。




方法和属性的覆盖

子类只能覆盖父类使用open修饰的方法,子类复写的方法需使用override关键字修饰,并且子类复写的方法也是open的,也就是说其还能被自己的子类复写,如果想改变这种情况,只需要在override前面使用关键字final.

属性的覆盖也类似方法,只能覆盖使用open修饰的,并且也需要关键字override。覆盖的属性类型必须与基类兼容,也就是子类型的属性类型必须是父类型的子类。可以使用var类型来覆盖val类型的,反过来则不行。




调用父类的方法

子类可以使用super关键字来调用父类的方法或属性。也可以使用super@外部类名字来访问外部类的属性和方法。如下:

fun teach() { super.speaker() }

访问外部类的基类:

class Xiaomin : Teacher, Person() { inner class IdCard { fun printBaseName() { super@Xiaomin.speaker() } }




覆盖的规则

如果一个类继承了多个父类,而其中父类之间有相同的名字的方法,那么子类需要一定的规则来区分覆盖的是哪个类的方法,这时就需要使用super<Base>这种方式来表示覆盖的是哪个类的方法。如下所示:

class Xiaomin : Teacher, Person() { override fun eat() {//Teacher是一个接口,Person类中的eat方法必须是open的,否则编译不通过 super<Teacher>.eat() } }





抽象类、接口

抽象类和接口类似于Java中的,抽象类使用abstract关键字,接口使用interface。需要注意的是抽象的类和接口不需要使用open关键字来修饰就可以直接被覆盖。如下:

class Xiaomin : Teacher, Person() { override fun eat() { super<Teacher>.eat() } }

interface Teacher { fun eat() }




同伴对象

这块会单独的使用一篇文章来详细的描述。