类与对象
定义一个类
class Person {
var name = ""
var age = 0
fun eat() {
println("$name is eating. He is $age years old.")
}
}
使用示例:
val person = Person()
person.name = "Jom"
person.age = 23
person.eat()
继承
class Student : Person(){
var sno = ""
var grade = 0
override fun eat() {
super.eat()
println("$name at grade $grade and sno is $sno")
}
}
- 使Person类可以被继承
- 在Kotlin中任何—个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final关键字
- Effective Java这本书中明确提到,如果—个类不是专门为继承而设计的,那么就应该主动将它加上final声明,禁止它可以被继承。
- 让它可以被继承才行,需要在Person类的前面加上open关键字,主动告诉Kotlin编译器,Person这个类是专门为继承而设计的,这样Person类就允许被继承了。
- 函数默认也是不能重写的,若要重写也要加上 open 关键字
open class Person {
var name = ""
var age = 0
open fun eat() {
println("$name is eating. He is $age years old.")
}
}
使用示例:
val stu = Student()
stu.name = "Lily"
stu.age = 14
stu.grade = 8
stu.sno = "2012211598"
stu.eat()
构造函数
- Kotlin将构造函数分成了两种:主构造函数和次构造函数
- 写在class后面的是主构造函数
- 一个类只能有一个主构造函数
- 一个类可以有多个次构造函数
- 当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
每个类默认都会有—个不带参数的主构造函数
class Student : Person(){}
val stu = Student()
当然你也可以显式地给它指明参数, 主构造函数的特点是没有函数体,直接定义在类名的后面即可
class Student(val sno: String, val grade: Int) : Person() {}
val student = Student("a123", 5)
主构造函数没有函数体,如果我想在主构造函数中编写—些逻辑,Kotlin给我们提供了—个init结构体,所有主构造函数中的逻辑都可以写在里面
class Student(val sno: String, val grade: Int) : Person() {
init {
println("sno is $sno")
println("grade is $grade")
}
}
子类中的构造函数必须调用父类中的构造函数
Person类后面的—对空括号表示Student类的主构造函数在初始化的时候会调用Person类的无参数构造函数
如果我们将Person改造—下,将姓名和年龄都放到主构造函数当中, Student 类中继承 Person 中就不能只写空括号了
open class Person(val name: String, val age: Int) {
}
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
}
val student = Student("20122025002", 1, "Jack", 18)
注意:
我们在Student类的主构造函数中增加name和age这两个字段时,不能再将它们声明成val,
因为在主构造函数中声明成val或者var的参数将自动成为该类的字段,
这就会导致和父类中同名的name和age字段造成冲突。
当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数
class Person(val name: String, val age: Int) {
constructor(name: String) : this(name, 18) {} // 空的{}也可省略
constructor(age: Int) : this("Tony", age) {}
constructor() : this("Tony", 18) {}
}
次构造函数使用示例:
val person1 = Person2("Lily", 19)
val person2 = Person2("Lily")
val person3 = Person2(19)
val person4 = Person2()
一种非常特殊的情况:类中只有次构造函数,没有主构造函数
当一个类没有显式地定义主构造函数且定义了次构造函数时,它就是没有主构造函数的
既然没有主构造函数,继承Person类的时候也就不需要再加上括号了
open class Person(val name: String, val age: Int) {}
class Student : Person {
constructor(name: String, age: Int) : super(name, age) {}
}
接口
- 定义一个接口,接口函数默认不需要函数体,此类型函数实现类必须实现
- 接口中也可以有已经实现了的函数,此类函数实现类可以不实现,也可以进行重写
- 实现接口同样写在冒号 : 后面,同继承一样
interface Study {
fun readBooks()
fun doHomework()
fun play() {
println("play default impl")
}
}
class Student : Person(), Study {
var sno = ""
var grade = 0
override fun readBooks() {
println("$name readBooks")
}
override fun doHomework() {
println("$name doHomework")
}
override fun play() {
println("$name not play")
}
}
函数的可见性修饰符
Java中有public、private、protected和default(什么都不写)这4种函数可见性修饰符。
Kotlin中也有4种,分别是public、private、protected和internal,
需要使用哪种修饰符时,直接定义在fun关键字的前面即可
数据类
数据类通常需要重写equals()、hashCode()、toString()这几个方法。
其中,equals()方法用于判断两个数据类是否相等。
hashCode()方法作为equals()的配套方法,也需要—起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。
使用java方式编写需要写很多无意义的代码,Kotlin中不需要了
data class Cellphone(val brand: String, val price: Double)
当在—个类前面声明了data关键字时,就表明你希望这个类是—个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量
val cellphone1 = Cellphone("Samsung", 1299.99)
val cellphone2 = Cellphone("Samsung", 1299.99)
println("cellphone1 equals cellphone2 " + (cellphone1 == cellphone2))
单例类
只需要把class关键字改成object关键字,—个单例类就创建完成了
object Singleton {
fun singletonTest() {
println("singletonTest is called.")
}
}
Singleton.singletonTest()
这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了—个Singleton类的实例,并且保证全局只会存在—个Singleton实例。
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章