我有一个定义不可变值类型的类,我现在需要序列化。不变性来自构造函数中设置的最终字段。我已经尝试过序列化了,但它有效(令人惊讶的是?) - 但我不知道如何。
以下是类
的示例public class MyValueType implements Serializable
{
private final int value;
private transient int derivedValue;
public MyValueType(int value)
{
this.value = value;
this.derivedValue = derivedValue(value);
}
// getters etc...
}
鉴于该类没有没有arg构造函数,它如何实例化并设置最终字段?
(旁边 - 我注意到这个类特别是因为IDEA没有为这个类生成“no serialVersionUID”检查警告,但是成功地为我刚刚可序列化的其他类生成了警告。)
答案 0 :(得分:38)
反序列化由JVM在低于基本语言结构的级别上实现。具体来说,它不会调用任何构造函数。
答案 1 :(得分:18)
鉴于该类没有没有arg构造函数,它如何实例化并设置最终字段?
发生了一些令人讨厌的黑魔法。 JVM中有一个后门允许在不调用任何构造函数的情况下创建对象。首先将新对象的字段初始化为其默认值(false,0,null等),然后对象反序列化代码使用对象流中的值填充字段。
(既然Java是开源的,你可以阅读执行此操作的代码......然后哭泣!)
答案 2 :(得分:11)
迈克尔和斯蒂芬都给了你一个很好的答案,我只想提醒你transient
字段。
如果反序列化后默认值(引用null
,基元为0)不可接受,则必须提供readObject
版本并在那里初始化。
private void readObject (
final ObjectInputStream s
) throws
ClassNotFoundException,
IOException
{
s.defaultReadObject( );
// derivedValue is still 0
this.derivedValue = derivedValue( value );
}