gpt4 book ai didi

serialization - 如何防止 -Xcheckinit 干扰 Scala 对象的反序列化?

转载 作者:行者123 更新时间:2023-12-01 02:53:41 26 4
gpt4 key购买 nike

当使用 -Xcheckinit 编译器选项并在可序列化类中实现我自己的 readObject 方法时,我无法从 readObject 方法调用我的类主体中声明的字段上的任何访问器函数。声明为构造函数参数的字段是可以的。当我尝试访问类主体中声明的字段时,我收到 scala.UninitializedFieldError。

也就是说,以下代码在 println(y) 上失败在 readObject 方法中,即使在上一行中设置了 y 之后!

@serializable case class XYPointWithRWAndPrint(var x: Int) {
var y = 0
@throws(classOf[java.io.IOException])
private def writeObject(out: java.io.ObjectOutputStream) {
out.writeInt(x)
out.writeInt(y)
}
@throws(classOf[java.io.IOException])
@throws(classOf[ClassNotFoundException])
private def readObject(in: java.io.ObjectInputStream) {
x = in.readInt()
println(x)
y = in.readInt()
println(y)
}
}

为什么?

最佳答案

使用 -Xcheckinit 编译器选项时,编译器会创建一个位图字段,用于检查初始化。

public volatile int bitmap$0;

在访问器中,编译器检查位图:
public int y(){
if ((this.bitmap$0 & 0x1) != 0){ return this.y; }
throw new UninitializedFieldError("Uninitialized field: Test.scala: 2".toString());
}

在构造函数中,编译器更新位图:
public XYPointWithRW(int x) {
Product.class.$init$(this);
this.y = 0;
this.bitmap$0 |= 1;
}

请注意,它不会更新构造函数参数的位图,只会更新类主体中声明的字段。它这样做是因为它假定您将调用构造函数并且这些字段将立即初始化。

然而,在反序列化期间,调用第一个不可序列化父类(super class)的无参数构造函数(在本例中为 Object),而不是上面显示的单参数构造函数。然后调用 readObject。上面的构造函数永远不会被调用。因此,位图永远不会更新。调用访问器将在其调用的任何地方失败,而不仅仅是在 readObject 方法中。

要解决此问题,您必须手动更新位图。我选择从 readObject 方法中这样做。我将位图中的所有位设置为 1,如下所示:
getClass.getField("bitmap$0").set(this, -1)

通过将所有位设置为 1,它将适用于所有字段(无论如何最多可达 32 个字段......除此之外会发生什么是任何人的猜测)。

关于serialization - 如何防止 -Xcheckinit 干扰 Scala 对象的反序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3876163/

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