一、作用
二、概念
1. 类与对象
类是对事物的一种封装,可以拥有属性和行为。
(1)定义类
class
关键字
class Person {
var name = ""
var age = 0
fun eat() {
println(name + " is eating. He is " + age + " years old.")
}
}
(2)创建对象
当你调用某个类的构造函数时,你的意图只可能是对这个类进行实例化,即使没有new
关键字,也能清晰表达出你的意图。Kotlin 本着最简化的设计原则,将诸如new
、行尾分号
都取消掉了。
fun testClass() {
val p = Person()
p.name = "hello"
p.age = 10
p.eat()
}
2.继承与构造函数
比如要定义一个Student
类,每个学生都有自己的学号和年级,因此我们可以在Student
类中加入sno
、grade
字段。
但同时学生也是人,学生也会有姓名、年龄,也需要吃饭。
这个时候:可以让Student
去继承Person
。
(1)定义Person
类
在 Kotlin 中任何一个非抽象类默认都是不可被继承的。这所以这么设计,类似于val
,因为类和变量一样,他们最好都是不可变的,一个类如果允许被继承的话,它无法预知子类会如何实现,可能产生一些未知的风险。
抽象类本身是无法创建实例的,一定要由子类去继承它才能创建实例,因此抽象类必须可以被继承才行。
open
关键字让该类允许继承
open class Person {
var name = ""
var age = 0
fun eat() {
println(name + " is eating . He is " + age + " years old.")
}
}
(2)创建Student
类继承Person
类
class Student(val sno: String, val grade: Int) : Person() {
init {
println("sno is " + sno)
println("grade is " + grade)
}
}
3. 主构造函数和次构造函数
Kotlin 中构造函数分为主构造函数和次构造函数。任何一个类只能有一个主构造函数(或没有),可以有多个次构造函数。
(1)主构造函数
Kotlin 类默认情况下有一个无参的主构造函数,主构造函数没有函数体,也可以显式地声明带参的主构造函数,这样无参的主构造函数就没了。
主构造函数中声明成val
或var
的参数将自动称为该类的字段。
// 带参的主构造函数
class Student(val sno: String, val grade: Int) : Person() {
}
(2)次构造函数
Java 的继承特性规定,子类构造函数必须调用父类构造函数,Kotlin 同样遵循这点。【此处的构造函数,即可以是主也可是次,只要是构造函数就行】
Q:回看下面的Student
类,声明了一个主构造函数,但主构造函数并没有函数体,它如何调用父类的构造函数呢?
A:子类的主构造函数调用父类的哪个构造函数,在继承的时候通过括号来指定。下面这个即表示调用父类的不带参的主构造函数。
// 带参的主构造函数
class Student(val sno: String, val grade: Int) : Person() {
}
Kotlin 规定:当一个类中既有主构造函数,又有次构造函数时,所有次构造函数必须调用主构造函数(包括间接调用)。
open class Person(val name: String, val age: Int) {
fun eat() {
println(name + " is eating. He is " + age + " years old.")
}
}
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)
}
【证明:】
当`Student`类中有主构造函数和次构造函数时
Kotlin 要求次构造函数必须调用主构造函数
& Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) 这样的声明方式,使得`Student`类的主构造函数一定会调用父类 Person 的主构造函数
所以:Student 的所有构造函数都会调用父类的主构造函数。『Java 的继承特性规定子类构造函数必须调用父类构造函数』,这个规定得到满足
当一个类没有显式地定义主构造函数且定义了次构造函数时,那这个类中就没有主构造函数。
// 子类构造函数中必须调用父类的构造函数
// Teacher 类中没有主构造函数,所以继承 Person 类的时候也就不需要加上括号了
class Teacher : Person {
constructor(name: String, age: Int) : super(name, age)
}
【证明:】
当`Teacher`类中只有次构造函数时
Kotlin 要求次构造函数必须调用主构造函数
constructor(name: String, age: Int) : super(name, age) 这样的方式,使得这个次构造函数一定会调用父类 Person 的主构造函数
所以:Teacher 的所有构造函数都会调用父类的主构造函数。『Java 的继承特性规定子类构造函数必须调用父类构造函数』,这个规定得到满足
4.接口
(1)override
Kotlin 通过上述关键字来重写父类或实现接口中的函数。
open class Person(val name: String, val age: Int) {
}
interface Study {
fun readBooks()
fun doHomework()
}
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age), Study {
override fun readBooks() {
println(name + " is readBooks")
}
override fun doHomework() {
println(name + " is doHomework")
}
}
(2)Kotlin 允许对接口中的函数提供默认实现
interface Study {
fun readBooks()
fun doHomework() {
println("do homework defalut implementation")
}
}
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age), Study {
override fun readBooks() {
println(name + " is readBooks")
}
}
5.数据类与单例类
(1)data
关键字
在一个类前面声明data
关键字,就标明你希望这个类是一个数据类,Kotlin 会根据主构造函数中的参数帮我们将equals()
、hashCode()
、toString()
等固定且无实际逻辑意义的方法自动生成。
data class CellPhone(val brand: String, val price: Double) {
}
【简化】
// 当一个类没有任何代码时,可以将大括号省略
data class CellPhone(val brand: String, val price: Double)
(2)object
关键字
object Singleton {
fun singletonTest() {
println("this is a singleton.")
}
}
调用方法
fun testSingleton() {
Singleton.singletonTest()
}
网友评论