1、静态内部类
public class InnerClassSingleton implements Serializable {
//无参构造函数
private InnerClassSingleton(){};
public static final InnerClassSingleton getInstance(){
return InnerClassHelper.INSTANCE;
}
//内部类
private static class InnerClassHelper{
private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
}
它的原理是利用了类加载机制。
1.1、但是它可以被反射破坏
Class clazz = InnerClassSingleton.class;
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object o1 = c.newInstance();
Object o2 = InnerClassSingleton.getInstance();
执行这段代码会发现o1<>o2,这就破坏了单例。
为什么呢?罪魁祸首就是如下代码,它是反射的newInstance()的底层实现。
UnsafeFieldAccessorImpl.unsafe.allocateInstance(class)
我们知道new创建对象时会被编译成3条指令:
- 1、根据类型分配一块内存区域
- 2、把第一条指令返回的内存地址压入操作数栈顶
- 3、调用类的构造函数
而Unsafe.allocateInstance()方法值做了第一步和第二步,即分配内存空间,返回内存地址,没有做第三步调用构造函数。所以Unsafe.allocateInstance()方法创建的对象都是只有初始值,没有默认值也没有构造函数设置的值,因为它完全没有使用new机制,绕过了构造函数直接操作内存创建了对象,而单例是通过私有化构造函数来保证的,这就使得单例失败。
1.2、还可以被反序列化破坏
InnerClassSingleton o1 = null;
InnerClassSingleton o2 = InnerClassSingleton.getInstance();
FileOutputStream fos = new FileOutputStream("InnerClassSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(o2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("InnerClassSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
o1 = (InnerClassSingleton) ois.readObject();
ois.close();
System.out.println(o1);
System.out.println(o2);
执行完这段代码我们又会发现o1<>o2,可见通过反序列化,成功破坏了