Kotlin,实现扩展var属性



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

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();
}

正确,这将防止调用agesetter的Dog实例在定义dogAgeMap的范围内被GCed。如果您在有限(短(寿命的有限范围内定义了Dog.age扩展属性(从而定义了dogAgeMap(,那么您就可以了。

但是,如果不是这样,并且您需要在整个应用程序中使用age信息,那么age应该只是原始类定义的一部分,您永远不会遇到这个问题。

这种情况下的解决方案

class Dog(val age: Int)

如果您只在应用程序的一个部分中需要age信息,那么更好的方法是只为该部分创建查找(HashMap(,或者简单地使用带有age的富集类(或带有age的包装类(,而不是应用程序的该部分中的Dog类。当您在那里完成工作时,您将清理映射或丰富的类实例。这样就不会有任何实例泄漏。


但是,如果真的想在整个应用程序中使用扩展属性,因此您需要始终保留对dogAgeMap的引用,那么如果您要处理大量实例并设置它们的年龄,则需要注意内存泄漏。

如果是这种情况,您可以使用WeakHashMap<Dog, Int>WeakHashMap只保留弱引用,不会阻止Dog实例被GCed(一旦不再保留强引用(。

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

但是,请注意,WeakHashMap是一个Java类,而不是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
}

最新更新