当没有指定默认构造函数时,java序列化如何反序列化最终字段?

时间:2010-05-25 12:32:19

标签: java serialization final

我有一个定义不可变值类型的类,我现在需要序列化。不变性来自构造函数中设置的最终字段。我已经尝试过序列化了,但它有效(令人惊讶的是?) - 但我不知道如何。

以下是类

的示例
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”检查警告,但是成功地为我刚刚可序列化的其他类生成了警告。)

3 个答案:

答案 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 );
    }