Kotlin语言中文站
Kotlin中使用关键字class
声明一个类,类声明由类名、类头(指定其类型参数、主构造函数等)
以及由花括号包围的类体
构成。 类头、类体是可选的,如果一个类没有类体,可以省略花括号
。
//声明Person类
class Person { /* .... */ }
//没有类体,可以省略花括号
class Person
在kotlin中一个类可以有一个或者没有主构造函数
以及一个或多个次构造函数
。主构造函数是类头的一部分,它跟在类名(与可选的类型参数)后面。
//携带主构造函数的Person类
class Person constructor(firstname: String) { /* ... */ }
//如果主构造函数没有任何注解或者可见性修饰符,可以省略 constructor 关键字
class Person(firstname: String) { /* ... */ }
主构造函数不能包含任何的代码,那如果我想增加一些初始化代码怎么办? kotlin中的初始化块 init
应运而生。
class Person(firstname: String) {
//主构造器的参数firstname也可以在类体内声明的属性初始化器中使用
val propertyOne = "propertyOne##firstname:$firstname.".also { println(it) }
//初始化块1
init {
//这里可以使用主构造器的参数firstname
println("init1##firstname:$firstname.")
}
//主构造器的参数firstname也可以在类体内声明的属性初始化器中使用
val propertyTwo = "propertyTwo##firstname:$firstname.".also { println(it) }
//初始化块2
init {
//这里可以使用主构造器的参数firstname
println("init2##firstname:$firstname.")
}
}
//执行上面的代码
fun main(args: Array<String>) {
Person("hepingdev")
}
//打印结果
propertyOne##firstname:hepingdev.
init1##firstname:hepingdev.
propertyTwo##firstname:hepingdev.
init2##firstname:hepingdev.
如上,一个类可以有一个或多个初始化块
,初始化块按照它们出现在类体中的顺序执行,与属性初始化器优先级一样
。 这里我们不妨把上面的代码转成Java代码,看看init到底是个啥?
public final class Person {
@NotNull
private final String propertyOne;
@NotNull
private final String propertyTwo;
@NotNull
public final String getPropertyOne() {
return this.propertyOne;
}
@NotNull
public final String getPropertyTwo() {
return this.propertyTwo;
}
//主构造函数
public Person(@NotNull String firstname) {
super();
String var2 = "propertyOne##firstname:" + firstname + '.';
System.out.println(var2); ----> 打印属性1
this.propertyOne = var2;
var2 = "init1##firstname:" + firstname + '.';
var3 = false;
System.out.println(var2); ----> 打印初始化块1
var2 = "propertyTwo##firstname:" + firstname + '.';
System.out.println(var2); ----> 打印属性2
this.propertyTwo = var2;
var2 = "init2##firstname:" + firstname + '.';
System.out.println(var2); ----> 打印初始化块2
}
}
由上可知,它的作用就是在主构造函数里面增加操作性代码
,即初始化块中的代码实际上会成为主构造函数的一部分
。
类中声明前缀有constructor
的次构造函数。
class Person {
//次构造函数
constructor(secondname:String, modifydata:String) {
println("secondname:$secondname modifydata:$modifydata")
}
}
次构造函数可以简单理解:解决kotlin中只能定义一个主构造函数的缺陷
,毕竟开发中类会存在多个构造器的需求。
如果类有主构造函数,每个次构造函数必须委托给主构造函数(否则会编译报错),可直接委托或者通过别的次构造函数间接委托,通过关键字this
进行委托。
class Person(name:String) {
init {
println("init####.")
}
constructor(name:String, age: Int) : this(name, age, "") {
println("constructor##间接委托")
}
constructor(name: String, age: Int, address: String) : this(name) {
println("constructor##直接委托")
}
}
没有主构造函数,虽然不用显式声明委托,但实际仍会隐式发生委托,从如下代码打印结果可看出:
class Person {
init {
println("init####.")
}
constructor(name:String, age: Int) {
println("constructor##2")
}
constructor(name: String, age: Int, address: String) {
println("constructor##3")
}
}
fun main(args: Array<String>) {
Person("hepingdev", 100, "中国")//打印什么?
//打印结果
init####.
constructor##3
Person("hepingdev", 100)//打印什么?
//打印结果
init####.
constructor##2
}
上面说到,初始化块实际上会成为主构造函数的一部分,委托给主构造函数会作为次构造函数的第一条语句,因此所有初始化块与属性初始化器中的代码都会在次构造函数之前执行。即使类没有主构造函数,这种委托仍会隐式发生,并且仍会执行初始化块
。
如果一个非抽象类没有声明任何(主/次)构造函数,那么会自动生成一个不带参数的主构造函数
:
//kotlin类
class Person
//java代码如下
public final class Person {
//一般默认不写
public Person(){}
}
类中声明属性kotlin有个简洁的写法:
class Person(var name:String, var age: Int, var address: String) { ... }
上面是在主构造函数声明,当然也可以在类体中声明:
class Person {
var name:String = ""
var age: Int = 0
var address:String=""
}
转成Java代码如下所示:
/** 主构造函数声明 */
public final class Person {
@NotNull
private String name;
private int age;
@NotNull
private String address;
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
this.name = var1;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
@NotNull
public final String getAddress() {
return this.address;
}
public final void setAddress(@NotNull String var1) {
this.address = var1;
}
public Person(@NotNull String name, int age, @NotNull String address) {
this.name = name;
this.age = age;
this.address = address;
}
}
/** 类体中声明 */
public final class Person {
@NotNull
private String name = "";
private int age;
@NotNull
private String address = "";
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
this.name = var1;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
@NotNull
public final String getAddress() {
return this.address;
}
public final void setAddress(@NotNull String var1) {
this.address = var1;
}
}
两种写法没啥区别。
注意 Kotlin 没有 new
关键字。
//无参构造函数
val p = Person()
//携带参数的构造函数
val p = Person("hepingdev", 100, "中国")
如下代码, 打印什么?
class Person(name: String, age: Int) {
var name: String = "i am $name, $age years old.".also { println(it) }
init {
println("init####.")
}
constructor(name: String, age: Int, address: String):this(name, age) {
println("constructor##i am $name, $age years old, from $address")
}
}
fun main(args: Array<String>) {
//调用主构造函数
Person("hepingdev", 100) //打印什么
//打印如下
//i am hepingdev, 100 years old.
//init####.
//调用次构造函数
Person("hepingdev", 100, "中国")//打印什么
//打印如下
//i am hepingdev, 100 years old.
//init####.
//constructor##i am hepingdev, 100 years old, from 中国
}
根据打印结果,结论如下:
super() -> init() / 属性初始化器
super() -> init() / 属性初始化器 -> 次构造函数
下一篇:Kotlin学习历程——继承。