详解单例模式
什么是单例模式?
根据我的理解,在程序运行期间,类只实例化出一个对象,即,一个类只有一个实例化对象,我们把这种设计模式称为单例模式,通常在我们用JAVA代码构建单例模式时又分为饿汉式和DCL(Double Check Lock)懒汉式,枚举式,前两者为了保证程序运行过程中只有一个实例化对象,我们的构造方法必须设为private,下面我们就来分析这两种单例模式。
饿汉式:一上来就实例化一个类的对象,程序运行阶段都只使用这有个对象,但可能会造成空间浪费。
懒汉式:即需要用到某个类的对象的时候才new出一个唯一对象,由于线程安全问题的缘故,要加上双重检测锁判断该对象是否为空
正常的创建对象的步骤为:
(1)分配内存空间
(2)执行构造方法
(3)把对象指向空间
为避免指令重排序,我们要给静态的类对象加上volatile关键字
枚举式:使用枚举类
当然,天底下没有不透风的墙,我们的懒汉式和枚举式都会被反射机制所破坏,造成可以创建多个实例化对象的问题,那么我们就要想办法解决它。
可以通过反射机制拿到空参构造器,然后将权限设为可进入,那么就可以通过空参构造器调用newInstance方法来创建一个完全不用于类名实例化的对象,所以我们在得到一个唯一对象后,要禁止使用反射机制破坏单例模式。
如果我们的唯一对象是用类名实例化的对象,而别人要通过反射机制再实例化一个对象,我们可以这样处理。
反射破坏(正常new)解决方法 :在构造方法中加锁,如果正常new的对象不为空就抛出异常
我们可以在空参构造器中加一个判断,如果我们已经有了唯一对象,则抛出异常。
反射破坏(都用反射new)解决方法:
尽管我们这样做还是避免不了反射机制的破坏,比如反射破坏(通过反射获取到flag,并且设置其权限为可进入),我们同样可以通过反射机制拿到flag并在创建第二个对象之前强制改变它的值,使我们的判断无效。
下面来看枚举类的反射破坏。
同样以可以使用反射拿到枚举类的构造器,虽然源码中有枚举类的空参构造器,但事实上是不存在的,它的参数是String和int类型