1. 程式人生 > >- Kotlin類之資料類、密封類、內部類.md

- Kotlin類之資料類、密封類、內部類.md

資料類

1.宣告

data關鍵字

data class Leaf(val size: String,val color: String,val shape: String,val vein: Int)

2.資料類宣告條件

  1. 主建構函式最少要有一個引數
  2. 資料類的主構造器的所有引數必須標記為val或var
  3. 資料類不能是抽象類、open類、封閉類、內部類
  4. 資料類不能繼承自任何其他類(但可以實現介面)

3.訪問資料類的2種方法

  1. 和普通類一樣"物件名.資料名"
  2. 編譯器從主建構函式中宣告的屬性中匯出的成員方法componentN()函式群
data class Leaf(val size: String,
val color: String,val shape: String,val vein: Int) fun main(args: Array<String>) { val leaf = Leaf("20","green","cicle",57) val size = leaf.size val color = leaf.color val shape = leaf.shape val vein = leaf.vein println("大小:$size 顏色: $color 形狀 $shape 葉子數: $vein") }
data
class Leaf(val size: String,val color: String,val shape: String,val vein: Int) fun main(args: Array<String>) { val leaf = Leaf("20","green","cicle",57) val(size,color,shape,vein) = leaf println("大小:$size 顏色: $color 形狀 $shape 葉子數: $vein") }

4.componentN()函式群

componentN函式群會按宣告順序對應於所有屬性

上面的程式碼我們可以看到結構出來的變臉可以直接拿來用,比如資料體Leaf中的size屬性,componentN函式群會按照資料體Leaf中屬性宣告的順序,從component1到component4和size、color、shape、及vein一一對應。

5.編輯器做的事

  1. 生成equals()函式與hasCode()函式
  2. 生成toString()函式,由類名(引數1 = 值1,引數2 = 值2,…)構成
  3. 由所定義的屬性自動生成component1()、component2()、…、componentN()函式,其對應於屬性的宣告順序。
  4. copy()函式。(Koltin要修改資料類的屬性,則使用其獨有的copy()函式。其作用就是:修改部分屬性,但是保持其他不變)

密封類

1. 什麼是受限的類繼承結構

  1. 所謂受限的類繼承結構,即當類中的一個值只能是有限的幾種型別,而不能是其他的任何型別。
  2. 這種受限的類繼承結構從某種意義上講,它相當於是列舉類的擴充套件。但是,我們知道Kotlin的列舉類中的列舉常量是受限的,因為每一個列舉常量只能存在一個例項
  3. 但是其和列舉類不同的地方在於,密封類的一個子類可以有可包含狀態的多個例項。
  4. 也可以說成,密封類是包含了一組受限的類集合,因為裡面的類都是繼承自這個密封類的。但是其和其他繼承類(open)的區別在,密封類可以不被此檔案外被繼承,有效保護程式碼。但是,其密封類的子類的擴充套件是是可以在程式中任何位置的,即可以不在同一檔案下

2.宣告

sealed class SealedExpr()

內部類(巢狀類)

在實際開發中,用到內部類的地方是很多的。比如說:

  • 對於Android開發來說,列表介面卡中的ViewHolder類就是一個內部類
  • 根據後臺開發人員提供的json字串生成的物件中,也包含另外一個物件,這也是一個內部類

1.巢狀類

上面提到的兩種情況,是在開發中最常見的。當然說到內部類,就必須提到另一個概念,巢狀類,所謂巢狀類:即指一個類可以巢狀在其他類中。

例如:

class Other{           // 外部類
    val numOuther = 1

    class Nested {      // 巢狀類
        fun init(){
            println("執行了init方法")
        }
    }
}

fun main(args: Array<String>) {
    Other.Nested().init()      // 呼叫格式為:外部類.巢狀類().巢狀類方法/屬性
}

注意

  • 呼叫巢狀類的屬性或者方法格式為: 外部類.巢狀類().巢狀類方法/屬性。在呼叫的時候巢狀類是需要例項化的。
  • 巢狀類不能使用外部類的屬性和成員

2.內部類

宣告一個內部類使用inner關鍵字。 宣告格式:inner class 類名(引數){}

class Other{            // 外部類
    val numOther = 1

    inner class InnerClass{     // 巢狀內部類
        val name = "InnerClass"
        fun init(){
            println("我是內部類")
        }
    }
}

fun main(args: Array<String>) {
   Other().InnerClass().init()  // 呼叫格式為:外部類().內部類().內部類方法/屬性
}

*注意

  • 呼叫內部類的屬性或方法的格式為:外部類().內部類().內部類方法/屬性。在呼叫的時候巢狀類是需要例項化的。
  • 內部類不能使用外部類的屬性和成員

匿名內部類

作為一名Android開發者,對匿名內部類都不陌生,因為在開發中,匿名內部類隨處可見。比如說Button的OnClickListener,ListView的單擊、長按事件等都用到了匿名內部類。 一般的使用方式為定義一個介面,在介面中定義一個方法。

class Other{
    
    lateinit private var listener : OnClickListener

    fun setOnClickListener(listener: OnClickListener){
        this.listener = listener
    }
    
    fun testListener(){
        listener.onItemClick("我是匿名內部類的測試方法")
    }
}    

interface OnClickListener{
    fun onItemClick(str : String)
}

fun main(args: Array<String>){
    // 測試匿名內部類
    val other = Other()
    other.setOnClickListener(object : OnClickListener{
        override fun onItemClick(str: String) {
            // todo
            println(str)
        }
    })
    other.testListener()
}

內部類和繼承的區別

  • 從宣告類上看,繼承的兩個類單獨宣告,子類通過(子類:父類)繼承父類,而內部類必須宣告在外部類裡面,並且用關鍵字inner標記
  • 從訪問上看,繼承的父類不能直接訪問子類,外部類可以通過“外部類().內部類()”訪問內部類,繼承的子類能直接訪問父類公開的成員屬性及方法,而內部類值能通過[email protected]外部類的方式訪問外部類的屬性和方法
  • 從能否覆蓋上看,繼承的子類能覆蓋父類用open標記的屬性和方法,內部類不能覆蓋外部類的屬性和方法
  • 從定義物件的方法看,繼承的子類定義為val/var son = Son(),內部類的定義為 val/var inter = Outer().Inter()