学习kotlin时,有很多小伙伴无法理解为何有的继承结构父类后面需要加括号,有时候却不用加括号,本篇文章小编将为你们解除这个困惑!顺便为大家详解一下kotlin中的主构造函数和次构造函数。
首先我们先来了解一下kotlin中的继承:
比如我们现在要定义一个Student类,每个学生都有自己的学号和年级,我们在Student类中加入sno和grade字段,同时每个学生又都是人,有自己的年龄和名字而且都会睡觉,如果在Student类中重复定义age和name字段还有sleep()函数的话就显得过于冗余,这时我们就可以让Student类去继承Person类,这样就拥有了Person类中的字段和函数了。
那么kotlin中如何让Student类继承Person类呢,我们分为两个步骤,首先让Person类可以被继承,第二步就是让Student类继承于Person类。
这里我们就看到kotlin与java的不同了,在kotlin中,任何一个非抽象类都是默认不可被继承的,相当于java中声明了final关键字。
接下来我们就让Person类能够被继承,很简单,只需要在类前加入open关键字就好了。如下所示:
open class Person{
...
}
第二步就是让Student类继承于Person类,不同于java的extends关键字,kotlin中继承使用的时冒号。写法如下:
class Student : Person() {
var sno = " "
val grade = 0
}
这里就出现了我们刚开始提到的,Person类后面我们加入了一个括号,这里就涉及到了一个规定,子类中的构造函数必须调用父类中的构造函数,这里的括号就是代表Student类(子类)的主构造函数调用Person类(父类)的无参构造函数,每个类默认都有一个不带参数的主构造函数,当然也有特殊情况,当一个类没有显式地定义主构造函数且定义了次构造函数时,那么这个类就是没有主构造函数。(这里我们在文章后面还会再提到)接下来我们就来详细介绍一下kotlin中的主构造函数和次构造函数。
我们说到每个类都会默认有一个不带参数的主构造函数,当然可以显式地给它指明参数,,主构造函数的特点就是没有函数体,直接定义在类名的后面即可,写法如下:
class Student(val sno : String,val grade : Int) : Person(){
}
这里我们将学号和年级两个字段都放入主构造函数中,当我们对Student类进行实例化时,必须传入构造函数中要求的所有参数,写法如下:
val student = Student("zk123",6)
既然主构造函数没有函数体,如果我想在主构造函数中编写一些逻辑怎么办呢?当然有办法,kotlin提供了一个init结构体,所有主构造函数中的逻辑都可以写在里面,写法如下:
class Student(val sno : String,val grade : Int) : Person(){
init{
println("sno is $sno")
println("grade is $grade")
}
}
这里简单打印了一下学号和年级的值。
我们改造一下Person类:
open class Person(val name : String,val age : Int){
}
那么子类Student类的主构造函数调用父类Person类的构造函数就可以这样写:
class Student(val sno : String,val grade : Int,name : String,age : Int) :
Person(name,age){
}
注意Student类的构造函数中加入的name和age字段不再声明为val或var,假设声明了val或var会自动成为该类的字段,会导致和父类中的name和age字段发生冲突。接下来创建实例就可以这样写:
val student = Student("zk123",6,"Tom",20)
接下来我们来了解一下次构造函数:
任何一个类只能有一个主构造函数,但可以有多个次构造函数,次构造函数也可以用于实例化一个类,且次构造函数是有函数体的。
次构造函数是通过constructor关键字来定义的。
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() : this("",0){
}
}
这里我们定义了两个次构造函数,第一个次构造函数接收name和age两个字段,并通过this关键字调用了主构造函数;第二个构造函数不接收任何参数,通过this关键字调用了我们定义的第一个次构造函数,由于第一个次构造函数调用了主构造函数,所以第二个次构造函数等于间接调用了主构造函数,所以也是合法的。
接下来我们创建实例就可以通过次构造函数进行创建,写法如下:
val firstStudent = Student("Dick",20)
val secondStudent = Student()
接下来我们回到上面说到的特殊情况,当一个类没有显式地定义主构造函数且定义了次构造函数时,那么这个类就是没有主构造函数。那既然这个类没有了主构造函数,那这时次构造函数肯定没办法调用主构造函数,此时就得调用父类的构造函数,写法如下:
class Student : Person{
constructor(name : String,age : Int) : super(name,age){
}
}
细心的同学会发现,这里的Person类后面没有了括号,因为此时的Student没有主构造函数,所以不需要调用在主构造函数中调用Person类的构造函数,即不需要再加括号。
希望这些对大家能有帮助,有不足欢迎大家补充,本篇也是参考郭神的文献,自己梳理一遍方便复习。