在通常情况下饿汉式,懒汉式,静态内部类方式,的方法保证了单例,但是别有用心的人可以通过反射 将 .class(字节码文件) load到内存,然后new出一个实例。
但是枚举类因为没有构造方法,所以反射无法new出对象,就避免了通过反射来创建对象。
通过反射来破解饿汉式单例
public class test {
public static void main(String[] args) {
Class<?> c = null;
Person1 personReflection = null;
try {
c = Class.forName("com.luca.Person1"); //参数是类的全路径名
Constructor<?> cons = c.getDeclaredConstructor();//提示使用泛型,getDeclaredConstructor() 获取构造器,包括私有的
cons.setAccessible(true); //将权限set为true,使得可以访问私有的属性
Object obj1 = cons.newInstance();
personReflection = (Person1) obj1;
} catch (Exception e) {
e.printStackTrace();
}
Person1 instance1 = Person1.getInstance();
Person1 instance2 = Person1.getInstance();
System.out.println(personReflection);
System.out.println(instance1 == instance2);
System.out.println(personReflection == instance1);
}
Peroson1 类:
package com.luca;
public class Person1 {
private static final Person1 INSTANCE = new Person1();
private Person1() {
}
public static Person1 getInstance(){
return INSTANCE;
}
}
运行结果:
而枚举类方法就可以防止反射,因为java规定枚举类没有构造器。但是这样子写非常别扭,因为我们知道枚举类一般都有自己的用途,而现在所以的单例都要是枚举类就有些别扭。
public enum Mgr {
INSTANCE;
}