考虑以下:
Map<Class<?>, Object> myMap = new HashMap<Class<?>, Object>();
Foo fooObject = New Foo();
myMap.put(fooObject.getClass(), fooObject)
请注意,java.lang.Class并没有实现hashCode()方法本身,而是隐式地从java.lang.Object继承了它。我在JDK 1.8中对此进行了验证。
java.lang.Class
可以安全用作java.util.HashMap
的 key 吗?myMap.get(Foo.class)
是否总是像myMap.put(fooObject.getClass(), fooObject)
一样返回我输入的值?考虑该软件具有各种类加载器和序列化机制。结果会还是一样吗?如果没有,那有什么选择呢? 最佳答案
是的。
是的。
将Class
对象用作HashMap
中的键是安全的。 Class
类继承了Object::equals
和Object::hashCode
方法。因此,equals
对象的Class
正在测试对象身份。
这是Java中类型相等的正确语义。 ClassLoader::defineClass
方法的实现可确保您永远无法获得表示相同Java类型的两个不同的Class
对象。
但是,有皱纹。 Java语言规范(JLS 4.3.4)声明如下:
(二进制名称与命名类型的FQDN相关,并考虑了匿名类和数组类型。)
这意味着如果(成功)在两个不同的类加载器中为具有完全限定名称的类调用ClassLoader::defineClass
,您将获得不同的Java类型。与您使用的字节码无关。此外,如果尝试从一种类型转换为另一种类型,则将获得类转换异常。
现在的问题是,这在您的用例中是否重要?
答:可能不会。
HashMap
中具有不同的条目。 (因为类型不同!)Class::getCanonicalName
获得该键。如果需要处理数组类等,请使用Class::getName
,它返回该类型的二进制名称。 序列化机制又如何呢?
Class
对象无法使用对象序列化进行序列化,因为Class
不实现Serializable
。如果实现/使用其他确实支持Class
对象序列化的序列化机制,则该机制需要与JLS 4.3.4兼容。