Maa*_*ten 7 java class hashmap hashcode
考虑以下:
Map<Class<?>, Object> myMap = new HashMap<Class<?>, Object>();
Foo fooObject = New Foo();
myMap.put(fooObject.getClass(), fooObject)
Run Code Online (Sandbox Code Playgroud)
请注意,java.lang.Class本身并不实现hashCode()方法,而是隐式地从java.lang.Object继承它.我在JDK 1.8中验证了这一点.
可以java.lang.Class安全地用作钥匙java.util.HashMap吗?将myMap.get(Foo.class)始终返回,我把喜欢的价值观myMap.put(fooObject.getClass(), fooObject)?考虑该软件具有各种类加载器和序列化机制.它仍然会是相同的结果吗?如果不是......会有什么选择?
在我的头顶,是否有任何理由不使用字符串类名?例如,改为使用:
myMap.put("Foo", fooObject);
Run Code Online (Sandbox Code Playgroud)
如果你是偏执狂,也许Foo在范围内可能有多个类,你可以使用完整的规范名称:
myMap.put(Foo.class.getCanonicalName(), fooObject);
Run Code Online (Sandbox Code Playgroud)
java.lang.Class 用作 java.util.HashMap 的键是否安全?
是的。
myMap.get(Foo.class) 是否总是返回我像 myMap.put(fooObject.getClass(), fooObject) 这样输入的值?
是的。
使用Class对象作为 a 中的键HashMap是安全的。该类Class继承了Object::equals和Object::hashCode方法。因此,equals对于Class对象来说,正在测试对象身份。
这是 Java 中类型相等的正确语义。该ClassLoader::defineClass方法的实现确保您永远无法获得Class代表相同 Java 类型的两个不同对象。
然而,有一个问题。Java 语言规范 ( JLS 4.3.4 ) 指出:
在运行时,具有相同二进制名称的多个引用类型可能会被不同的类加载器同时加载。这些类型可能代表也可能不代表相同的类型声明。即使两个这样的类型确实代表相同的类型声明,它们也被认为是不同的。
(二进制名称与命名类型的 FQDN 相关,并考虑匿名类和数组类型。)
这意味着,如果您(成功)ClassLoader::defineClass在两个不同的类加载器中调用具有相同完全限定名称的类,您将获得不同的 Java 类型。无论您使用什么字节码。此外,如果您尝试从一种类型转换为另一种类型,您将收到类转换异常。
现在的问题是这在您的用例中重要吗?
答:可能不会。
除非您(或您的框架)正在使用类加载器做一些棘手的事情,否则这种情况不会出现。
如果是这样,那么您可能需要两种类型(具有相同的 FQDN 和不同的类加载器)才能在HashMap. (因为类型不同!)
但是,如果您需要这两种类型具有相同的条目,那么您可以使用该类的 FQDN 作为键,您可以使用Class::getCanonicalName. 如果您需要处理数组类等,请使用Class::getName它返回类型的二进制名称。
序列化机制怎么样?
Class无法使用对象序列化来序列化对象,因为它没有Class实现Serializable. 如果您实现/使用某些支持Class对象序列化的其他序列化机制,则该机制需要与 JLS 4.3.4 兼容。
Class 的实例是唯一的,ClassLoader因此不需要覆盖hashCodeor equals。