這篇的內容仍是和類有關,介紹 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)
}
複製代碼