反射花式破坏单例
懒汉式
反射破坏单例代码演示:
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
;
}
}