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 的風險。