单例实现的一种方式:私有构造器,公有静态工厂方法
public class Singleton2 {
private static final Singleton2 INSTANCE = new Singleton2(); // 私有静态final域
/*
* 私有构造器
*/
private Singleton2() {
}
/*
* 公有静态工厂方法
*/
public static Singleton2 getInstance() {
return INSTANCE;
}
}
这段话是effective java中的描述,我不理解的是为什么仅仅加上implements Serializable不行呢,反序列化一个序列化的实例时会创建一个新的实例?
--
补充问题:
关于这种单例模式有一种评论如下:这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有
其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。
这里的其他方式还可以是什么?
黄舟2017-04-17 11:53:32
1 Why just adding implements serializable doesn’t work
The basis of this method of building a singleton pattern is encapsulation. How to implement a singleton? Since the constructor has become private, it cannot be constructed externally and can only be obtained through Singleton2.getInstance(). This achieves a single column, but is this the case during serialization? How does the sequence object know to call getInstance() to obtain the object? Let’s take a look at the implementation of Java’s underlying serialization and open the ObjectStreamClass class in the JDK (this class is responsible for serializing class objects)
private static ObjectStreamField[] getSerialFields(Class<?> cl)
throws InvalidClassException
{
ObjectStreamField[] fields;
if (Serializable.class.isAssignableFrom(cl) &&
!Externalizable.class.isAssignableFrom(cl) &&
!Proxy.isProxyClass(cl) &&
!cl.isInterface())
{
if ((fields = getDeclaredSerialFields(cl)) == null) {
fields = getDefaultSerialFields(cl);
}
Arrays.sort(fields);
} else {
fields = NO_FIELDS;
}
return fields;
}
Following the trace further, it can be clearly seen that it uses reflection to serialize. It uses reflection instead of calling getinstance(). Of course, the singleton will fail
2 A new instance is created every time a serialized instance is deserialized
Since reflection is also used during deserialization, of course each object will create a new instance
迷茫2017-04-17 11:53:32
Let me add that when deserializing here, a new instance will be generated because the access permission restrictions in Java can be bypassed in reflection.
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible(boolean)
corresponds to the java source code, jdk1.7.0.21, ObjectStreamClass.java:
private static Constructor getExternalizableConstructor(Class<?> cl) {
//...
Constructor cons = cl.getDeclaredConstructor((Class<?>[]) null);
cons.setAccessible(true);
//...
}
private static Constructor getSerializableConstructor(Class<?> cl) {
//...
Constructor cons = initCl.getDeclaredConstructor((Class<?>[]) null);
//...
cons = reflFactory.newConstructorForSerialization(cl, cons);
cons.setAccessible(true);
return cons;
//...
}
In this way, during deserialization, you can directly call singleton's private constructor to generate a new object instance.