1、在Kotlin中任何一个非抽象类(抽象类本身是无法创建实例的,一定要由子类去继承它才可以创建实例,因此抽象类必须可以被继承才行)默认都是不可以被继承的,相当于Java中给类声明了final关键字,之所以这么设计,原因与val相似,如果一个类不是专门为继承而设计的,那么就应该主动将它加上final声明,禁止它可以被继承。
2、使类可以被继承,可以添加open关键字:
open class Person{
}
3、子类继承父类时,Java中的关键字是extends,在Kotlin中变成冒号:
class Student : Person(){// 在父类之后添加()的原因涉及主构造函数和次构造函数如下描述
var sno = ""
var grade = 0
}
4、任何一个面向对象编程语言都有构造函数概念,Kotlin中将构造函数分成了两种:主构造函数和次构造函数。
4.1、主构造函数是最常用的构造函数,每个类都会默认有一个不带参数的构造函数,也可以显式的给它指明参数,主构造函数的特点是没有函数体,直接定义在类名的后面即可;
class Student(val sno: String, val grade: Int) : Person(){
// 将学号和年纪放在主构造函数中,表明在对Student类进行实例化的时候,必须传入构造函数中要求的所有参数
// 由于构造函数中的参数是在创建实例的时候传入的,不会需要重新赋值,因此可以将参数全部声明成val
}
如果想在主构造函数中编写一些逻辑:
class Student(val sno: String, val grade: Int) : Person(){// Person类后面的一对空括号表示Student类的主构造函数在初始化的时候会调用Person类的无参数构造函数,即使在无参数的情况下,这对括号也不能省略
init {// 所有主构造函数中的逻辑都可以写在init结构体中
println("sno is " + sno);
println("grade is " + grade);
}
}
相同于Java继承特性中的一个规定,子类中的构造函数必须调用父类中的构造函数,可是构造函数并没有函数体,在绝大多数场景下,我们是不需要编写init结构体的,因此在继承父类时,在父类的后面加上括号,子类的主构造函数调用父类中的哪个构造函数,在继承的时候,通过括号来指定。
继承有参数的构造函数的写法:
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name,age){
// 注意:在Student类的主构造函数中增加name和age时,不能再将它们声明成val,因为在主构造函数中声明成val或者var的参数,将自动成为该类的字段,这就会导致和父类中同名的name和age造成冲突
// 因此,name和age参数前面不用加任何关键字,让它的作用域仅限定在主构造函数当中即可
}
4.2、任何一个类只能有一个主构造函数,但是可以有多个次构造函数。
次构造函数也可以用于实例化一个类,同主构造函数一样,只不过它是有函数体的。
Kotlin规定:当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)。
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age){
constructor(name: String, age: Int) : this("", 0, name, age){
//次构造函数是通过constructor来定义的,第一个次构造函数接收name和age参数,然后它用通过this关键字调用了主构造函数,并将sno和grade这两个参数赋值成初始值
}
constructor() : this("", 0){
//第二个次构造函数不接收任何参数,它通过this关键字调用第一个次构造函数,并将name和age参数赋值成初始值,第二个次构造函数间接调用了主构造函数
}
}
4.3、类中只有次构造函数,没有主构造函数,这种情况十分少见,但是在Kotlin中是允许的。
class Student : Person {
constructor(name: String, age: Int) : super(name,age){
}
}
Student类的后面没有显式的定义主构造函数,同时又因为定义了次构造函数,所以现在Student类是没有主构造函数的;
既然没有主构造函数,继承Person类的时候也就不需要再加上括号了;
由于没有主构造函数,次构造函数只能直接调用父类的构造函数。
网友评论