C05 单例模式 Enum枚举单例(二) 抗反射攻击分析
枚举单例抗反射攻击演示(一)
NoSuchMethodException
报的是枚举类
EnumInstance
中没有
getDeclaredConstructor()
这个方法;
EnumInstance
枚举类中没有无参构造器;
public enum EnumInstance {
INSTANCE;
private Object data;
public Object getData() {
return data;
public void setData(Object data) {
this.data = data;
public static EnumInstance getInstance() {
return INSTANCE;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
reflectionAttack();
public static void reflectionAttack() throws Exception {
Class objectClass = EnumInstance.class;
Constructor constructor = objectClass.getDeclaredConstructor();
constructor.setAccessible(true);
Exception in thread "main" java.lang.NoSuchMethodException: designpattern.creational.singleton.enuminstance.EnumInstance.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at designpattern.creational.singleton.enuminstance.Test.reflectionAttack(Test.java:14)
at designpattern.creational.singleton.enuminstance.Test.main(Test.java:9)
攻击失败源码分析(一)
Enum
类中只有一个构造器,该构造器有 2 个参数,所以在用 objectClass.getDeclaredConstructor()
获取 Enum
的无参构造器时是无法获得的;
获取到了 Enum
类的构造器还是无法用反射创建出EnumInstance
类的实例;
这次报的错不一样,是 IllegalArgumentException: Cannot reflectively create enum objects
,说得很明显,不允许以反射的方式创建 enum
实例;
public class Test {
public static void main(String[] args) throws Exception {
reflectionAttack2();
public static void reflectionAttack2() throws Exception {
Class objectClass = EnumInstance.class;
Constructor constructor = objectClass.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
EnumInstance instance = (EnumInstance)constructor.newInstance("", 0);
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
at designpattern.creational.singleton.enuminstance.Test.reflectionAttack2(Test.java:16)
at designpattern.creational.singleton.enuminstance.Test.main(Test.java:9)
攻击失败源码分析(二)
java.lang.reflect.Constructor
类在 newInstance(Object ... initargs)
方法中针对需要被反射创建的对象的类型,专门针对 Enum
做了判断,在 Java 层面禁止了反射创建枚举实例的可能;
getInstance()
方法;
public static final EnumInstance INSTANCE;
在静态代码块中初始化,饿汉模式(可用防御代码抵御反射攻击);
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumInstance.java
package designpattern.creational.singleton.enuminstance;
public final class EnumInstance extends Enum
public static EnumInstance[] values()
return (EnumInstance[])$VALUES.clone();
public static EnumInstance valueOf(String name)
return (EnumInstance)Enum.valueOf(designpattern/creational/singleton/enuminstance/EnumInstance, name);
private EnumInstance(String s, int i)
super(s, i);
public Object getData()
return data;
public void setData(Object data)
this.data = data;
public static EnumInstance getInstance()
return INSTANCE;
public static final EnumInstance INSTANCE;
private Object data;
private static final EnumInstance $VALUES[];
static
INSTANCE = new EnumInstance("INSTANCE", 0);
$VALUES = (new EnumInstance[] {
INSTANCE
在枚举单例中定义方法
定义完的方法要在 EnumInstance
中定义抽象方法;
public enum EnumInstance {
INSTANCE {
protected void printTest() {
System.out.println("EmumInstance.INSTANCE.printTest()...");
protected abstract void printTest();
private Object data;
public Object getData() {
return data;
public void setData(Object data) {
this.data = data;
public static EnumInstance getInstance() {
return INSTANCE;
public class Test {
public static void main(String[] args) throws Exception {
EnumInstance instance = EnumInstance.getInstance();
instance.printTest();
EmumInstance.INSTANCE.printTest()...
反编译带方法的EnumInstance
变成抽象类了,所以要把定义好的方法声明成抽象方法;
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumInstance.java
package designpattern.creational.singleton.enuminstance.addmethod;
import java.io.PrintStream;
public abstract class EnumInstance extends Enum
public static EnumInstance[] values()
return (EnumInstance[])$VALUES.clone();
public static EnumInstance valueOf(String name)
return (EnumInstance)Enum.valueOf(designpattern/creational/singleton/enuminstance/addmethod/EnumInstance, name);
private EnumInstance(String s, int i)
super(s, i);
protected abstract void printTest();
public Object getData()
return data;
public void setData(Object data)
this.data = data;
public static EnumInstance getInstance()
return INSTANCE;
public static final EnumInstance INSTANCE;
private Object data;
private static final EnumInstance $VALUES[];
static
INSTANCE = new EnumInstance("INSTANCE", 0) {
protected void printTest()
System.out.println("EmumInstance.INSTANCE.printTest()...");
$VALUES = (new EnumInstance[] {
INSTANCE