首页 > android > Kotlin引用嵌套类的外部类

Kotlin引用嵌套类的外部类 (Kotlin reference outer class from nested class)

问题

我有一个类O和一个嵌套类在O调用N

N我想通过使用参考thisO功能this@O

但它不承认O,只有当我使用时inner class

但是,如果我使用内部类,android-studio表明这可能会导致泄漏。

有没有其他方法来引用外层或避免泄漏?

解决方法

内存泄漏的可能性是由于inner类的每个实例都拥有对外部类的实例的引用这一事实引起的。程序逻辑可能不需要该外部类实例,但它仍然可见,因此不受垃圾收集的影响。

因此,如果您知道嵌套类实例可能不需要外部类实例的整个内容用于其逻辑,则可以通过不使用inner类来确保没有内存泄漏。

如果仍需要外部类实例的某些部分,则可以手动将这些值传递给嵌套类实例:

class A {
    val b: B = someB()
    val c: C = someC()

    // D uses C but does not need B, so we pass C to the constructor:
    class D(private val c: C) { /* ... */ }

    fun createD(): D = D(c)
}

如果您还需要嵌套类实例来观察外部类实例属性的更改(不仅仅是在嵌套类实例构造时使用属性的快照),您可以手动将该属性包装到引用持有者中并传递该持有者嵌套类构造函数:

class A {
    val b: B = someB()

    private val cHolder = CHolder(someC())

    class CHolder(var c: C)

    var c: C
        get() = cHolder.c
        set(value) { cHolder.c = value }

    // D uses C but does not need B, so we pass C to the constructor:
    class D(private val cHolder: CHolder) { /* ... */ }

    fun createD(): D = D(cHolder)
}

CHolder如果在您的代码中重复此模式,您可能希望使用一些通用解决方案而不是类; 这只是一个演示。

然后,如果要引用外部类的整个实例,仍然可以选择将其传递给嵌套类构造函数。inner class与之相比,这允许您手动控制外部实例的生命周期,并在不需要时删除对它的引用:

class A {
    class D(private var outer: A?) {
        fun forgetOuterInstance() {
            outer = null
        }
    }

    fun createD(): D = D(this)
}

最后,如果您的嵌套类在其所有生命周期中都需要外部类实例,或者如果外部类不包含任何昂贵的资源并且您可以处理其实例的可能更长的生命周期,那么可以使用inner class,只需请记住,只要内部类实例有效,外部类实例就会保持活动状态。因此,您可能希望将一些资源移出外部类以更精细地保存和释放它们。

问题

I have a class O and a nested class inside of O called N.

In a function of NI want to reference this of O by using this@O.

But it does not recognize O, only when I use inner class.

However, if I use inner classes, android-studio suggests that this might lead to leaks.

Is there another way to reference the outer class or avoid leaks?

解决方法

The memory leak possibility is caused by the fact that each instance of an inner class holds a reference to an instance of the outer class. That outer class instance may not be needed by the program logic, but it is still visible and thus is not subject to garbage collection.

So, if you are aware that the nested class instance may not need the whole content of the outer class instance for its logic, you can ensure that there's no memory leaks by not using inner classes.

If you still need some parts of the outer class instance, you can pass those values to the nested class instance manually:

class A {
    val b: B = someB()
    val c: C = someC()

    // D uses C but does not need B, so we pass C to the constructor:
    class D(private val c: C) { /* ... */ }

    fun createD(): D = D(c)
}

If you also need the nested class instance to observe the changes of the outer class instance property (not just using a snapshot of the property at the nested class instance construction time), you may manually wrap that property into a reference holder and pass that holder to the nested class constructor:

class A {
    val b: B = someB()

    private val cHolder = CHolder(someC())

    class CHolder(var c: C)

    var c: C
        get() = cHolder.c
        set(value) { cHolder.c = value }

    // D uses C but does not need B, so we pass C to the constructor:
    class D(private val cHolder: CHolder) { /* ... */ }

    fun createD(): D = D(cHolder)
}

Instead of the class CHolder, you may want to use some generic solution if this pattern repeats in your code; this is just a demo.

Then, if you want to reference the whole instance of the outer class, there's still an option to pass it to the nested class constructor. Compared to inner class, this allows you to manually control the lifetime of the outer instance and drop the reference to it once it is not needed:

class A {
    class D(private var outer: A?) {
        fun forgetOuterInstance() {
            outer = null
        }
    }

    fun createD(): D = D(this)
}

And finally, if your nested class needs the outer class instance during all of its lifetime, or if the outer class does not hold any expensive resources and you can deal with the potentially longer lifetime of its instances, then it's OK to use an inner class, just keep in mind that the outer class instance will stay alive as long is the inner class instance does. Due to this, you may want to move some resources out of the outer class to hold and release them in a more granular way.

相似信息