反编译EnumSingleton.class文件
package com.lmc.gp12380.pattern.singleton.register; public final class EnumSingleton extends Enum { public static EnumSingleton[] values() { return (EnumSingleton[])$VALUES.clone(); } public static EnumSingleton valueOf(String name) { return (EnumSingleton)Enum.valueOf(com/lmc/gp12380/pattern/singleton/register/EnumSingleton, name); } private EnumSingleton(String s, int i) { super(s, i); } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance() { return INSTENCE; } public static final EnumSingleton INSTENCE; private Object data; private static final EnumSingleton $VALUES[]; static { INSTENCE = new EnumSingleton("INSTENCE", 0); $VALUES = (new EnumSingleton[] { INSTENCE }); } }反编译之后枚举 INSTENCE变成了静态最终变量,由静态代码块饿汉式初始化,EnumSingleton构造函数也是私有的,不允许外部创建对象。所有枚举符合单例需求。
测试代码
/** * @description: 枚举单例测试 * @author: lmc * @create: 2019-04-03 15:33 **/ public class EnumSingletonTest { public static void main(String[] args) { for (int i = 0; i <10 ; i++) { Thread thread=new Thread(new Runnable() { @Override public void run() { EnumSingleton enumSingleton=EnumSingleton.getInstance(); System.out.println(Thread.currentThread().getName()+"enumSingleton>>"+enumSingleton); } }); thread.start(); } } }测试结果
上述代码中,饿汉式和懒汉式,在私有化构造方法中都是有条件抛出异常
if(condition){ throw new RuntimeException("单例类,不允许被反射实例化"); }这段代码是为了保证单例类只能实例化一次,防止反射破坏单例。
private Object readResolve(){ return hungrySingletonOne; }上面的代码是重写了Serializable接口的readResolve方法,是为了防止序列化破坏单例对象。
防止反射破坏单例测试
/** * @description: 反射破坏单例测试 * @author: lmc * @create: 2019-05-25 23:19 **/ public class TestReflectDestructionSingleton { public static void main(String[] args) { try { LazyInnerClassSingleton lazyInnerClassSingleton1= LazyInnerClassSingleton.getInstance(); System.out.println(lazyInnerClassSingleton1); Class<?> clazz=LazyInnerClassSingleton.class; Constructor c=clazz.getDeclaredConstructor(null); c.setAccessible(true); LazyInnerClassSingleton lazyInnerClassSingleton2= (LazyInnerClassSingleton) c.newInstance(); System.out.println(lazyInnerClassSingleton2); System.out.println(lazyInnerClassSingleton1==lazyInnerClassSingleton2); }catch (Exception e){ e.printStackTrace(); } } }测试结果
利用反射生成实例,直接抛出异常,中断程序运行。客户端调用就不会去利用反射了。
去掉上面的抛出异常的条件执行测试程序,会出现两个不一样的实例,单例被破坏。
防止序列化破坏
/** * @description: 序列化破坏单例测试 * @author: lmc * @create: 2019-05-25 23:13 **/ public class TestSerializDestructionSingleton { public static void main(String[] args) { LazyInnerClassSingleton s1 = null; LazyInnerClassSingleton s2 = LazyInnerClassSingleton.getInstance(); FileOutputStream fos = null; try { fos = new FileOutputStream("LazyInnerClassSingleton.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s2); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("LazyInnerClassSingleton.txt"); ObjectInputStream ois = new ObjectInputStream(fis); s1 = (LazyInnerClassSingleton)ois.readObject(); ois.close(); System.out.println(s1); System.out.println(s2); System.out.println(s1 == s2); } catch (Exception e) { e.printStackTrace(); } } }测试结果
序列化和反序列化生成的对象和之前的对象是一样的,这就说明单例模式有效。
验证序列化破坏单例只需要去掉重写的readResolve方法就可以得到两个不一样的实例,单例被破坏。
反射破坏单例测试和序列化破坏单例只需要更换类就能测试其他单例了,在这就不做测试了。
注册式容器式单例是从Map集合获取对象,不需要做单例破坏测试。
注册式枚举式单例是重JVM层面防止单例破坏。虽然没有加上面的防止破坏代码,也可以用上面的测试代码测试。