枚举类
public enum Color {
RED, GREEN, BLUE;
}
测试方法
/**
* @author zzs
*/
@RestController
@Slf4j
@RequestMapping("/test")
@Api(tags = "测试")
public class TestController {
static void makeAccessible(Field field) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~ Modifier.FINAL);
}
protected static Field getEnumsArrayField(Class< ? > ec) throws Exception {
Field field = ec.getDeclaredField("$VALUES");
field.setAccessible(true);
return field;
}
protected static void clearFieldAccessors(Field field) throws ReflectiveOperationException {
Field fa = Field.class.getDeclaredField("fieldAccessor");
fa.setAccessible(true);
fa.set(field, null);
Field ofa = Field.class.getDeclaredField("overrideFieldAccessor");
ofa.setAccessible(true);
ofa.set(field, null);
Field rf = Field.class.getDeclaredField("root");
rf.setAccessible(true);
Field root = (Field) rf.get(field);
if (root != null) {
clearFieldAccessors(root);
}
}
protected static <E extends Enum<E>> void setEnumsArray(Class<E> ec, E... e) throws Exception {
Field field = ec.getDeclaredField("$VALUES");
Field modifiersField = Field.class.getDeclaredField("modifiers");
field.setAccessible(true);
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(ec, e);
}
public static void main2(String[] args) {
Field[] declaredFields = Color.class.getDeclaredFields();
for (Field field : declaredFields) {
if (Modifier.isStatic(field.getModifiers())) {
System.out.println(field.getName() +":" + field.getType());
}
}
}
public static void main1(String[] args) throws Exception{
Color[] values = Color.values();
System.out.println(Arrays.toString(values));
System.out.println(Arrays.toString((Object[]) getEnumsArrayField(Color.class).get(null)));
clearFieldAccessors(getEnumsArrayField(Color.class));
setEnumsArray(Color.class, Color.BLUE, Color.GREEN, Color.RED, Color.BLUE);
System.out.println(Arrays.toString(Color.values()));
}
public static void main(String[] args) {
try {
Color[] values = Color.values();
System.out.println(Arrays.toString(values));
Class<Color> enumClass = Color.class;
// 找到构造函数,并使其可访问
Constructor< ? > constructor = enumClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
// 跳过枚举检查
Field constructorAccessorField = Constructor.class.getDeclaredField("constructorAccessor");
constructorAccessorField.setAccessible(true);
// sun.reflect.ConstructorAccessor -> 我们不应该使用它,如果你需要使用它,最好不要导入它,只能通过反射来使用。(包可能会改变,在Java 9中也会)
ConstructorAccessor ca = (ConstructorAccessor) constructorAccessorField.get(constructor);
if (ca == null) {
Method acquireConstructorAccessorMethod = Constructor.class.getDeclaredMethod("acquireConstructorAccessor");
acquireConstructorAccessorMethod.setAccessible(true);
ca = (ConstructorAccessor) acquireConstructorAccessorMethod.invoke(constructor);
}
// 注意,构造函数包含两个附加参数,名称和序号.你也可以调用它使用反射
Color enumValue = (Color) ca.newInstance(new Object[]{"WHITE", 1});
Field valuesField = Color.class.getDeclaredField("$VALUES");
makeAccessible(valuesField);
//复制旧值到新数组并添加我们的新字段。
Color[] oldValues = (Color[]) valuesField.get(null);
// Color[] newValues = new Color[oldValues.length + 1];
// System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
// newValues[oldValues.length] = enumValue;
Color[] newValues = new Color[oldValues.length];
System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
newValues[1] = enumValue;
valuesField.set(null, newValues);
Field enumConstantDirectoryField = Class.class.getDeclaredField("enumConstantDirectory");
enumConstantDirectoryField.setAccessible(true);
enumConstantDirectoryField.set(Color.class, null);
Field enumConstantsField = Class.class.getDeclaredField("enumConstants");
enumConstantsField.setAccessible(true);
enumConstantsField.set(Color.class, null);
Color[] values2 = Color.values();
System.out.println(Arrays.toString(values2));
System.out.println("-----------------------------------");
// Color[] values3 = Color.values();
// System.out.println(Arrays.toString(values3));
// Field enumConstantDirectoryField = Class.class.getDeclaredField("enumConstantDirectory");
// enumConstantDirectoryField.setAccessible(true);
// enumConstantDirectoryField.set(Color.class, null);
// Field enumConstantsField = Class.class.getDeclaredField("enumConstants");
// enumConstantsField.setAccessible(true);
// enumConstantsField.set(Color.class, null);
// Color[] values4 = Color.values();
//
// System.out.println(Arrays.toString(values4));
} catch (Exception e) {
e.printStackTrace();
}
}
}
启动main方法发现枚举类被改变。原理可知通过巧妙的方法绕过了枚举检查