这篇的内容仍是和类有关,介绍 Kotlin 中继承和接口。html
Kotlin 中全部类都继承自 Any
类,是全部类的超类,相似于 Java 中的 Object
。bash
Any 默认提供三个函数:ide
equals()
hashCode()
toString()
复制代码
默认的类都是不可被继承的,相似于 Java 中的 final
类。函数
要让类能够被继承,须要加 open
关键字修饰。post
open class Base{}
复制代码
若是子类有主构造函数,则基类必须在主构造函数中当即初始化。ui
open class Person(var name: String, var age: Int) {
var mName = name
var mAge = age
}
class Student(name: String, age: Int, var no: String, var score: Int) : Person(name, age) {
var mNo = no
var mScore = score
}
fun main(args: Array<String>) {
val s = Student("Owen",23, "12138",100)
println("学生名字:${s.mName}")
println("学生年龄:${s.mAge}")
println("学生学号:${s.mNo}")
println("学生成绩:${s.mScore}")
}
// 运行结果
学生名字:Owen
学生年龄:23
学生学号:12138
学生成绩:100
复制代码
若是子类没有主构造函数,则必须在每个次级构造函数中须要使用 super
关键字调用基类的构造函数,或者使用 this
关键字调用子类另外一个构造函数,初始化基类时,能够调用基类不一样的构造函数。this
open class Person(name: String) {
var mName = name
var mAge: Int = 0
init {
println("-----这是基类的主构造函数----")
}
constructor(name: String, age: Int) : this(name) {
mAge = age
println("-----这是基类的次级构造函数----")
}
}
class Student : Person {
var mNo: String = ""
var mScore: Int = 0
constructor(name: String, age: Int, no: String) : super(name, age) {
mNo = no
println("-----这是子类的三个参数的次级构造函数----")
}
constructor(name: String, age: Int, no: String, score: Int) : this(name, age, no) {
mScore = score
println("-----这是子类的四个参数的次级构造函数----")
}
}
fun main(args: Array<String>) {
val s = Student("Owen", 23, "70", 100)
println("学生名字:${s.mName}")
println("学生年龄:${s.mAge}")
println("学生学号:${s.mNo}")
println("学生成绩:${s.mScore}")
}
//运行结果
-----这是基类的主构造函数----
-----这是基类的次级构造函数----
-----这是子类的三个参数的次级构造函数----
-----这是子类的四个参数的次级构造函数----
学生名字:Owen
学生年龄:23
学生学号:70
学生成绩:100
复制代码
在基类中,函数默认为 final
修饰,不可被重写。若是容许子类重写,须要手动添加 open
关键字进行修饰,子类重写函数使用 override
关键字。spa
open class Person {
open fun study() {
println("我毕业了")
}
}
class StudentA : Person() {
override fun study() {
println("我在读大学")
}
}
fun main() {
val s = Student()
s.study()
}
//输出结果
我在读大学
复制代码
子类能够用一个函数重写父类和接口中的多个同名函数。若是要调用父类或接口的函数实现,须要用 super
关键字来显式调用。code
open class A {
open fun f() {
println("A:f")
}
}
interface B {
fun f() {
println("B:f")
}
}
class C : A(), B {
override fun f() {
super<A>.f() //调用父类A中f()的实现,也能够选择不调用
super<B>.f() //调用接口B中f()的实现,也能够选择不调用
println("C:f")
}
}
fun main() {
val c = C()
c.f()
}
//运行结果
A:f
B:f
C:f
复制代码
Kotlin 中支持对属性进行重写,属性重写用 override
关键字。基类中被重写的属性须要用 open
关键字修饰,不能为 private。htm
open class A {
open var property: String = "a"
}
class B : A() {
override var property: String = "b"
}
fun main() {
val b = B()
println(b.property)
}
//运行结果
b
复制代码
能够使用一个 var 属性重写一个 val,可是反过来不行(可变比不可变的范围更大)。val 属性自己定义了 getter 方法,重写为 var 属性会在子类中额外声明一个 setter 方法。(机制相似于子类不能将 public 的方法重写为 private 的,范围不能缩小,只能变大)
能够在子类的主构造函数中使用 override 关键字做为属性声明的一部分。
interface Foo{
val count :Int
}
class Bar1(override val count: Int):Foo{
}
class Bar2:Foo{
override val count: Int = 0
get() = field
}
fun main(){
val bar1 = Bar1(4)
println(bar1.count)
val bar2 = Bar2()
println(bar2.count)
}
复制代码
子类继承父类时,不能有跟父类同名的变量,除非父类中该变量为 private,或者父类中该变量为 open 而且子类用 override 关键字重写。
Kotlin 接口与 Java8 相似,使用 interface 关键字,容许方法有默认实现。
interface MyInterface {
fun b() //未实现
fun f() { //已实现
println("MyInterface:f")
}
}
复制代码
一个类能够实现一个或多个接口。多个接口中有同名方法时,和前面提到的类和接口中又同名方法的处理是同样的。
接口中的属性只能是抽象的,不容许
初始化值,接口不会保存属性值,实现接口时,必须
重写属性。
interface MyInterface {
var name :String // 属性,抽象的
fun b()
fun f() {
println("MyInterface:f")
}
}
class Child : MyInterface {
override var name: String = "owen"
override fun b() {
println("Child:b")
}
}
fun main() {
val c = Child()
c.b()
c.f()
println(c.name)
}
复制代码