Kotlin 做为类 Java 语言,在面向对象上具备与 Java 类似的特性,可是针对不一样的状况进行了不一样的优化,今天咱们简单介绍一下 Kotlin 中的类和构造函数。java
Kotlin 中定义类与 Java 相同,使用 class 关键字:app
class 类名[主构造函数][{ //类成员 }]
Kotlin 中的类名与 Java 相同,采用骆峰式命名法,首字母大写。ide
不一样的是,Kotlin 中的类若是是空类,没有任何语句,则能够省略大括号(闲的)。函数
要建立一个类的实例,只须要调用类的构造函数,不使用 new 关键字:优化
val s = StringBuilder("Hello World")val list: List<String> = ArrayList()
Kotlin 类的构造函数与 Java 有较大区别。首先,Kotlin 把构造函数分为 主构造函数 和 次构造函数,主构造函数写在类头中,有且只有一个;次构造函数写在类语句中,能够有多个,也能够没有。ui
首先,咱们看一个简单的 Java 类:this
public class Person { String name; public Person(String name) { this.name = name; }}
这个类定义一个 String 类型的成员变量 name,而后定义了带有一个 String 类型参数的构造函数,这个构造函数把参数列表中的 name 赋给了成员变量 name。spa
用 Kotlin,咱们能够这样写:orm
class Person constructor(name: String) { val name: String init { this.name = name }}
首先,咱们使用 class 定义了一个类 Person,而后在类头用 constructor 关键字定义带有一个 String 类型参数的主构造函数。在类体里,咱们定义了一个不可变的 String 类型成员变量 name,而后使用 init 关键字定义主构造函数的行为,把主构造函数的 name 参数赋给成员变量 name。对象
能看到,Kotlin 类的主构造函数,参数列表定义在类声明的部分,函数体却在 init 代码块里。(莫名其妙)
这样写不够简洁呀!实际上,充分利用 Kotlin 提供的特性,咱们能够把这个类缩短到一行:
class Person(val name: String)
看吧,全部冗余信息都已除去,只保留了最关键的部分。想理解这句话,咱们须要知道主构造函数定义中的两个细节:
若是主构造函数没有任何修饰符,则能够去掉 constructor 关键字。这样,咱们的类定义就很像一个函数了:
class Person(name: String) {/*……*/}
若是想使用在主构造函数前使用修饰符,那么这个 constructor 就不能省了:
class Person private constructor() {/*……*/}
若是主构造函数中定义的参数使用 val 或者 var 修饰,则会建立与这个参数同名的成员变量,并使用传入的参数值初始化这个成员变量。简单来讲,就是把“定义成员变量”和“使用构造函数传入的参数初始化成员变量”简化为一个 val 或者 var 关键字。
上面的例子中,咱们在主构造方法里声明 val name: String,Kotlin 就会自动为咱们添加一个名为 name 的不可变的 String 类型成员变量,而后用主构造函数传入的值初始化这个成员变量,能够直接调用。
Java 中,一个类每每有多个不一样的构造函数,它们通常有下面两种关系:
参数列表由少到多,参数列表少的构造函数使用 默认值 调用参数列表多的构造函数。对于这个常见的类型,Kotlin 中使用 函数默认参数 的方法简化代码;
不一样的构造方法使用不一样的参数列表,相互之间存在调用关系。Kotlin 中使用 次构造函数委托 的解决方法。
首先看第一种状况,这里咱们给用 Java 写的 Person 类添加一些东西:
public class Person { long id; String name = ""; int age = 0; public Person(long id, String name, int age) { this.id = id; this.name = name; this.age = age; } public Person(long id, String name) { this.id = id; this.name = name; } public Person(long id, int age) { this.id = id; this.age = age; } public Person(long id) { this.id = id; }}
咱们添加了两个属性,一个 long 类型的 id,一个 int 类型的 age。三个构造函数都须要传入 id 变量,name 和 age 变量的要求则是 若是没有外部传入的参数,就使用默认值。
使用 Kotlin,咱们能够大大简化这一长串代码:
class Person(val id: Long, val name: String = "", val age: Int = 0)
好吧,Kotlin 又是只用一行就解决了问题……
咱们重点看一下参数列表:
参数列表中定义了三个参数,都使用 val 关键字修饰,说明要使用它们建立成员变量并初始化;
name 和 age 参数后面都使用 = 默认值 的方法声明了它们的默认值,在调用主构造函数的时候,若是不传入参数,就使用指定的默认值。
对于构造函数的第二种类型:使用没有关系的参数列表,但存在调用关系,Kotlin 中的处理方式是使用次构造函数委托主构造函数。咱们接着改一下 Person 类:
public class Person { long id; String name = ""; public Person(long id) { this.id = id; } public Person(String name) { this(name.hashCode()); this.name = name; }}
使用 Kotlin,咱们能够这样写:
class Person(val id: Long) { var name: String = "" constructor(name: String) : this(name.hashCode().toLong()) { this.name = name }}
首先,咱们在主构造函数里声明了并初始化了成员变量 id,而后在类体内使用 constructor 关键字定义一个带有一个 String 类型参数的 次构造方法,这个次构造方法先调用主构造函数,而后将参数赋给成员变量。这里有几个须要注意的地方:
若是类已经有了一个主构造函数,那么全部的次构造函数都要直接或间接地委托给主构造函数。也能够先委托给其余的次构造函数,再由它们委托给主构造函数。全部的次构造函数都会先调用主构造函数,再执行本身特有的代码。写法:
constructor([参数列表]): this([参数列表]) {/*……*/}
次构造函数不能在参数列表中声明并初始化成员变量,这也是上面“name: String”前面为何没有 val 的缘由。并且由于次构造函数会改动 name 的值,因此 name 必须声明为 var。