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
}
似乎像下面这样的简单扩展 属性 不起作用。
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
}