java - Singleton模式序列化问题?
PHP中文网
PHP中文网 2017-04-17 11:51:32
0
2
377

单例实现的一种方式:私有构造器,公有静态工厂方法

public class Singleton2 { private static final Singleton2 INSTANCE = new Singleton2(); // 私有静态final域 /* * 私有构造器 */ private Singleton2() { } /* * 公有静态工厂方法 */ public static Singleton2 getInstance() { return INSTANCE; } }
  • 为了使利用这种方法实现的Singleton类变成可序列化的,仅仅在申明中加上“implements
    Serializable”是不够的。为了维护并保证Singleton,必须声明所有的实例域都是transient,并提供一个readResolve()方法,否则,每次反序列化一个序列化的实例时都会创建一个新的实例。

这段话是effective java中的描述,我不理解的是为什么仅仅加上implements Serializable不行呢,反序列化一个序列化的实例时会创建一个新的实例?

--

补充问题:
关于这种单例模式有一种评论如下:
这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载这时候初始化instance显然没有达到lazy loading的效果。
这里的其他方式还可以是什么?

PHP中文网
PHP中文网

认证0级讲师

répondre à tous (2)
黄舟

1 为什么仅仅加上implements serializable不行
这种方式的单例模式构建的基础是封装性,如何实现单例呢?由于构造函数变为了私有,外部无法构造,只能通过Singleton2.getInstance()来获取,这样实现了单列,但是序列化时是这样吗?序列对象如何知道调用getInstance()来获取对象呢?我们来看看java底层序列化的实现,打开JDK中类ObjectStreamClass(这个类是负责序列化类对象的)

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

再往下跟踪可以明显看出他是用反射方式来序列化,用反射方式,不是调用getinstance(),当然单例就失效了
2 每次反序列化一个序列化的实例时都会创建一个新的实例
由于反序列化时也是用反射,所有当然每一个对象会创建一个新的实例

    迷茫

    补充一下吧, 这里反序列化时, 会生成一个新的实例, 是因为可以在 反射中绕开 java里访问权限的限制.

    http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible(boolean)

    对应到java源代码里, 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; //... }

    这样, 反序列化时, 即可直接调用到 singleton的 私有构造器 来生成一个新的对象实例.

      Derniers téléchargements
      Plus>
      effets Web
      Code source du site Web
      Matériel du site Web
      Modèle frontal
      À propos de nous Clause de non-responsabilité Sitemap
      Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!