Kotlin | Inner内部类 vs 嵌套类(静态内部类)

448 阅读3分钟

写在前面

  • 在 Kotlin 中,inner 关键字用于声明一个内部类(Inner Class)。内部类是一个嵌套在另一个类中的类,它能够访问其外部类的成员(包括属性和方法)。与普通的嵌套类(nested class)不同,inner 类会持有一个对其外部类对象的引用(跟Java中的内部类一样,非静态内部类默认会持有外部类的引用),因此它可以访问和修改外部类的属性和方法。
  • Kotlin 中嵌套类是默认静态的,不持有对外部类的引用,无法访问外部类的成员。

两者的选择取决于是否需要访问外部类的成员。如果需要访问外部类成员,选择 inner;否则使用嵌套类(静态内部类)。

Inner类(内部类)

inner 类会持有对外部类的引用,因此可以访问外部类的属性和方法。它比较适用于需要频繁访问外部类成员的场景。

示例

class OuterClass {
    private var outerProperty: String = "I am from OuterClass"

    // 使用 inner 声明内部类
    inner class InnerClass {
        fun accessOuter() {
            // 通过 this@OuterClass 引用外部类
            println("Accessing from InnerClass: $outerProperty")
        }
    }
}

fun main() {
    val outer = OuterClass()
    val inner = outer.InnerClass() // 创建内部类实例
    inner.accessOuter() // 调用内部类方法访问外部类成员
}

输出如下:

Accessing from InnerClass: I am from OuterClass

使用场景

  • 事件监听:需要在一个内部类中访问和修改外部类的 UI 或数据。
  • 双向交互:当外部类和内部类需要频繁交互,访问彼此的数据时使用 inner 类。

嵌套类(静态内部类)

Kotlin 中默认的嵌套类是静态的,也就是说它不持有对外部类的引用,因此不能访问外部类的成员。

示例

class OuterClass {
    private var outerProperty: String = "I am from OuterClass"

    // 嵌套类(默认静态)
    class NestedClass {
        fun showMessage() {
            // 无法访问 outerProperty,因为嵌套类不持有对外部类的引用
            println("This is a nested class")
        }
    }
}

fun main() {
    val nested = OuterClass.NestedClass() // 创建嵌套类实例
    nested.showMessage() // 调用嵌套类方法
}

输出如下:

This is a nested class

使用场景

  • 不需要外部类的引用:嵌套类只处理自己的逻辑,不需要访问外部类的成员。例如,工具类、数据处理类等。
  • 避免内存泄漏:嵌套类不会持有对外部类(通常是 Activity)的隐式引用,减少内存泄漏的风险。使用示例参见:Kotlin中正确的使用Handler

总结

  • Inner 类:适合需要访问外部类成员的场景,但要小心内存泄漏。
  • 嵌套类(静态内部类):默认不持有外部类引用,适合不需要外部类成员的场景,静态内部类有助于防止内存泄漏。例如在使用 Handler 时,利用静态嵌套类和 WeakReference 可以有效避免内存泄漏。
特点Inner 类嵌套类(静态内部类)
是否持有外部类引用持有外部类引用,可以访问外部类成员不持有外部类引用,不能访问外部类成员
用途需要访问外部类的成员不需要访问外部类成员
使用场景事件监听、UI交互等复杂交互场景工具类、辅助类,避免内存泄漏的场景