Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin reference outer class from nested 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?

like image 588
Benjamin Basmaci Avatar asked Apr 26 '26 21:04

Benjamin Basmaci


1 Answers

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.

like image 105
hotkey Avatar answered Apr 29 '26 09:04

hotkey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!