提示:此文章仅作为本人记录日常学习使用,若有存在错误或者不严谨得地方,欢迎各位在评论中指出。
一、类的继承
Kotlin语言和Java语言都是单继承,它们的区别在于Kotlin中用冒号":"代替了Java中的"extends"关键字。
1.1 类与对象
在开始类的继承之前,我们先来了解一下如何用Kotlin语言声明一个类并对其进行实例化。
class Person {
//字段
var name = ""
var age = 0
//方法
fun eat() {
println(name + "is eating. He is " + age + "years old.")
}
}
通过以上代码我们就成功定义了一个Person类,并使用var关键字(为了后续可以对其重新进行赋值)声明了name和age这两个字段。接下来,我们在Person类中声明了一个eat()方法,并让它打印一句话。
Person类已经创建好了,现在我们来了解一下如何对这个Person类进行实例化(创建对象):
val p = Person()
我们使用val关键字定义了一个不可变的变量p,并且通过Person()构造函数创建了一个Person对象。
1.2 类的继承
在类的继承上,Kotlin和Java还是存在些许不同的。在Kotlin语言中,一个类若想要被继承,需要在这个类前面加上open关键字。
//通过open关键字来告诉Kotlin编译器 Person这个类是专门为继承而设计的
open class Person {
· · ·
}
为了更好地理解类的继承,我们来看一段示例代码。在这段代码中我们声明了一个Student类和一个Person类,并让Student类继承自Person类:
//Person类(open关键字让该类允许被继承)
open class Person {
}
//Student类继承自Person类
子类 继承 父类
class Student : Person() {
var sno = ""
var grade = 0
}
二、构造函数
Kotlin语言中将构造函数分成了两种:主构造函数和次构造函数。我们使用最多的就是主构造函数,而次构造函数接触的机会很少很少。
1.1 主构造函数
在Kotlin语言中每个类默认都会有一个不带参数的主构造函数,我们也可以显式的给它指明参数。主构造函数的特点就是没有函数体,直接定义在类名的后面:
子类 主 构 造 函 数 继承 父类
class Student(val sno: String, val grade: Int) : Person() {
}
在上述代码中我们将“学号sno”和“年级grade”都放入到主构造函数中。在对Student类进行实例化(创建对象)的时候,必须传入构造函数中要求的所有参数:
val student = Student("s10001", 6)
通过这种方式我们就创建了一个Student对象,他的学号是s10001,他的年级是6。
1.1.1 主构造函数——init结构体
前面我们说过"主构造函数直接定义在类名的后面,是没有函数体的"。那么我们该如何在主构造函数中添加逻辑呢?Kotlin语言提供了一个叫init{ }的结构体,所有主构造函数中的逻辑都可以写在init{ }结构体中。
class Student(val sno: String, val grade: Int): Person() {
init {
println("sno is:" + sno + "grade is:" + grade)
}
}
需要注意的是,在Kotlin语言中要求子类的构造函数必须调用父类中的构造函数。所以在前面Student类继承Person父类时,Person类后面的那一对括号其实代表Student子类的主构造函数在初始化的时候会调用Person父类的无参构造函数。
父类的无参构造函数
class Student(val sno: String, val grade: Int) : Person() {
}
前面我们定义的Person类中有name和age两个字段。
class Person {
var name = ""
var age = 0
fun eat() {
println(name + "is eating. He is " + age + "years old.")
}
}
如果我们尝试将Person类改造一下,把姓名和年龄都放到主构造函数中。
class Person(val name: String, val age: Int) {
fun eat() {
println(name + " is eating. He is " + age + " years old.")
}
}
此时,Student类中以下代码的Person()是会报错的:
报错
class Student(val sno: String, val grade: Int): Person() {
init {
println("sno is:" + sno + "grade is:" + grade)
}
}
报错的原因是 Person()表示要调用Person类的无参构造函数,但是Person类现在已经没有无参构造函数了,所以就会报错。若想解决这个问题需要给Person类的构造函数传入name和age这两个字段。我们可以在Student类的主构造函数中加入name和age这两个参数,再将这两个参数传给Person类的构造函数:
//Person()会报错
class Student(val sno: String, val grade: Int): Person() {
· · ·
}
|
| fix
|
V
//Person()不会报错
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参数前面不用添加任何关键字,让他的作用域只限定在主构造函数当中即可。
val student = Student("s10001", 6 , "Mike", 18)
1.2 次构造函数
次构造函数使用的场景很少,任何一个类只能有一个主构造函数,但是却可以有多个次构造函数。Kotlin语言规定,当一个类中既有主构造函数又有次构造函数时,所有的次构造函数都必须(直接或者间接)的调用主构造函数。次构造函数是通过constructor关键字来定义的:
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name,age) {
//次构造函数①:接收2个参数,并通过this关键字调用4个参数的构造函数(主构造函数)
constructor(name: String, age: Int) : this("", 0, name, age) {
}
//次构造函数②:不接收任何参数,并通过this关键字调用2个参数的次构造函数①
//由于次构造函数①调用了主构造函数,而次构造函数②又调用了次构造函数①
//相当于次构造函数②间接调用了主构造函数,是符合Kotlin语言要求的
constructor() : this("", 0) {
}
}
接下来我们就可以通过三种方式来对Student类进行实例化:①通过不带参数的构造函数②通过带两个参数的构造函数③通过带四个参数的构造函数。
//对应次构造函数② constructor() : this("", 0)
val student1 = Student()
//对应次构造函数① constructor(name: String, age: Int) : this("", 0, name, age)
val student2 = Student("Mike", 18)
//对应主构造函数
val student3 = Student("s10001", 6, "Mike", 18)