gpt4 book ai didi

serialization - 无法在 Kotlin 中序列化对象单例

转载 作者:行者123 更新时间:2023-12-02 12:47:11 25 4
gpt4 key购买 nike

在 Kotlin 中,密封类的一个常见用途是组合包含一些数据(使用 data class )和其他单例(使用 object )的案例,如下所示:

sealed class Location {
object Unknown : Location()
data class Known(val lat: Float, val lon: Float) : Location()
}

我们使用的系统需要模型实现 Serializable .令我惊讶的是,这不适用于 object您可以在此演示中看到单例:

https://pl.kotl.in/vd_TgUR6a

输出以下内容:
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 使用“人工”手段对其进行反序列化。无论是反射还是其他合成方式。

我怎样才能使这项工作?

最佳答案

我找到了一个“更好”的解决方案。使用 readResolve() 的隐藏 JVM API :

sealed class Location: Serializable {
object Unknown : Location() {
private fun readResolve() : Any? = Location.Unknown
}
data class Known(val lat: Float, val lon: Float) : Location()
}

此处代码: https://pl.kotl.in/tMGf-AIfq

产生以下输出:
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

此函数在从流中加载对象后调用,并允许返回不同的对象,而不是从内存中加载的对象。

这意味着即使我们的 object 也可以安全使用。有一个状态(虽然不是应该的。并且应该更有效地使用内存。

这里有一张关于这个的票: https://youtrack.jetbrains.com/issue/KT-9499

看起来它可能会作为另一张票的一部分来添加 @JVMSerializable注释: https://youtrack.jetbrains.com/issue/KT-14528

旧答案:

我发现的最佳解决方案是让单例对象覆盖默认值 equals , hashCodetoString使其在功能上相同:
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()
}

这是演示: https://pl.kotl.in/oNd-mnWlQ

输出是:
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 中的序列化方式不同。但是,它们不能扩展类(仅限接口(interface)),因此它不适用于此实例。

所有这一切都表明甲骨文计划最终放弃它:
https://www.infoworld.com/article/3275924/oracle-plans-to-dump-risky-java-serialization.html

与此同时,我们坚持这一点。

注意:只要对象不可变,这将起作用。如果我们允许更改状态,那么当我们开始在每个反序列化对象上具有不同的状态时,所有 hell 都会破裂。

关于serialization - 无法在 Kotlin 中序列化对象单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56485742/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com