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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2904560/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:20:48  来源:igfitidea点击:

How does java serialization deserialize final fields when no default constructor specified?

javaserializationfinal

提问by mdma

I have an class defining an immutable value type that I now need to serialize. The immutability comes from the final fields which are set in the constructor. I've tried serializing, and it works (surprisingly?) - but I've no idea how.

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

Here's an example of the class

这是类的一个例子

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

Given that the class doesn't have a no arg constructor, how can it be instantiated and the final field set?

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

(An aside - I noticed this class particularly because IDEA wasn't generating a "no serialVersionUID" inspection warning for this class, yet successfully generated warnings for other classes that I've just made serializable.)

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

采纳答案by Michael Borgwardt

Deserialization is implemented by the JVM on a level below the basic language constructs. Specifically, it does not call any constructor.

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

回答by Stephen C

Given that the class doesn't have a no arg constructor, how can it be instantiated and the final field set?

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

Some nasty black magic happens. There is a backdoor in the JVM that allows an object to be created without invoking any constructor. The fields of the new object are first initialized to their default values (false, 0, null, etc), and then the object deserialization code populates the fields with values from the object stream.

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

(Now that Java is open sourced, you can read the code that does this ... and weep!)

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

回答by Alexander Pogrebnyak

Both Michael and Stephen gave you an excellent answer, I just want to caution you about transientfields.

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

If default value (nullfor references, 0 for primitives ) is not acceptable for them after deserialization then you have to provide your version of readObjectand initialize it there.

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

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

        // derivedValue is still 0
        this.derivedValue = derivedValue( value );
    }