「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。 单例模式就是仅仅有一个实例,那么有没有方法可以破坏这一特性呢?有三种方式可以破坏单例模式,分别是反射,克隆,和序列化。
一、使用反射破坏单例模式
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
DoubleLockSingle doubleLockSingleA = DoubleLockSingle.getInstance();
Class<?> clazz = Class.forName("com.cn.model.single.DoubleLockSingle");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
DoubleLockSingle doubleLockSingleB = (DoubleLockSingle) declaredConstructor.newInstance();
System.out.println(doubleLockSingleA);
System.out.println(doubleLockSingleB);
System.out.println(doubleLockSingleA==doubleLockSingleB);
}
clazz.getDeclaredConstructor()获取指定参数的构造器(方法不限参数,根据参数确定是那个构造器),上面没有参数获取的就是无参构造器。然后设置为允许访问,即可通过反射的方式创建构造器,从而通过反射创建对象,绕过了单例不能创建对象的问题,打破了单例模式。
二、使用克隆破坏单例模式
上述为单例类,这里必须实现Cloneable接口,重写clone方法。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
DoubleLockSingle doubleLockSingleA = DoubleLockSingle.getInstance();
Class<?> clazz = Class.forName("com.cn.model.single.DoubleLockSingle");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
DoubleLockSingle doubleLockSingleB = (DoubleLockSingle) declaredConstructor.newInstance();
System.out.println(doubleLockSingleA);
System.out.println(doubleLockSingleB);
System.out.println(doubleLockSingleA==doubleLockSingleB);
}
此处是通过克隆对象的方式,创建了一个新的对象,从而打破了私有构造方法无法创建对象的情况,创建了新的对象,破坏了单例模式,结果如下,可以看出A和B不是同一个对象。
三、使用序列化破坏单例模式
此处必须实现Serializeable接口,表明类可以序列化(把对象序列化成二级制字节流的形式必须实现此接口,例如把对象存到redis中,如果转换成JSON格式可以不用实现此接口)。
DoubleLockSingleOfSerialize doubleLockSingleA = DoubleLockSingleOfSerialize.getInstance();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("temp"));
objectOutputStream.writeObject(doubleLockSingleA);
File file = new File("temp");
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
DoubleLockSingleOfSerialize doubleLockSingleB = (DoubleLockSingleOfSerialize) objectInputStream.readObject();
System.out.println(doubleLockSingleA);
System.out.println(doubleLockSingleB);
System.out.println(doubleLockSingleA==doubleLockSingleB);
这里就是先把类写到一个临时文件里面,然后在读出来,最后同样破坏了单例模式。此处序列化后反序列化回来不是同一个对象,从而打破了单例模式。
四、为啥要破坏泛型
这个我本人不是很能理解为什么要破坏泛型,我不写反射去破坏它不就没得问题了吗?但实际上,我们用别人的jar包的时候,某个类是单例的,然后我们去破坏它,这个不就是很尴尬了吗。换成我们自己提供的jar,别人搞破坏后问你,这就比较尴尬了。可能有别的原因,请大佬指点。