【问题标题】:How does java serialization deserialize final fields when no default constructor specified?java序列化如何在未指定默认构造函数时反序列化最终字段?
【发布时间】:2016-08-28 07:45:39
【问题描述】:

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

这是一个类的例子

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

【问题讨论】:

    标签: java serialization final


    【解决方案1】:

    Michael 和 Stephen 都给了你一个很好的答案,我只是想提醒你注意 transient 字段。

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

        private void readObject (
                final ObjectInputStream s
            ) throws
                ClassNotFoundException,
                IOException
        {
            s.defaultReadObject( );
    
            // derivedValue is still 0
            this.derivedValue = derivedValue( value );
        }
    

    【讨论】:

    • 如果足够的话,你也可以在字段声明时赋值。
    • 如果这个瞬态字段是最终字段,那就太糟糕了。例如随机生成的 uuid
    【解决方案2】:

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

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

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

    【讨论】:

    • 事实上,你甚至不需要讨厌的黑魔法,反射(又名讨厌的灰色魔法;)可以用来设置最终字段。只要在第一次读取字段之前设置了值,它就可以工作。
    • @gustafc - 但是在不执行任何构造函数的情况下创建对象需要黑魔法。
    • ... 这很重要,因为任何构造函数的执行都可能产生不需要的副作用。无论如何,>>spec
    【解决方案3】:

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

    【讨论】:

    • 其实它确实调用了无参构造函数。只有具有这种构造函数的类是可序列化的。
    • @Oak。不对。您可以在没有默认构造函数的情况下序列化一个类。
    • @Alexander:我的错。我把它与可序列化类型的不可序列化超类必须具有这样的构造函数这一事实混淆了。
    • @Oak:对,所以迈克尔的回答实际上有点不准确(这对于这个问题的目的并不重要)。反序列化确实调用了层次结构中最后一个不可序列化类的构造函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多