Talk is cheap Show me the code
个人学习笔记--仅供参考
基于上次内容,我们的单例模式已完善,看似没有问题了,也保证了单例对象的唯一性
但是,通过其他非正常手段还是可以改变你单例
1通过反射机制
package pattern;
import java.lang.reflect.Constructor;
/**
*
* @author qsnp236
*
*/
public class LazyInnerClassSingletonTest {
public static void main(String[] args) {
try {
//查你基因信息
Class<?> clazz= LazySingletonInnerClass.class;
//复制你的基因信息
Constructor<?> c = clazz.getDeclaredConstructor();
//剥夺你的政治权利,后续操作合法化,你不能拒绝
c.setAccessible(true);
//用你的基因克隆一个你
Object o1=c.newInstance();
//用你的基因再次克隆一个你
Object o2=c.newInstance();
System.out.println(o1==o2);
System.out.println(o1);
System.out.println(o2);
System.out.println(o1.hashCode());
System.out.println(o2.hashCode());
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果:
false
pattern.LazySingletonInnerClass@7852e922
pattern.LazySingletonInnerClass@4e25154f
2018699554
1311053135
需要改造
package pattern;
/**
* 懒汉式 ,在外部调用getInstance的时候,判断对象是不是空,为空就去床架一个,返回,
* 这种方式在getInstance 时,如果有多个同时调用,会产生两个对象,
* 这个是利用内部类
* @author qsnp236
*
*/
public class LazySingletonInnerClass {
/**
* 内部初始化函数
*/
private LazySingletonInnerClass() {
if(InnerClass.innerObj!=null) {
throw new RuntimeException("不允许创建多个实");
}
}
/**
* 提供外部访问,加锁
* @return
*/
public static final LazySingletonInnerClass getInstance() {
return InnerClass.innerObj;
}
private static class InnerClass{
public static final LazySingletonInnerClass innerObj =new LazySingletonInnerClass();
}
}
结果
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at pattern.LazyInnerClassSingletonTest.main(LazyInnerClassSingletonTest.java:21)
Caused by: java.lang.RuntimeException: 不允许创建多个实
at pattern.LazySingletonInnerClass.<init>(LazySingletonInnerClass.java:16)
... 5 more
2.通过深度拷贝,序列化和反序列化
package pattern;
import java.io.Serializable;
/**
* 懒汉式 ,在外部调用getInstance的时候,判断对象是不是空,为空就去床架一个,返回,
* 这种方式在getInstance 时,如果有多个同时调用,会产生两个对象,
* 这个是利用内部类
* @author qsnp236
*
*/
public class LazySingletonInnerClass2 implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 内部初始化函数
*/
private LazySingletonInnerClass2() {
}
/**
* 提供外部访问,加锁
* @return
*/
public static final LazySingletonInnerClass2 getInstance() {
return InnerClass.innerObj;
}
private static class InnerClass{
public static final LazySingletonInnerClass2 innerObj =new LazySingletonInnerClass2();
}
}
测试:
package pattern;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
/**
*
* @author qsnp236
* 序列化破坏单例
*
*/
public class LazyInnerClassSingletonTest3 {
public static void main(String[] args) {
try {
LazySingletonInnerClass2 lazySingletonInner1=LazySingletonInnerClass2.getInstance();
LazySingletonInnerClass2 lazySingletonInner2=null;
//利用序列化和反序列化产生lazySingletonInner2
FileOutputStream fos=new FileOutputStream("LazySingletonInnerClass2.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(lazySingletonInner1);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("LazySingletonInnerClass2.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
lazySingletonInner2 = (LazySingletonInnerClass2)ois.readObject();
ois.close();
System.out.println(lazySingletonInner1);
System.out.println(lazySingletonInner2);
System.out.println(lazySingletonInner1 == lazySingletonInner2);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果
pattern.LazySingletonInnerClass2@3d4eac69
pattern.LazySingletonInnerClass2@776ec8df
false
克隆模式尝试
package pattern;
/**
* 懒汉式 ,在外部调用getInstance的时候,判断对象是不是空,为空就去床架一个,返回,
* 这种方式在getInstance 时,如果有多个同时调用,会产生两个对象,
* 这个是利用内部类
* @author qsnp236
*
*/
public class LazySingletonInnerClass3 implements Cloneable{
/**
* 内部初始化函数
*/
private LazySingletonInnerClass3() {
}
/**
* 提供外部访问,加锁
* @return
*/
public static final LazySingletonInnerClass3 getInstance() {
return InnerClass.innerObj;
}
private static class InnerClass{
public static final LazySingletonInnerClass3 innerObj =new LazySingletonInnerClass3();
}
@Override
public Object clone() throws CloneNotSupportedException
{
Object object = super.clone();
return object;
}
}
测试
package pattern;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
/**
*
* @author qsnp236
* 克隆破坏单例
*
*/
public class LazyInnerClassSingletonTest3 {
public static void main(String[] args) {
LazySingletonInnerClass3 l1=LazySingletonInnerClass3.getInstance();
try {
LazySingletonInnerClass3 l2=(LazySingletonInnerClass3) l1.clone();
System.out.println(l1);
System.out.println(l2);
System.out.println(l1 == l2);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果
pattern.LazySingletonInnerClass3@7852e922
pattern.LazySingletonInnerClass3@4e25154f
false
防止序列化
package pattern;
import java.io.Serializable;
/**
* 懒汉式 ,在外部调用getInstance的时候,判断对象是不是空,为空就去床架一个,返回, 这种方式在getInstance
* 时,如果有多个同时调用,会产生两个对象, 这个是利用内部类
*
* @author qsnp236
*
*/
public class LazySingletonInnerClass4 implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 内部初始化函数
*/
private LazySingletonInnerClass4() {
}
/**
* 提供外部访问,加锁
*
* @return
*/
public static final LazySingletonInnerClass4 getInstance() {
return InnerClass.innerObj;
}
private static class InnerClass {
public static final LazySingletonInnerClass4 innerObj = new LazySingletonInnerClass4();
}
// 强行阉割,底层调用的时候屏蔽掉新生成的对象
private Object readResolve() {
return InnerClass.innerObj;
}
}
测试类
package pattern;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
/**
*
* @author qsnp236
*
*/
public class LazyInnerClassSingletonTest4 {
public static void main(String[] args) {
try {
LazySingletonInnerClass4 lazySingletonInner1=LazySingletonInnerClass4.getInstance();
LazySingletonInnerClass4 lazySingletonInner2=null;
//利用序列化和反序列化产生lazySingletonInner2
FileOutputStream fos=new FileOutputStream("LazySingletonInnerClass2.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(lazySingletonInner1);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("LazySingletonInnerClass2.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
lazySingletonInner2 = (LazySingletonInnerClass4)ois.readObject();
ois.close();
System.out.println(lazySingletonInner1);
System.out.println(lazySingletonInner2);
System.out.println(lazySingletonInner1 == lazySingletonInner2);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果,
pattern.LazySingletonInnerClass4@3d4eac69
pattern.LazySingletonInnerClass4@3d4eac69
true