公共最终字段的序列化

时间:2011-10-30 11:53:26

标签: java serialization final

我正在使用一个简单的结构来存储只读值(比如C#中没有setter的属性)。要实现这一点,我使用的是public final int test=42;

由于某些原因,我想允许序列化这个类。我正在使用此代码:

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.writeInt(test);
}
private void readObject(ObjectInputStream ois) throws IOException {
    test=ois.readInt();
}

最后一个不起作用,因为现场测试是最终的,我该如何解决这个问题?

4 个答案:

答案 0 :(得分:2)

readObject应始终以defaultReadObjectreadFields开头; writeObject defaultWriteObjectputFields defaultReadObjectfinal会为您设置readFields字段。

如果您想使用final,请移除readResolve,或隐藏临时字段并实施sun.misc.Unsafe(请注意原始对象仍可供相关方使用) 。一般来说,你真的不想求助于{{1}}。

(新的Java内存模型(JMM)在J2SE 5.0中引入(并在JDK 1.4中实现)为最终字段的优化提供了更多的自由。在问题的示例代码中,字段初始化为< em>编译时常量表达式。因此我希望它是内联的(未经过测试)。)

答案 1 :(得分:0)

首先,public final原始常量可以public static final,并且不需要序列化,因为它始终是相同的值。

但是,假设你有一个由构造函数设置的字段可以是不同的。

int test=ois.readInt();
Field testField = getClass().getDeclaredField("test");
testField.setAccessible(true);
testField.set(this, test);

注意:如果您有安全管理员,安全管理人员通常不允许这样做。

答案 2 :(得分:0)

您可以使用反射来修改test

的值
// Get the Class object for the class of which test is a field
Class<?> myClass = MyClass.class;

// We will need to set test as accessible so as to change it's value
// Get the Field object for test
Field testField = myClass.getDeclaredField("test");
// Save the current accessibility of test
boolean wasAccessible = testField.isAccessible();
// Mark test as accessible
testField.setAccessible(true);
// Set the value of test for this instance of MyClass
int newTestValue = 42;
testField.setInt(this, newTestValue);
// Restore the accesibility of test to it's original
testField.setAccessible(wasAccessible);

以上假设您的应用程序具有SecurityManager给出的使用反射的权限。如果没有,SecurityManager将抛出异常。

答案 3 :(得分:0)

final字段的值是为每个对象更改还是对所有对象都相同?即它是在构造函数或字段声明级别设置的?如果它保持不变,那么这里最简单的解决方案是使它static并消除读取和写入“只读”值的额外开销。此外,您是否必须提供readObjectwriteObject实施,而不是依赖于默认机制?