55

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

这是该类的示例

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...
}

鉴于该类没有无参数构造函数,如何实例化它并设置最终字段?

(顺便说一句 - 我注意到这个类特别是因为 IDEA 没有为这个类生成“无 serialVersionUID”检查警告,但成功地为我刚刚使可序列化的其他类生成了警告。)

4

3 回答 3

44

反序列化由 JVM 在低于基本语言结构的级别实现。具体来说,它不调用任何构造函数。

于 2010-05-25T12:35:26.173 回答
24

鉴于该类没有无参数构造函数,如何实例化它并设置最终字段?

一些令人讨厌的黑魔法发生了。JVM 中有一个后门,它允许在不调用任何构造函数的情况下创建对象。新对象的字段首先被初始化为其默认值(false、0、null 等),然后对象反序列化代码使用对象流中的值填充字段。

(现在 Java 是开源的,您可以阅读执行此操作的代码……然后哭泣!)

于 2010-05-25T12:36:32.247 回答
13

迈克尔和斯蒂芬都给了你一个很好的答案,我只是想提醒你注意transient领域。

如果在反序列化后默认值(null对于引用,0 表示原语)对于它们来说是不可接受的,那么你必须提供你的版本readObject并在那里初始化它。

    private void readObject (
            final ObjectInputStream s
        ) throws
            ClassNotFoundException,
            IOException
    {
        s.defaultReadObject( );

        // derivedValue is still 0
        this.derivedValue = derivedValue( value );
    }
于 2010-05-25T12:53:29.750 回答