反射花式破坏单例
懒汉式
package singleton ;
import java. lang. reflect. Constructor ;
import java. lang. reflect. InvocationTargetException ;
public class SingletonLazyTest {
public static void main ( String [ ] args) throws IllegalAccessException , InstantiationException , NoSuchMethodException , InvocationTargetException {
SingletonLazy lazy = SingletonLazy . getInstance ( ) ;
SingletonLazy lazy1 = SingletonLazy . getInstance ( ) ;
Class < SingletonLazy > lazyClass = SingletonLazy . class ;
Constructor < SingletonLazy > constructor = lazyClass. getDeclaredConstructor ( ) ;
constructor. setAccessible ( true ) ;
SingletonLazy lazy2 = constructor. newInstance ( ) ;
System . out. println ( "正常获取的实例比较:" + ( lazy == lazy1) ) ;
System . out. println ( "正常获取实例与反射获取比较:" + ( lazy == lazy2) ) ;
System . out. println ( "lazy :" + lazy) ;
System . out. println ( "lazy1:" + lazy1) ;
System . out. println ( "lazy2:" + lazy2) ;
}
static class SingletonLazy {
public static SingletonLazy instance;
private SingletonLazy ( ) {
}
public static SingletonLazy getInstance ( ) {
if ( instance == null ) {
instance = new SingletonLazy ( ) ;
}
return instance;
}
}
}
正常获取的实例比较:true
正常获取实例与反射获取比较:false
lazy :singleton.SingletonLazyTest$SingletonLazy @4554617c
lazy1:singleton.SingletonLazyTest$SingletonLazy @4554617c
lazy2:singleton.SingletonLazyTest$SingletonLazy @74a14482
Process finished with exit code 0
结论:
从结果可以看出,lazy 和 lazy1是正常获取的,是同一实例 lazy2通过反射获取的,与lazy 和 lazy1已经不是同一实例 懒汉式的单例被反射破坏
饿汉式
package singleton ;
import java. lang. reflect. Constructor ;
import java. lang. reflect. InvocationTargetException ;
public class SingletonHungryTest {
public static void main ( String [ ] args) throws NoSuchMethodException , IllegalAccessException , InvocationTargetException , InstantiationException {
SingletonHungry hungry = SingletonHungry . getInstance ( ) ;
SingletonHungry hungry1 = SingletonHungry . getInstance ( ) ;
Class < SingletonHungry > hungryClass = SingletonHungry . class ;
Constructor < SingletonHungry > constructor = hungryClass. getDeclaredConstructor ( ) ;
constructor. setAccessible ( true ) ;
SingletonHungry hungry2 = constructor. newInstance ( ) ;
System . out. println ( "饿汉式正常获取的实例比较:" + ( hungry == hungry1) ) ;
System . out. println ( "饿汉式正常获取的实例与反射获取实例比较:" + ( hungry == hungry2) ) ;
System . out. println ( "hungry :" + hungry) ;
System . out. println ( "hungry1:" + hungry1) ;
System . out. println ( "hungry2:" + hungry2) ;
}
static class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry ( ) ;
private SingletonHungry ( ) {
}
public static SingletonHungry getInstance ( ) {
return instance;
}
}
}
饿汉式正常获取的实例比较:true
饿汉式正常获取的实例与反射获取实例比较:false
hungry :singleton.SingletonHungryTest$SingletonHungry @4554617c
hungry1:singleton.SingletonHungryTest$SingletonHungry @4554617c
hungry2:singleton.SingletonHungryTest$SingletonHungry @74a14482
Process finished with exit code 0
结论:
从结果可以看出,hungry 和 hungry1 是正常获取的,是同一实例 hungry2通过反射获取的,与hungry 和 hungry1 已经不是同一实例 饿汉式的单例被反射破坏
检查锁单例模式
package singleton ;
import java. lang. reflect. Constructor ;
import java. lang. reflect. InvocationTargetException ;
public class SingletonLazyLockTest {
public static void main ( String [ ] args) throws NoSuchMethodException , IllegalAccessException , InvocationTargetException , InstantiationException {
SingletonLazyLock lazyLock = SingletonLazyLock . getInstance ( ) ;
SingletonLazyLock lazyLock1 = SingletonLazyLock . getInstance ( ) ;
Class < SingletonLazyLock > lazyClass = SingletonLazyLock . class ;
Constructor < SingletonLazyLock > constructor = lazyClass. getDeclaredConstructor ( ) ;
constructor. setAccessible ( true ) ;
SingletonLazyLock lazyLock2 = constructor. newInstance ( ) ;
System . out. println ( "正常获取的实例比较:" + ( lazyLock == lazyLock1) ) ;
System . out. println ( "正常获取的实例比较:" + ( lazyLock == lazyLock2) ) ;
System . out. println ( "lazyLock :" + lazyLock) ;
System . out. println ( "lazyLock1:" + lazyLock1) ;
System . out. println ( "lazyLock2:" + lazyLock2) ;
}
static class SingletonLazyLock {
public static SingletonLazyLock instance;
private SingletonLazyLock ( ) {
}
public static synchronized SingletonLazyLock getInstance ( ) {
if ( instance == null ) {
instance = new SingletonLazyLock ( ) ;
} else {
throw new RuntimeException ( "禁止使用反射破坏单例" ) ;
}
return instance;
}
}
}
正常获取的实例比较:true
正常获取的实例比较:false
lazyLock :singleton.SingletonLazyLockTest$SingletonLazyLock @4554617c
lazyLock1:singleton.SingletonLazyLockTest$SingletonLazyLock @4554617c
lazyLock2:singleton.SingletonLazyLockTest$SingletonLazyLock @74a14482
Process finished with exit code 0
结论:
从结果可以看出,lazyLock和 lazyLock1是正常获取的,是同一实例 lazyLock2通过反射获取的,与lazyLock和 lazyLock1已经不是同一实例 加锁之后的单例看似很安全,但仍然可以被反射破坏
双重检查锁
package singleton ;
import java. lang. reflect. Constructor ;
import java. lang. reflect. InvocationTargetException ;
public class SingletonDoubleCheckLockTest {
public static void main ( String [ ] args) throws NoSuchMethodException , IllegalAccessException , InvocationTargetException , InstantiationException {
SingletonLazyDoubleLock lazyDoubleLock = SingletonLazyDoubleLock . getInstance ( ) ;
SingletonLazyDoubleLock lazyDoubleLock1 = SingletonLazyDoubleLock . getInstance ( ) ;
Class < SingletonLazyDoubleLock > lazyClass = SingletonLazyDoubleLock . class ;
Constructor < SingletonLazyDoubleLock > constructor = lazyClass. getDeclaredConstructor ( ) ;
constructor. setAccessible ( true ) ;
SingletonLazyDoubleLock lazyDoubleLock2 = constructor. newInstance ( ) ;
System . out. println ( "正常获取的实例比较:" + ( lazyDoubleLock == lazyDoubleLock1) ) ;
System . out. println ( "正常获取的实例比较:" + ( lazyDoubleLock == lazyDoubleLock2) ) ;
System . out. println ( "lazyDoubleLock :" + lazyDoubleLock) ;
System . out. println ( "lazyDoubleLock1:" + lazyDoubleLock1) ;
System . out. println ( "lazyDoubleLock2:" + lazyDoubleLock2) ;
}
static class SingletonLazyDoubleLock {
public static SingletonLazyDoubleLock instance;
private SingletonLazyDoubleLock ( ) {
}
public static synchronized SingletonLazyDoubleLock getInstance ( ) {
if ( instance == null ) {
synchronized ( SingletonLazyDoubleLock . class ) {
if ( instance == null ) {
instance = new SingletonLazyDoubleLock ( ) ;
}
}
}
return instance;
}
}
}
正常获取的实例比较:true
正常获取的实例比较:false
lazyDoubleLock :singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock @4554617c
lazyDoubleLock1:singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock @4554617c
lazyDoubleLock2:singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock @74a14482
Process finished with exit code 0
结论:
从结果可以看出,lazyDoubleLock 和 lazyDoubleLock2是正常获取的,是同一实例 lazyDoubleLock 通过反射获取的,与lazyDoubleLock 和 lazyDoubleLock2已经不是同一实例 双重检查锁单例仍然可以被反射破坏
静态内部类
package singleton ;
import java. lang. reflect. Constructor ;
import java. lang. reflect. InvocationTargetException ;
public class SingletonInnerTest {
public static void main ( String [ ] args) throws NoSuchMethodException , IllegalAccessException , InvocationTargetException , InstantiationException {
SingletonInner inner = SingletonInner . getInstance ( ) ;
SingletonInner inner1 = SingletonInner . getInstance ( ) ;
Class < SingletonInner > lazyClass = SingletonInner . class ;
Constructor < SingletonInner > constructor = lazyClass. getDeclaredConstructor ( ) ;
constructor. setAccessible ( true ) ;
SingletonInner inner2 = constructor. newInstance ( ) ;
System . out. println ( "正常获取的实例比较:" + ( inner == inner1) ) ;
System . out. println ( "正常获取的实例比较:" + ( inner == inner2) ) ;
System . out. println ( "inner :" + inner) ;
System . out. println ( "inner1:" + inner1) ;
System . out. println ( "inner2:" + inner2) ;
}
static class SingletonInner {
private SingletonInner ( ) {
}
private static class SingletonHoler {
private static SingletonInner INSTANCE = new SingletonInner ( ) ;
}
public static final SingletonInner getInstance ( ) {
return SingletonHoler . INSTANCE ;
}
}
}
正常获取的实例比较:true
正常获取的实例比较:false
inner :singleton.SingletonInnerTest$SingletonInner @4554617c
inner1:singleton.SingletonInnerTest$SingletonInner @4554617c
inner2:singleton.SingletonInnerTest$SingletonInner @74a14482
Process finished with exit code 0
结论:
枚举单例
package singleton ;
import java. lang. reflect. Constructor ;
import java. lang. reflect. InvocationTargetException ;
public class SingletonEnumTest {
public static void main ( String [ ] args) throws NoSuchMethodException , IllegalAccessException , InvocationTargetException , InstantiationException {
SingletonEnum singletonEnum = SingletonEnum . getInstance ( ) ;
SingletonEnum singletonEnum1 = SingletonEnum . getInstance ( ) ;
Class < SingletonEnum > singletonEnumClass = SingletonEnum . class ;
Constructor < SingletonEnum > constructor = singletonEnumClass. getDeclaredConstructor ( ) ;
constructor. setAccessible ( true ) ;
SingletonEnum singletonEnum2 = constructor. newInstance ( ) ;
System . out. println ( "正常获取的实例比较:" + ( singletonEnum == singletonEnum1) ) ;
System . out. println ( "正常获取的实例比较:" + ( singletonEnum == singletonEnum2) ) ;
System . out. println ( "singletonEnum :" + singletonEnum. hashCode ( ) ) ;
System . out. println ( "singletonEnum1:" + singletonEnum1. hashCode ( ) ) ;
System . out. println ( "singletonEnum2:" + singletonEnum2. hashCode ( ) ) ;
}
enum SingletonEnum {
INSTANCE ;
public static SingletonEnum getInstance ( ) {
return INSTANCE ;
}
}
}
Exception in thread "main" java.lang.NoSuchMethodException: singleton.SingletonEnumTest$SingletonEnum .< init> ( )
at java.lang.Class.getConstructor0( Class.java:3074)
at java.lang.Class.getDeclaredConstructor( Class.java:2170)
at singleton.SingletonEnumTest.main( SingletonEnumTest.java:20)
Process finished with exit code 1
结论:
通过反射获取枚举单例实例异常 枚举形式的单例不能通过反射
防止反射破坏单例
通过上述示例可以看出枚举可以防止单例破坏 反射可以获取到单例类的私有构造,然后实例化
通过修改私有构造可以防止反射破坏单例
方式一、私有构造函数加锁
private SingletonLazyLock ( ) {
synchronized ( SingletonLazyLock . class ) {
if ( instance != null ) {
throw new RuntimeException ( "不要用反射破坏单例" ) ;
}
}
}
结果
方式二、私有构造函数加标识位
static class SingletonLazy {
public static SingletonLazy instance;
private static boolean flag = false ;
private SingletonLazy ( ) {
synchronized ( SingletonLazy . class ) {
if ( ! flag) {
flag = true ;
} else {
throw new RuntimeException ( "不要用反射破坏单例" ) ;
}
}
}
public static SingletonLazy getInstance ( ) {
if ( instance == null ) {
instance = new SingletonLazy ( ) ;
}
return instance;
}
}