我正在使用一个简单的结构来存储只读值(比如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();
}
最后一个不起作用,因为现场测试是最终的,我该如何解决这个问题?
答案 0 :(得分:2)
readObject
应始终以defaultReadObject
或readFields
开头; writeObject
defaultWriteObject
或putFields
defaultReadObject
。 final
会为您设置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
并消除读取和写入“只读”值的额外开销。此外,您是否必须提供readObject
和writeObject
实施,而不是依赖于默认机制?