Tho*_*mas 1 java reflection enums openjdk-11
我正在开发一个使用 JDK8 运行的项目,我们希望将其迁移到 OpenJDK11。
但是,有一些遗留代码可以在运行时动态创建枚举(使用反射和sun.reflect.*包):
public class EnumUtil {
static Object makeEnum(...) {
...
enumClass.cast(sun.reflect.ReflectionFactory.getReflectionFactory() .newConstructorAccessor(constructor).newInstance(params));
}
}
Run Code Online (Sandbox Code Playgroud)
或者
// before, field is made accessible, the modifier too
sun.reflect.FieldAccessor fieldAccessor = sun.reflect.ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false);
field.set(target, value);
Run Code Online (Sandbox Code Playgroud)
例如,假设我们有枚举AEnum:
public enum AEnum {
; // no values at compile time
private String label;
private AEnum (String label) {
this.label = label;
}
Run Code Online (Sandbox Code Playgroud)
然后,我们添加这样的枚举值:
EnumUtil.addEnum(MyEnum.class, "TEST", "labelTest");
Run Code Online (Sandbox Code Playgroud)
最后,在运行时,我们有一个带有 label = labelTest 的值AEnum.TEST(不是通过直接调用,而是通过)。Enum.valueOf
不幸的是,sun.reflect.*OpenJDK11 中不再提供类。
我尝试过使用jdk.internal.reflect.ConstructorAccessor,但出现错误java: package jdk.internal.reflect does not exist。而且我认为依赖课程并不是一个好主意jdk.internal.*。
是否有任何 OpenJDK11 替代方案可以在运行时创建枚举?
这个答案包含一种仅使用标准 API 的工作方法,即使使用 JDK\xc2\xa017,仍然可以工作。
\n由于它使用 JDK 类型作为示例,--add-opens java.base/java.lang=\xe2\x80\xa6在启动时需要一个参数,这里\xe2\x80\x99s 是一个使用它自己的示例enum,不需要对环境进行任何修改。
import java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.reflect.Constructor;\nimport java.util.EnumSet;\n\nclass EnumHack {\n public static void main(String[] args) throws Throwable {\n System.out.println(Runtime.version());\n Constructor<Example> c\n = Example.class.getDeclaredConstructor(String.class, int.class);\n c.setAccessible(true);\n MethodHandle h = MethodHandles.lookup().unreflectConstructor(c);\n Example baz = (Example) h.invokeExact("BAZ", 42);\n System.out.println("created Example " + baz + "(" + baz.ordinal() + \')\');\n EnumSet<Example> set = EnumSet.allOf(Example.class);\n System.out.println(set.contains(baz));\n set.add(baz);\n System.out.println(set);\n }\n\n enum Example {\n FOO, BAR\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n由于它不需要特殊设置,因此可以在 Ideone 上进行演示
\n12.0.1+12\ncreated Example BAZ(42)\nfalse\n\nException in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 42 out of bounds for length 2\n at java.base/java.util.RegularEnumSet$EnumSetIterator.next(RegularEnumSet.java:105)\n at java.base/java.util.RegularEnumSet$EnumSetIterator.next(RegularEnumSet.java:78)\n at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:472)\n at java.base/java.lang.String.valueOf(String.java:3042)\n at java.base/java.io.PrintStream.println(PrintStream.java:897)\n at EnumHack.main(Main.java:18)\nRun Code Online (Sandbox Code Playgroud)\n这不仅表明黑客完成了它的工作,而且还表明了由此引起的一些问题。应该包含所有元素的集合并不包含新常量,并且在手动添加后,所产生的不一致状态会在后续操作中产生异常。
\n因此,这样的枚举常量不能与枚举类型的标准工具一起使用,这与问题\xe2\x80\x99s评论中所说的相匹配,它失去了作为枚举类型的优势。事实上,它\xe2\x80\x99s比这更糟糕。
\n因此,上面显示的方法只能用作临时解决方法,或者根本不使用。
\n| 归档时间: |
|
| 查看次数: |
1686 次 |
| 最近记录: |