使用来自不同类加载器的键的 EnumMap 的奇怪行为
我遇到了由不同类加载器加载的枚举类型的奇怪行为。在公共库中,我有枚举定义(类似于以下内容):
enum MyEnumType { VAL_1, VAL_2, VAL_3 };
我有第一个应用程序,它创建以下地图并将其注册为系统中的某种全局变量(为了简单起见,注册代码只是象征性的):
final Map<MyEnumType, String> map = new EnumMap<MyEnumType, String>(MyEnumType.class);
map.put(MyEnumType.VAL_1, "value 1");
map.put(MyEnumType.VAL_2, "value 2");
map.put(MyEnumType.VAL_3, "value 3");
GLOBAL_SYSTEM_MAP = Collections.unmodifiableMap(map);
第二个应用程序(具有不同的类加载器)执行以下操作:
String value = GLOBAL_SYSTEM_MAP.get(MyEnumType.VAL_1);
并接收空值。我使用调试器检查 GLOBAL_SYSTEM_MAP 是否正确,包含适当的值,但 get() 方法仍然没有返回任何正确的值。
我怀疑原因可能与两个应用程序用于加载 MyEnumType 类型的不同类加载器有关。但另一方面,枚举的 equals() 方法可能是为这种情况准备的,不是吗?那么,也许 EnumMap.get() 实现使用 == 而不是 equals() ? (但我相当怀疑)我也尝试用 HashMap 替换 EnumMap 但这也没有解决问题。
I encountered strange behavior of enum type loaded by different class loader. In common library I have enum definition (similar to the following):
enum MyEnumType { VAL_1, VAL_2, VAL_3 };
I have first application which creates following map and registers it as some kind of global in the system (the registration code is only symbolic for simplicity):
final Map<MyEnumType, String> map = new EnumMap<MyEnumType, String>(MyEnumType.class);
map.put(MyEnumType.VAL_1, "value 1");
map.put(MyEnumType.VAL_2, "value 2");
map.put(MyEnumType.VAL_3, "value 3");
GLOBAL_SYSTEM_MAP = Collections.unmodifiableMap(map);
The second application (with different class loader) performs following operation:
String value = GLOBAL_SYSTEM_MAP.get(MyEnumType.VAL_1);
and receives null value. I checked using debugger that the GLOBAL_SYSTEM_MAP was correct, contained appropriate values, yet get() method still didn't return any correct value.
I suspect that the reason may be connected with different class loaders used by both applications to load MyEnumType type. But on the other hand, the enum's equals() method is probably prepared for such a case, isn't it? So, maybe the EnumMap.get() implementation uses == instead of equals()? (but I rather doubt that) I also tried replace EnumMap by HashMap but this didn't solve the problem either.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
EnumMap 检查您传入的键的实际类与创建它所用的枚举的类。如果它们不同,
get
将返回 null。该类将会有所不同,因为您使用不同的类加载器加载 MyEnum 类两次。修复方法是安排两个应用程序使用 MyEnum 类的共享实例。
EnumMap checks the actual class of the key you pass in against the class of the enum it was created with. If they are different,
get
will return null. The class will be different since you are loading the MyEnum class twice with different classloaders.The fix is to arrange for both applications use a shared instance of the MyEnum class.
不同类加载器加载的
enum
值不应是==
或equals
。如果将不同类加载器中具有相同名称的不同类视为相同,通常应该会出现某种错误。 GLOBAL_SYSTEM_MAP 的类型是Map
还是Map
(或类似)?隐藏错误的一个可能原因是某些类加载器不会首先委托给其父类加载器(IIRC,违反了 Java SE 规范,由 EE 规范推荐)。这会导致各种各样的问题。
enum
values loaded by different class loader should neither be==
orequals
. You should generally get some kind of error if treating different classes with the same name from different class loaders as the same. Is the type ofGLOBAL_SYSTEM_MAP
Map<MyEnumType,String>
orMap<?,String>
(or similar)?One possible reason for an error to be hidden is that some class loaders do not delegate to their parent first (IIRC, breaks the Java SE spec, recommended by the EE specs). This causes all manner of problems.