繼承語法
類和接口的繼承經過 : 來實現java
/**定義一個基類,必須有open關鍵字 才能被繼承*/ open class Base(val p:Int) { } /**類繼承*/ class Derived(p:Int):Base(p){ } /**接口中的方法 默認是 open的*/ interface Animal{ fun run() } //實現接口 不須要 () abstract class BaseAnimal() : Animal{ var name:String ? = null constructor(name:String):this(){ this.name = name } } class Dog(name: String) : BaseAnimal(name) { override fun run() { println("$name run ....") } } fun main() { val dog = Dog("哈士奇") dog.run() }
接口
kotlin 的接口能夠包含抽象方法,以及方法的實現,接口能夠有屬性但必須是抽象的,或者提供訪問器的實現,固然java 8 中的接口也支持這些特性了。算法
- 接口之間的繼承
interface Animal{ fun die() fun eat(){ //kotlin中的接口方法容許有函數體 println("animal eat ... ") } } interface Bird:Animal{ fun fly(){ println("自由飛翔") } //直接覆蓋Animal接口中的方法 override fun eat() { println("bird eat ... ") } } class Magpie:Bird{ override fun die() { println("鵲 死了") } override fun eat() { super.eat() println("鵲 吃穀物") } } fun main() { val magpie = Magpie() magpie.eat() magpie.fly() magpie.die() }
bird eat ... 鵲 吃穀物 自由飛翔 鵲 死了ide
- 接口中的屬性與繼承 在kotlin中,在接口中不只能夠定義和實現方法,也能夠定義屬性,在接口中所聲明的屬性,默認是abstract類型的,所以一個類型若是實現了某個接口,則必需要複寫接口中的屬性。在複寫接口屬性時,必須添加override關鍵字,而且定義在接口中的屬性不能被初始化。
interface Animal { var name: String fun run() } class Magpie(override var name: String) : Animal { //複寫接口中的屬性的兩種方式 // override var name: String = "喜鵲" override fun run() { println("喜鵲 自由飛翔") } } fun main() { val magpie = Magpie("喜鵲") magpie.run() println(magpie.name) }
虛類(抽象類)
在kotlin中定義一個虛類,語法與java類似,在虛類中,能夠聲明類屬性,構造函數,能夠只定義方法頭,也能夠定義個包含方法體的完整方法。函數
abstract class Animal(val name: String) { var age: Int = 0 abstract fun run() fun eat(){ println("animal eat ... ") } }
多重繼承
- 類與接口的繼承 kotlin中也像java同樣一個類(接口)能夠繼承多個接口,只是類繼承接口的時候必須實現接口方法。和java同樣一個類只能繼承一個類,不能繼承多個類。
interface Animal{ fun run() } interface Mammal{ fun feed() } interface Canine:Mammal,Animal{ fun bite() } open class Bird:Animal,Mammal{ override fun run() { // } override fun feed() { // } } //類繼承 必須有() class Eagle : Bird(){ }
- 構造函數繼承 若是父類中有多個構造函數,子類隨便繼承父類的一個構造函數就好
open class Animal(var name:String){ fun run(){ println("$name run ...") } } //顯示定義主構造函數類繼承包含主構造函數的父類 class Mammal(name: String):Animal(name){ fun feed(){ println("投喂 $name") } } class Canine:Animal{ //經過二級構造函數繼承父類的主構造函數 constructor(name: String):super(name){ //do something } }
- 接口方法的多重繼承 不管在java仍是kotlin中,一個類都沒法同時繼承多個父類,可是若是父類又繼承了另外一個基類,如此即可以造成一個 「繼承樹」,在一棵繼承樹中,一個類能夠有多個基類,只不過這些基類之間自己也有繼承關係。在子類中,能夠經過super關鍵字調用父類中的某個方法。當一個類的多個基類都同時定義了同一個方法時,那麼在子類中經過super關鍵字去調用父類的方法時,會調用哪個父類的同名方法呢?
- 類的多繼承:
open class Animal(var name:String){ open fun run(){ println("animal run ...") } } open class Mammal(name: String):Animal(name){ override fun run() { println("mammal run ....") } } class Panda(name: String):Mammal(name){ override fun run() { super.run() } } fun main() { val panda = Panda("盼盼") panda.run() }
mammal run ....this
- 接口的多繼承
interface Animal{ fun run(){ println("animal run ...") } } interface Mammal:Animal{ override fun run() { println("mammal run ....") } } class Panda(val name: String):Mammal,Animal{ override fun run() { //這裏必須使用泛型,標明調用哪個父類的方法 super<Mammal>.run() } }
- 繼承的初始化 當子類構造函數被執行的時候,期父類以及繼承體系中的全部父類的構造函數都會被執行,類的繼承,不單單是對接口的繼承,更重要的是對字段屬性的繼承。
open class Base{ constructor(){ println("base constructor") } init { println("base init") } } open class ExtendClass1:Base{ constructor():super(){ println("ExtendClass1 constructor") } init { println("ExtendClass1 init") } } open class ExtendClass2:ExtendClass1{ constructor():super(){ println("ExtendClass2 constructor") } init { println("ExtendClass2 init") } } fun main() { val base = ExtendClass2() }
base init base constructor ExtendClass1 init ExtendClass1 constructor ExtendClass2 init ExtendClass2 constructor設計
子類在實例化的時候,沒有實例化父類,那爲何要調用父類的構造函數呢?主要是爲了對字段屬性進行初始化。code
類型轉換
提出類的繼承機制的初衷,大致上處於如下兩個方面考慮:對象
- 爲了設計一些特殊的算法和模式
- 爲了實現一成文種通用的設計思想------面向接口設計
關於類型轉換,有兩條不成文的規則:繼承
- 能夠向上轉型,不能向下轉
- 編譯期不報錯,運行時報錯
在基於面向接口設計原則開發程序時,一定會發生如下兩種轉換:接口
- 在調用接口前,會先實例化子類,將子類實例做爲入參傳遞給接口,這裏發生了隱式轉換——有子類轉換成基類
- 在接口內部,則能夠將基類類型的入參變量強制轉換爲子類,並調用子類的方法。
在第二步中,將基類強制轉換爲子類,是正確的——由於基類變量實際上指向的是子類實例對象 在kotlin中提供的強制轉換語法是 as , 判斷一個類型是 is (代替了java 中的 instanceof)
val a:Int = 1 val b:Long = 2L //強制轉換 val c:Number = b as Number //判斷類型 println( a is Int)