我正在阅读Effective Java,并且遇到了这个例子。
class Elvis implements Serializable {
public static final Elvis inst = new Elvis();
private Elvis() {
System.out.println("In elvis constructor ");
}
public static Elvis getInstance() {
return inst;
}
}
根据这本书,当我反序列化时,应该构造一个新的ELVIS对象,但是我看到在反序列化时没有调用构造函数?
这是我的代码序列化和反序列化。
FileOutputStream fos = new FileOutputStream("myserial1.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
Elvis e = Elvis.getInstance();
System.out.println(" e = "+e.getInstance());
oos.writeObject(e);
System.out.println("Serialization done.");
FileInputStream fis = new FileInputStream("myserial1.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Elvis el = (Elvis) ois.readObject();
System.out.println(" el = "+el.getInstance());
我看到e和e1都引用相同的引用,构造函数只被调用一次。
我在这里误解了这个概念吗?
请帮忙。
答案 0 :(得分:8)
在序列化期间,不会调用构造函数,通过反序列化过程或readObject()
method初始化字段(如果将此方法添加到类中)。如果要实现可序列化的单例,则应另外添加readResolve()
方法,如其描述的here。
PS。
请注意,getInstance()
是类Elvis
的静态方法,因此e.getInstance()
和el.getInstance()
等调用等于Elvis.getInstance()
。
答案 1 :(得分:1)
我在这里误解了这个概念吗?
您误解的是构造函数创建了一个对象。不,不。构造函数只是初始化对象。现在,反序列化不需要调用构造函数,因为它已经具有序列化对象的状态,这就是它必须为我们提供的。
但是,如果在可序列化类的层次结构中,有一些非可序列化的类,那么它的构造函数将被调用以初始化该类中的状态,因为它尚未被序列化。
答案 2 :(得分:0)
According to the book, when i deserialize, a new ELVIS object should be constructed,
but i see the constructor is not called at the time of deserialization?
首先Object creation and constructor invocation are two separate thing
。在正常情况下,使用new
关键字创建对象时首先创建对象,然后调用构造函数。您可以看到创建对象的任何java类的字节码。
现在关于你的问题,在Serialization
对象中创建的对象与任何其他对象一样,而不是运行构造函数值/使用reflection
恢复状态。所以基本上从流中读取值(持久存储就是你的情况)并使用反射注入到对象中。
答案 3 :(得分:0)
由于Read和Write操作都在同一个jvm实例中执行
class已被加载用于读取操作,静态字段存储在类级别所以这里静态变量inst永远不需要重新实例化
public static final Elvis inst = new Elvis();
所以同样的引用是与类级别附加的返回