Kotlin 巢狀類別 (Nested & Inner Classes)

在類別裡面定義另一個類別,這在 Java 和 Kotlin 都很常見。 但要注意!Kotlin 的預設行為跟 Java 完全相反

巢狀類別 (Nested Class)

在 Kotlin 中,如果你直接在類別裡面定義一個類別,它預設是 靜態的 (Static)。 這意味著它 不持有 外部類別 (Outer Class) 的參考,因此 無法存取外部類別的成員

class Outer {
    val bar: Int = 1
    
    class Nested {
        fun foo() = 2
        // fun accessOuter() = bar // 錯誤!無法存取 Outer 的 bar
    }
}

val demo = Outer.Nested().foo() // 不需要 Outer 的實例就能建立

這等同於 Java 的 static class Nested { ... }

什麼是「靜態 (Static)」? 在這裡的意思是,Nested Class 雖然寫在 Outer Class 裡面,但它 獨立於 Outer Class 的實例。 你可以把它想像成一個完全獨立的類別,只是剛好寄生在別人的名下而已。因此它無法存取「宿主」的任何屬性。

內部類別 (Inner Class)

如果你希望內部的類別可以存取外部類別的成員,你必須加上 inner 關鍵字。 這樣它就會變成一個真正的「內部類別」,會持有外部類別的參考 (Reference)。

class Outer {
    val bar: Int = 1
    
    inner class Inner {
        fun foo() = bar // 可以存取!
    }
}

val demo = Outer().Inner().foo() // 必須先有 Outer 的實例才能建立 Inner

這等同於 Java 的 class Inner { ... } (非 static)。

存取外部類別實例 (this@Outer)

在內部類別中,如果你需要取得外部類別的 this,要使用 Qualified this 語法:this@OuterName

class Outer {
    val name = "Outer"
    
    inner class Inner {
        val name = "Inner"
        
        fun printName() {
            println(this.name)       // 印出 "Inner"
            println(this@Outer.name) // 印出 "Outer"
        }
    }
}

總結比較

特性Kotlin (預設 class)Kotlin (inner class)Java (預設 class)Java (static class)
持有外部參考❌ (無)✅ (有)✅ (有)❌ (無)
存取外部成員
記憶體洩漏風險高 (若生命週期處理不當)
在 Android 開發 (例如 RecyclerView Adapter 的 ViewHolder) 中,通常建議使用預設的 Nested Class (不加 inner),以避免不必要的記憶體持有,減少 Memory Leak 的風險。