- 接口聲明和實(shí)現(xiàn)
- 接口與多繼承
- 接口繼承
- 接口中的具體函數(shù)和屬性
- ??同一函數(shù)繼承多個(gè)實(shí)現(xiàn)的問題
- 比抽象類更加抽象的是接口赋焕,接口包括 抽象函數(shù)和抽象屬性 渠缕,也可以根據(jù)需要有 具體的函數(shù) 和 具體屬性(沒有‘field’)。
注意:接口和抽象類都可以有抽象函數(shù)和抽象屬性抗蠢,也可以有具體函數(shù)和具體屬性举哟。那么接口和抽象類有什么區(qū)別?接口不能維護(hù)一個(gè)對(duì)象狀態(tài)迅矛,而抽象類可以妨猩,因?yàn)榫S護(hù)一個(gè)對(duì)象狀態(tài)需要支持字段,而接口中無論是具體屬性還是抽象屬性,后面都 沒有支持字段约谈。
// 抽象類
abstract class Figure {
abstract fun onDraw() // 抽象函數(shù)担败,無函數(shù)體
abstract val name: String // 抽象屬性狈网,無初始值拓哺,無getter和setter訪問器
var cname: String = "幾何圖形" // 具體屬性 1??
get() = field
set(value) {
field = "Figure -> $value"
}
fun display() = println(name) // 具體函數(shù)
}
// 接口
interface Figure {
fun onDraw() // 抽象函數(shù),無函數(shù)體
val name: String // 抽象屬性谆级,無初始值,無getter和setter訪問器
var cname: String // 3??具體屬性
get() = "幾何圖形"
set(value) {
// 邏輯體
}
//var cname: String = "幾何圖形" // 2??編譯錯(cuò)誤边锁,接口不具有支持字段 field
// get() = field
// set(value) {
// field = "Figure -> $value"
// }
fun display() = println(name) // 具體函數(shù)
}
代碼第1??行是在抽象類中聲明了一個(gè)具體屬性 cname,且可以正常編譯通過晾蜘;
代碼第2??行是在接口中聲明了一個(gè)具體屬性 cname邻眷,編譯不通過眠屎,因?yàn)闆]有 支持字段(field) 存儲(chǔ)狀態(tài)。
接口中的聲明具體屬性肆饶,不能有初始值改衩,并且 getter 和 setter 訪問器中不能使用支持字段 field。例如上面代碼第3??行驯镊。
一葫督、接口聲明和實(shí)現(xiàn)
在 kotlin 中接口聲明使用的關(guān)鍵字是 interface。接口中可以定義 0 - N 個(gè)抽象函數(shù)和屬性板惑,也可以定義 0 - N 個(gè)具體函數(shù)和屬性橄镜。
interface 接口名 {
fun 函數(shù)名(參數(shù)列表): 返回值類型 // 抽象函數(shù),可有可無
var|val 屬性名: 屬性類型 // 抽象屬性冯乘,可有可無
fun 函數(shù)名(參數(shù)列表): 返回值類型 { // 具體函數(shù)洽胶,可有可無
// 函數(shù)體
}
val 屬性名: 屬性類型 // 具體屬性,可有可無
get() {
// 不能訪問 feild
return 具體類型實(shí)例
}
set(value) {
// 邏輯體
// 不能訪問 feild
}
}
例如聲明一個(gè) Figure
接口的示例:
interface Figure { // 4??
fun onDraw() // 5??抽象函數(shù)往湿,無函數(shù)體
val name: String // 6??抽象屬性妖异,無初始值惋戏,無getter和setter訪問器
val cname: String // 7??具體屬性
get() = "幾何圖形"
fun display() = println(name) // 8??具體函數(shù)
}
代碼第4??行是聲明
Figure
接口领追,聲明接口使用 interface 關(guān)鍵字。代碼第5??行是聲明抽象函數(shù)响逢,抽象函數(shù)沒有函數(shù)體绒窑。
代碼第6??行是聲明抽象屬性,抽象屬性沒有初始值舔亭,沒有 getter 和 setter 訪問器些膨。
代碼第7??行的屬性,是具體屬性钦铺,具體屬性不能有初始值订雾,并且 getter 和 setter 訪問器中不能使用支持字段 field。
代碼第8??行的函數(shù)矛洞,是具體函數(shù)洼哎,它有函數(shù)體。
提示:具體函數(shù)和屬性沼本,可以理解為抽象函數(shù)和屬性的默認(rèn)實(shí)現(xiàn)噩峦。
class Ellipse : Figure {
override val name: String
get() = "橢圓形"
override fun onDraw() {
println("繪制橢圓形...")
}
override fun display() {
println("Ellipse -> $name")
}
}
class Triangle(override val name: String) : Figure {
override var cname: String
get() = "Triangle -> $name"
set(value) { }
override fun onDraw() {
println("繪制三角形...")
}
}
class Rectangle : Figure {
override val name: String = "矩形"
override fun onDraw() {
println("繪制矩形...")
}
}
fun main(args: Array<String>) {
val f1 = Ellipse()
f1.onDraw()
f1.display()
println(f1.cname)
val f2 = Triangle("三角形")
f2.onDraw()
f2.display()
println(f2.cname)
}
2019-06-03 17:03:49.315 15906-15906/cn.ak.kot I/System.out: 繪制橢圓形...
2019-06-03 17:03:49.315 15906-15906/cn.ak.kot I/System.out: Ellipse -> 橢圓形
2019-06-03 17:03:49.316 15906-15906/cn.ak.kot I/System.out: 幾何圖形
2019-06-03 17:03:49.318 15906-15906/cn.ak.kot I/System.out: 繪制三角形...
2019-06-03 17:03:49.318 15906-15906/cn.ak.kot I/System.out: 三角形
2019-06-03 17:03:49.318 15906-15906/cn.ak.kot I/System.out: Triangle -> 三角形
注意:接口和抽象類一樣,都不能被實(shí)例化抽兆。
二识补、接口與多繼承
在 kotlin 中只允許繼承一個(gè)類,但可以實(shí)現(xiàn)多個(gè)接口辫红。通過實(shí)現(xiàn)多個(gè)接口的方法滿足多繼承的設(shè)計(jì)需求凭涂。
interface InterfaceA {
fun methodA()
fun methodB()
}
interface InterfaceB {
fun methodB()
fun methodC()
}
class AB: Any(), InterfaceA, InterfaceB {
override fun methodA() {
println("methodA()")
}
override fun methodB() { // 9??
println("methodB()")
}
override fun methodC() {
println("methodC()")
}
}
- 代碼第9??行是即實(shí)現(xiàn)了接口 InterfaceA 的抽象方法祝辣,也實(shí)現(xiàn)了接口 InterfaceB 的抽象方法。
三导盅、接口繼承
- kotlin 中允許接口和接口之間繼承较幌。由于接口中的函數(shù)都是抽象函數(shù),沒有函數(shù)體白翻,所以繼承之后也不需要額外做什么乍炉。
- 接口繼承時(shí)使用 (:) 聲明,當(dāng)繼承多個(gè)接口時(shí)使用 (,) 分隔滤馍。
interface InterfaceA {
fun methodA()
}
interface InterfaceB {
fun methodB()
}
interface InterfaceC : InterfaceA, InterfaceB {
override fun methodB() // ??
fun methodC()
}
class ABC : InterfaceC {
override fun methodA() {
println("methodA()")
}
override fun methodB() {
println("methodB()")
}
override fun methodC() {
println("methodC()")
}
}
代碼第??行岛琼,接口 InterfaceC
中的 methodB()
重寫了接口 InterfaceB
,事實(shí)上在接口中重寫抽象函數(shù)并沒有實(shí)際意義巢株,因?yàn)樗鼈兌际浅橄蟮幕比穑家艚o子類實(shí)現(xiàn)的。
四阁苞、接口中的具體函數(shù)和屬性
在 kotlin 中接口的主要成員是抽象函數(shù)和抽象屬性困檩,但是也有具體函數(shù)和具體屬性。接口中的抽象函數(shù)和抽象屬性是必須要實(shí)現(xiàn)的那槽,而具體函數(shù)和具體屬性是可選擇實(shí)現(xiàn)的悼沿。
// 定義接口InterfaceA
interface InterfaceA {
fun methodA()
fun methodB(): Int
fun methodC(): String {
return "InterfaceA -> methodC"
}
fun methodD(): Int = 0
}
// InterfaceA實(shí)現(xiàn)類
class InterfaceAImpl : InterfaceA {
override fun methodA() { }
override fun methodB(): Int {
return 0
}
override fun methodC(): String {
return "InterfaceAImpl -> methodC"
}
}
InterfaceAImpl
必須實(shí)現(xiàn)接口 InterfaceA
中的抽象方法 methodA()
和 methodB()
,同時(shí)選擇性的重寫了接口 InterfaceA
中的具體函數(shù) methodC()
骚灸。
五糟趾、??同一函數(shù)繼承多個(gè)實(shí)現(xiàn)的問題
實(shí)現(xiàn)多個(gè)接口時(shí),可能會(huì)遇到同一函數(shù)繼承多個(gè)實(shí)現(xiàn)的問題甚牲。例如:
interface A {
var name: String
var age: Int
fun foo() {
println("A")
}
fun bar()
}
interface B {
val age: Int
get() = 15
// val age: String // 這種情況义郑,實(shí)現(xiàn)類C,是無法同時(shí)繼承接口A和B
// get() = "15"
fun foo() {
println("B")
}
fun bar() {
println("bar")
}
}
class C : A, B {
override var age: Int = 0
override var name: String = "C"
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super.bar()
}
}
fun main(args: Array<String>) {
val c = C()
println("name = ${c.name}")
println("age = ${c.age}")
c.foo();
c.bar();
}
2019-06-03 18:32:34.377 24711-24711/cn.ak.kot I/System.out: name = C
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: age = 0
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: A
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: B
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: bar
當(dāng)遇到同一函數(shù)繼承多個(gè)實(shí)現(xiàn)時(shí)丈钙,子類必須重寫該函數(shù)非驮,指定具體調(diào)用哪方實(shí)現(xiàn),調(diào)用方式super<類名>.函數(shù)名()
雏赦,或都不調(diào)用實(shí)現(xiàn)子類自己的函數(shù)體劫笙。屬性也是如此,但如果遇到屬性名一致但類型不一致時(shí)喉誊,實(shí)現(xiàn)類是無法同時(shí)繼承雙方接口的邀摆,如上面被注釋代碼val age: String
。
interface A {
fun foo()
}
interface B {
fun foo(): String
}
class C : A, B { // 編譯錯(cuò)誤伍茄,無法同時(shí)繼承接口A和B
override fun foo(): String {
return ""
}
override fun foo() {}
}
class D : A, B { // 編譯錯(cuò)誤栋盹,無法同時(shí)繼承接口A和B
override fun foo(): String {
return ""
}
}
這種情況,接口中抽象函數(shù)名一致敷矫,返回類型不同例获,也會(huì)導(dǎo)致無法同時(shí)繼承不同接口汉额。