Kotlin,实现扩展 var 属性

Kotlin, implement extension var property

似乎像下面这样的简单扩展 属性 不起作用。

var Dog.age = 0;

推荐的实施方式是什么?我尝试了以下方法,它起作用了,但这会阻止任何 Dog 对象被垃圾收集器清理,不是吗?

class Dog
{
}

val dogAgeMap=HashMap<Dog, Int>();
var Dog.age:Int
    get() =  dogAgeMap[this]?: 0;
    set(value){ dogAgeMap[this] = value}

class PetShop
{
    fun work()
    {
        val d1 = Dog();
        d1.age = 100;
        val d2 = Dog();
        d2.age = 200;
        println("${d1.age}, ${d2.age}");
    }
}

fun main(args:Array<String>)
{
    PetShop().work();
}

正确,这将防止在 dogAgeMap 定义的范围内调用 age setter 的 Dog 个实例进行 GC。如果您在有限(短)生命周期的有限范围内定义了 Dog.age 扩展 属性(因此 dogAgeMap),那么您没问题。

但是,如果情况并非如此,并且您需要整个应用程序中的 age 信息,那么 age 应该只是原始 class 定义的一部分,并且您永远不要 运行 解决这个问题。

本例的解决方法

class Dog(val age: Int)

如果您只在应用程序的一部分中需要 age 信息,那么更好的方法是仅为该部分创建查找(HashMap),或者简单地使用一个丰富的 class 和 age(或包装器 class 和 age)而不是你应用程序那部分的 Dog class。当您在那里完成工作后,您可以清理地图或丰富的 class 实例。这样就不会泄漏任何实例。


但是如果你真的想要在整个应用程序中使用扩展属性来做到这一点,那么你需要保留对dogAgeMap 一直,那么如果你有很多实例要经历并设置它们的年龄,那么你需要注意内存泄漏。

如果是这种情况,您可以改用 WeakHashMap<Dog, Int>WeakHashMap 只保留弱引用,它不会阻止 Dog 个实例被 GC(一旦你的强引用不再保留)。

import java.util.WeakHashMap

val dogAgeMap = WeakHashMap<Dog, Int>()
var Dog.age: Int
    get() = dogAgeMap[this] ?: 0
    set(value) {
        dogAgeMap[this] = value
    }

但是请注意,WeakHashMap 是 Java class 而不是 Kotlin 核心库的一部分,因此如果您将 Kotlin 用于多平台,这将不起作用。在那种情况下,您需要在每个平台上有一个 WeakHashMap 实现(库)。

如果您的狗数据还包含每只狗的 ID,替代方法 将使用 ID 作为查找键。这将有可能移植到所有平台。然后实施将更改为

// I am using a Long here, but it could be whatever type that
// is small enough to not cause memory concerns, since
// these keys would still exist in memory because a normal HashMap is used.
class Dog(val id: Long) {}

val dogAgeMap = HashMap<Long, Int>()
var Dog.age: Int
    get() = dogAgeMap[id] ?: 0
    set(value) {
        dogAgeMap[id] = value
    }