【Kotlin從入門到深坑】之類的覆蓋屬性和方法以及抽象類
簡介
本篇部落格主要是介紹Kotlin語法中的【類的覆蓋屬性和方法以及抽象類】相關的知識,幫助各位更快的掌握Kotlin,如果有疏漏或者錯誤,請在留言中指正,謝謝。 系列彙總地址
上一篇部落格中我們詳細介紹了類的繼承和構造,下面我們來講一下,在繼承時如何覆蓋方法。
覆蓋方法
我們先看一下如何去寫,例子如下:
// 父類,使用open關鍵詞
open class TestB {
open fun test() { //需要被重寫的方法需要使用open修飾
}
}
//子類
class TestA() : TestB() {
override fun test() {//重寫的方法需要使用override
super.test()
}
}
方法和類一樣,預設是final的禁止重寫的,所以必須加上open
修飾,而重寫的方法也必須加上override
,否則子類不允許相同簽名的函式。
還有一點是需要注意的,預設override
的函式是open
的,如果你想再次限制它被覆蓋,可以使用final
修飾,程式碼如下:
//子類
class TestA() : TestB() {
final override fun test() {//重寫的方法需要使用override,使用了final,後續無法覆蓋
super.test()
}
}
覆蓋屬性
我們先看一下如何去寫,例子如下:
//父類
open class TestB {
open var x: Int? = null //屬性x
get() {//重寫了get方法,此處後面詳解
field = 34
return field
}
}
class TestA() : TestB() {
override var x: Int?=null //它覆蓋對應屬性後,對應的方法也被覆蓋
}
對於Kotlin中的屬性都有預設的get、set方法,當然也可以重寫,比如上面的TestB
的x的屬性的get
TestA
覆蓋屬性後,TestB
中定義的get
方法對其無效,舉例如下,便於理解其含義:
var a = TestA()
println(a.x)
var b=TestB()
println(b.x)
輸出結果:
null //說明TestB的get方法對TestA類無效
34 //說明TestB的get方法對TestB類有效
注意:如果原型別為var
,則覆蓋型別可以為var
,且不可以是val
,如果原型別是val
,覆蓋型別可以是val
,也可以是var
多實現
在Kotlin中,對於繼承來說,如果一個類從它的直接超類繼承相同成員的多個實現,它必須覆蓋這個成員並提供自己的實現。為了表達採用從哪個超型別繼承實現,我們使用super<父類名>
,下面舉例說明:
//首先宣告一個類
open class TestB {
open var x: Int? = null
get() {
field = 34
return field
}
open fun test() { //此處有一個可以覆蓋的方法test()
}
}
//宣告一個介面
interface TestC { //這個是介面的宣告方式
var x: Int? //聲明瞭一個抽象欄位,實現類必須覆蓋此屬性
fun test() { //聲明瞭一個方法,這個是特殊的,可以有實現方法
print("d")
}
fun test2() //這個是和java一致的抽象方法
}
此處需要注意此處的介面是可以實現具體的方法的
//實現類TestA
class TestA() : TestC, TestB() {
override fun test2() {//對於一般的抽象方法等同於java中,必須實現,否則宣告成抽象類
}
override fun test() {//此處必須寫,因為test有兩種不同實現
super<TestC>.test()
super<TestB>.test()
//上面兩個都可不寫,也可以都寫,類似於super.method
}
override var x: Int? = null //對於欄位沒影響,因為介面的屬性不允許賦值,
}
我們總結一波:
- 首先繼承
TestB
、TestC
是正常的 - 由於
TestB
、TestC
內都有test
方法,所以TestC
必須實現test
方法 - 在子類
TestC
中使用super<TestB>.test()
或者super<TestC>.test()
來呼叫父類的實現
上面我們說的是方法,仔細的話,我們還能看到介面還有屬性的定義,對於TestB
和TestC
都有x
欄位,TestA
中進行重寫的話,get/set都會被覆蓋,所以不會出現上面方法的問題
還需要注意,看一下程式碼
open class TestB {//類的一個成員變數
open var x: Int? = null
}
interface TestC { //這個是介面的宣告方式
var x: Int? //聲明瞭一個抽象欄位,實現類必須覆蓋此屬性
}
//實現類
class TestA() : TestC, TestB() {
}
我們總結一波:
- 對於介面來說,他的方法預設是抽象的,除非自己實現了
- 對於介面的成員變數也是一樣的,也是預設抽象的,子類必須覆蓋
- 但凡事都有例外,對於上面的實現中,我們並沒覆蓋
x
,但仍然正確是,因為,介面只是約束作用,因為TestA
繼承了TestB
,也就有了X
,欄位,而介面也就是約束必須有該欄位即可,所以,上面的實現也是允許的
抽象類
類和類中的某些成員可以宣告成abstract
,抽象成員在本類中可以不去實現,需要注意的是我們不需要用open標註抽象類或者函式,更有趣的是看如下實現:
//開放的類和方法
open class A{
open fun test(){
}
}
//抽象類
abstract class B : A() {
abstract override fun test() //抽象方法覆蓋開放方法
}
我們可以用一個抽象成員去覆蓋一個非抽象的開放成員
伴生物件
與java不同,Kotlin沒有靜態方法,官方建議使用包級函式,可以使用如下兩種方式來實現類似靜態類、靜態方法的方式
第一種:
object StaticDemo{
fun test(){
print("")
}
}
使用方法如下:
StaticDemo.test()
第二種:
class Demo {
companion object {//宣告在內部的,類似靜態方法,可以使用 類名.方法名
fun test() {
print("")
}
}
fun test2() { //test2在外部,必須例項化後才可呼叫
}
}
使用方法:
Demo.test()
下面我們總結一波:
無論方法還是類除了抽象類、抽象方法、介面、介面方法外,其他的繼承都需要寫
open
,重寫的成員變數和方法需要override
與java不同,Kotlin中的介面可以自己實現方法,從而導致了出現多實現的問題,出現多實現的,繼承的子類需要重寫對應的方法,然後決定是否或者呼叫哪個父類的方法。
總結
至此已經學完了Kotlin的【類的覆蓋屬性和方法以及抽象類】相關的知識,多回顧多思考,繼續後續內容。