1.3用私有构造器或者枚举类型强化singleton属性
1.3.1
饿汉式和懒汉式,通过反射机制被破解。需要强化校验当构造器被私有化后,程序员的任何行为都不会改变生成,该类只会生成一个实例。但是要注意的是反射机制。程序员可以借助AccessiableObject.setAccessiable方法(设置此方法后,将拥有访问私有属性,方法和构造器的能力),通过反射机制调用私有化的构造器。从而破坏了单例。
饿汉式,加强代码
public class Singleton {
private final static Singleton instance = new Singleton();
private Singleton (){
//在此处编写加强校验.如果第二次被调用,就抛出异常。这是为了防止被发射调用
if(instance!=null){
throw new RuntimeException("非法创建对象!");
}
}
public static Singleton getInstance() {
return instance;
}
}
懒汉式---DCL
public class Instance {
private static Instance ins = null;
private Instance(){
//在此处编写加强校验.如果第二次被调用,就抛出异常。这是为了防止被发射调用
if(instance!=null){
throw new RuntimeException("非法创建对象!");
}
}
/**
* DCL方式获取单例
* @return
*/
public static Instance getInstance(){
if (ins == null){
//为什么把synchronized加在这层,是提高性能。在多线程的情况,只要ins不为null。完全可以直接返回ins这个对象了。而不需要再去争夺锁。判断ins到底是不是空的。因为ins不是空的情况下,不会再执行生成实例的代码了。
synchronized (Instance.class){
if (ins == null){
ins = new Instance();
}
}
}
return ins;
}
}
1.3.2
饿汉式和懒汉式,通过序列化破解。需要强化代码当单例模式的类型实现了Serializable。对单例进行序列化,再进行反序列化之后,发现了序列化的对象和反序列的对象,不再相等。反序列化之后,又产生了新的对象。从而破坏了序列化。
懒汉式,加强代码
public class SingletonSerializable implements Serializable {
private static final long serialVersionUID = -1131868478960947804L;
private static final SingletonSerializable singletonSerializable = new SingletonSerializable();
private SingletonSerializable(){
}
public static SingletonSerializable getInstance(){
return singletonSerializable;
}
}
序列化和反序列化代码
public class TestSingleton {
@Test
public void testEqual() throws Exception{
//获取到单例对象
SingletonSerializable instance = SingletonSerializable.getInstance();
//序列化
FileOutputStream fileOutputStream = new FileOutputStream("temp");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(instance);
//反序列化
FileInputStream fileInputStream = new FileInputStream("temp");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
SingletonSerializable o = (SingletonSerializable)objectInputStream.readObject();
//打印结果
System.out.println(instance == o); //输入为false
}
}
对懒汉式进行代码强化
public class SingletonSerializable implements Serializable {
private static final long serialVersionUID = -1131868478960947804L;
private static final SingletonSerializable singletonSerializable = new SingletonSerializable();
private SingletonSerializable(){
}
public static SingletonSerializable getInstance(){
return singletonSerializable;
}
//加上此方法之后,序列化和反序化之后的对象将会相等。这里返回对象必须得是Object。这里涉及一些内部原理,不再过多的阐述了
private Object readResolve(){
return singletonSerializable;
}
}
1.3.4
枚举单例模式,无常的提供了序列化机制,并且不受反射的影响,天然的优势,使得枚举再实现单例模式时,代码更加简洁。更加安全。
public enum SingletonEnum{
INSTANCE;
public void doThing1(){
}
public void doThing2(){
}
}
public static void main(String[]args){
//去调用doThing1方法。
SingletonEnum.INSTANCE.doThing1();
}
网友评论