kotlin 类

kotlin中使用class申明类

构造函数

构造函数分为主构造函数、次构造函数

主构造函数

kotlin中可以在申明类时申明一个构造函数,并且次构造函数为 主构造函数

1
2
// 申明了主构造函数
class Person constructor(var name: String, var age: Int ) {}

如果主构造函数没有使用任何注解或者修饰符,则可以省略constructor关键字

1
class Person (var name: String, var age: Int ) {}

主构造函数不能含有代码块,有需要初始化的代码可以放在以init关键字作为前缀的初始化块中。
其中init可以申明多个,会根据代码顺序来执行。

1
2
3
4
5
6
7
8
9
class Person (var name: String, var age: Int ) {
var myName = name;
init {
println("this person's name was ${myName}");
}
init {
println(" test ");
}
}

如果没有申明主构造函数,系统会自动创建一个无参的主构造函数。

次构造函数

次构造函数必须要用constructor申明,
如果有主构造函数,必须将次构造函数委托给主构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyPerson(str: String, var age: Int) {

var name = str;
var tall:Double? = null;

init {
println("init test ${name}");
}

constructor(str: String, age: Int, tall: Double?):this(str, age) {
this.tall = tall;
}

}

初始化init代码块实际上会成为主构造函数的一部分。
当次级构造函数委托给主构造函数,init代码块会成为次级构造函数的第一句语句。
即使该类没有主构造函数,这种委托也会隐式发生,仍会执行初始化代码块。

如果一个非抽象类没有申明任何主、次构造函数,默认会生成一个不带参的主构造函数。
函数的可见性为public。如果不想类有一个公有构造函数,需要声明一个private的主构造函数。

1
class TestClass private constructor () {}

在JVM上,如果主构造函数中的所有参数都有默认值,则会默认生成一个额外的无参构造函数,它将使用默认值。

创建类的实例

kotlin 在创建实例时,不需要new 关键字

1
2
class MyPerson(str: String, var age: Int) {}
var person = MyPerson("jack", 11);

类成员

  • 构造函数与初始化代码块
  • 函数
  • 属性
  • 嵌套类、内部类
  • 对象申明

继承

在kotlin中,所有类都有一个超类 Any,这对于没有超类型声明的类是默认超类:

var oneClass; // 从Any隐式继承

Any 类中有三个方法 equas()、 hashcode()、 toString(), 因此所有kotlin类都定义有这三个方法

默认情况下,kotlin中类都是final 的,不可被继承,如果需要声明该类可以被继承,需要使用关键字 open。

并且kotlin中是使用 : 来表示继承。

1
2
open class TestClassSuper {}
class TestClassChild : TestClassSuper {}

如果超类中有声明主构造函数,
则子类可以声明主构造函数,则并必须用子类中主构造函数参数初始化超类。
如果子类没有声明主构造函数,则必须声明次级构造函数,并且使用super初始化基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
open class MyPerson(str: String, var age: Int) {
var name = str;
var tall:Double? = null;

init {
println("init test ${name}");
}
constructor(str: String, age: Int, tall: Double?):this(str, age) {
this.tall = tall;
}

}

class TestPerson(str: String, age: Int) : MyPerson(str, age) {}

class Test2 : MyPerson {
constructor(str: String, age: Int):super(str, age);
constructor(str: String, age: Int, tall: Double?): super(str, age, tall);
}

函数的重写

正如类的继承需要申明open标识该类开放继承,
类中的函数标识可以被重写也是需要使用open申明,如果没有函数没有申明open,
则在子类中不允许出现同名并且同参数类型的函数。
出现同名但不同参数的函数时允许的,正如java中的重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
open class MyPerson(str: String, var age: Int) {
var name = str;
var tall:Double? = null;

init {
println("init test ${name}");
}
constructor(str: String, age: Int, tall: Double?):this(str, age) {
this.tall = tall;
}

open fun testMethod() {

}

fun test1() {

}
}

class TestPerson(str: String, age: Int) : MyPerson(str, age) {}

class Test2 : MyPerson {
constructor(str: String, age: Int):super(str, age);
constructor(str: String, age: Int, tall: Double?): super(str, age, tall);

override fun testMethod() {
super.testMethod()
}

fun test1(str:String) {

}
}

属性的重写

同函数的重写,属性的重写也是需要使用open标识,并在子类中使用override

1
2
3
4
open var i = 2;

// childClass
override var i = 4;

在属性的重写中,有一点需要注意,
可以用var 重写val,却不能用val重写var;这一点是和java不一样的。
因为用val申明的属性本质上申明了get方法,而将其重写为var只是在子类新增了一个set方法

派生类的初始化顺序

1、进入子类的构造函数
2、进入父类的构造函数并完成初始化
3、进入父类的init代码块
4、父类中属性的初始化
5、子类构造函数完成初始化
6、子类init代码块
7、子类属性初始化

调用父类方法或属性

可以使用super关键字

1
2
3
4
// 方法
super.method();
// 属性
super.nema;

内部类中调用外部类父类属性或方法,使用super@Outer

1
super@OutClass.method();