天天看點

Kotlin學習筆記(六)

繼承

Kotlin的類預設都是封閉的,要讓某個類開放繼承,必須使用open關鍵字修飾它。
open class Product(val name: String) {}

class LuxuryProduct(name: String, private val price:Double):Product(name){}      

方法重寫和重載

父類的函數也要通過open關鍵字修飾才可以被子類重寫。
open class Product(val name: String) {
    fun description() = "Product:$name"

    //方法重載
    open fun load() {
        "Nothing..."
    }

    open fun load(name: String) {
        println("$name is very expensive")
    }
}

class LuxuryProduct(name: String, private val price: Double) : Product(name) {
    //方法重寫
    override fun load() {
        super.load()
        println("${super.description()},Price:$price")
    }

}

fun main() {
    val luxuryProduct: Product = LuxuryProduct("LV", 19800.00)
    println(luxuryProduct.description())
    luxuryProduct.load()
    luxuryProduct.load("LV")
}      

類型檢測

Kotlin的is運算符是一個不錯的工具,可以用來檢查某個對象的類型,其實就相當于Java中的instanceof關鍵字。
println(luxuryProduct is Product)
    println(luxuryProduct is LuxuryProduct)
    println(luxuryProduct is File)      

類型轉換

通過as操作符完成類型轉換,而且轉換一次,後面再使用時無需轉換。
open class Product0(val name: String) {
    fun special() = "Product0 special function"
}

class LuxuryProduct0 : Product0("Luxury") {}

fun main() {
    val lp = LuxuryProduct0()
    println((lp as Product0).special())
    //隻需要轉換一次,後面無需轉換,也不需要用臨時變量去存
    println(lp.special())
    println(lp.special())
}      
Kotlin編譯器很聰明,隻要能确定any is父類條件檢查屬實,就會将any當做子類類型對待,是以編譯器允許我們不經類型轉換直接使用。
open class Product2(val name: String) {
    fun load() {
        println(name)
    }
}

fun sale(p: Product2) {
    p.load()
}

class LuxuryProduct2(name: String, private val price: Double) : Product2(name) {}

fun main() {
    val lp2 = LuxuryProduct2("LV", 19800.00)
    //傳入的參數是Product2的子類對象lp2
    //sale(lp2 as Product2)
    sale(lp2)
}      

Any

無須在代碼裡顯示指定,每一個類都會繼承一個共同的叫做Any的超類。
Kotlin學習筆記(六)

Object

使用Object關鍵字,我們可以定義一個隻能産生一個執行個體的類 ———— 單例。

使用Object有三種方式:對象聲明、對象表達式、伴生對象。

對象聲明

object ApplicationConfig{
    init {
        println("ApplicationConfig loading...")
    }

    fun doSomething(){
        println("doSomething")
    }
}

fun main() {
    //ApplicationConfig既是類名,也是執行個體名
    ApplicationConfig.doSomething()
    println(ApplicationConfig)
    println(ApplicationConfig)
}      
Kotlin學習筆記(六)

對象表達式

有時候我們不一定非要定義一個新的命名類不可,也許需要某個現有類的一種變體執行個體,但隻需用一次就行了,事實上,對于這種用完就丢的類執行個體,連命名都可以省了。這個對象表達式是某個類的子類,這個匿名類依然遵循object關鍵字的一個原則,即一旦執行個體化,該匿名類隻能有唯一一個執行個體存在。
open class Player {
    open fun load() = "loading nothing.."
}

fun main() {
    val p = object : Player() {
        override fun load() = "anonymous nothing.."
    }

    println(p.load())
}      
Kotlin學習筆記(六)

伴生對象

如果你想将某個對象的初始化和一個類執行個體捆綁在一起,可以考慮使用伴生對象,使用companion修飾符,可以在一個類定義裡聲明一個伴生對象,一個類隻能有一個伴生對象。跟Java中的static有一些類似。
open class ConfigMap{

    companion object{
        private const val PATH= "d://honey.txt"

        fun load() = File(PATH).readBytes()
    }

}

fun main() {
    //static
    ConfigMap.load()
}      

通過反編譯,我們發現這基本就是Java中的static在Kotlin中的實作:

Kotlin學習筆記(六)

嵌套類

如果一個類隻對另一個類有用,那麼将其嵌入到該類中并使用這兩個類保持在一起是合乎邏輯的 ,可以使用嵌套類。
class Player2 {
    class Equipment(var name: String) {
        fun show() = println("equipment:$name")
    }
}

fun main() {
    Player2.Equipment("98k").show()
}      

資料類

顧名思義,資料類是專門設計用來存儲資料的類。
  • 資料類提供了toString的個性化實作
  • ==符号預設情況下,比較對象就是比較它們的引用值,資料類提供了equals和hashCode的個性化實作
data class Coordinate(var x: Int, var y: Int) {
    val isInBounds = x > 0 && y > 0
}

fun main() {
    println(Coordinate(10, 20))
    // == 比較的是内容,equals,Any 預設實作===,比較引用
    // === 比較的是引用
    println(Coordinate(10, 20) == Coordinate(10, 20))

    val (x, y) = Coordinate(10, 20)
    println("$x, $y")
}