Serialization 无法序列化Kotlin中的对象单例
在Kotlin中,密封类的一个常见用途是将包含一些数据(使用Serialization 无法序列化Kotlin中的对象单例,serialization,kotlin,Serialization,Kotlin,在Kotlin中,密封类的一个常见用途是将包含一些数据(使用数据类)和其他单例(使用对象)的案例组合在一起,如下所示: sealed class Location { object Unknown : Location() data class Known(val lat: Float, val lon: Float) : Location() } 我们正在使用的系统要求模型实现可序列化。令我惊讶的是,这不适用于对象单例,正如您在本演示中看到的: 其输出如下: Success
数据类
)和其他单例(使用对象
)的案例组合在一起,如下所示:
sealed class Location {
object Unknown : Location()
data class Known(val lat: Float, val lon: Float) : Location()
}
我们正在使用的系统要求模型实现可序列化
。令我惊讶的是,这不适用于对象
单例,正如您在本演示中看到的:
其输出如下:
Success: Known(lat=37.563934, lon=-116.85123) and Known(lat=37.563934, lon=-116.85123) are equal
Failure: sample.Location$Unknown@7c3df479 and sample.Location$Unknown@452b3a41 are not equal
实例id不同。我的猜测是JVM使用“artifital”方法对其进行反序列化。无论是反射还是其他合成方式
我怎样才能做到这一点呢?我找到了一个“最好”的解决方案。使用readResolve()
的隐藏JVM API:
代码如下:
生成以下输出:
Success: Known(lat=37.563934, lon=-116.85123) and Known(lat=37.563934, lon=-116.85123) are equal
Success: sample.Location$Unknown@452b3a41 and sample.Location$Unknown@452b3a41 are equal
此函数在从流加载对象后调用,并允许返回不同的对象,而不是从内存加载的对象
这意味着,即使我们的对象
有一个状态,也可以安全地使用它(虽然它不应该这样做,而且应该更高效地使用内存)
这里有一张关于这个的票:
看起来它可能是另一张票的一部分,添加了@JVMSerializable
注释:
旧答案:
我找到的最佳解决方案是使singleton对象覆盖默认的equals
、hashCode
和toString
,使其功能完全相同:
sealed class Location: Serializable {
object Unknown : Location() {
override fun equals(other: Any?) = other is Unknown
override fun hashCode() = toString().hashCode()
override fun toString(): String = "Location.Unknown"
}
data class Known(val lat: Float, val lon: Float) : Location()
}
以下是演示:
输出为:
Success: Known(lat=37.563934, lon=-116.85123) and Known(lat=37.563934, lon=-116.85123) are equal
Success: Location.Unknown and Location.Unknown are equal
如果内存不是一个极端的问题,这是一个可能的解决方案,因为它将为每个反序列化对象创建一个对象。尽管如此,该对象的占用空间非常小,这在大多数情况下不应该是一个问题,但需要注意
如果Kotlin可以使用枚举类实现object
,因为它们在JVM中的序列化方式不同,那么这不会是一个问题。但是,它们不能扩展类(只扩展接口),因此它不适用于此实例
所有这些都表明,甲骨文计划最终放弃:
同时,我们也要面对这个问题
注意:只要对象是不可变的,这就可以工作。如果我们允许更改状态,当我们开始在每个反序列化对象上有不同的状态时,所有的地狱都会打开。对我来说,这似乎是Kotlin语言中的一个错误,因为他们应该禁止序列化对象,或者让它们实现适当的
equals/hashcode
函数你在下面的回答中显示了什么。我还建议+1这个问题,让他们知道有多少人有同样的问题:
Success: Known(lat=37.563934, lon=-116.85123) and Known(lat=37.563934, lon=-116.85123) are equal
Success: Location.Unknown and Location.Unknown are equal