在Java中使用任意对象作为Map键的任何缺点?
我的应用程序中有两种对象,其中一种对象只有一种对应的对象。
跟踪这种关系的明显选择是Map
,就像HashMap一样。 但不知何故,我很怀疑。 我可以将一个对象用作Map中的一个键,传递它,让它坐在另一个集合中,并随时从Map中检索它的伙伴吗?
创建一个对象后,我所传递的只是一个标识符,对吧? 所以可能没有问题。 如果我对密钥进行序列化和反序列化怎么办?
还有其他警告吗? 我应该使用其他东西来关联对象,就像我自己生成的数字一样吗?
- 关键需要正确实现
.equals()
和.hashCode()
- 密钥不得以任何方式更改,
.hashCode()
在将其用作密钥时更改其.hashCode()
值 - 理想情况下,在
HashMap
用作键的任何对象都应该是不可变的。 这将自动确保2.始终保持为真。 - 当它们用作键和/或值时,可能会保留可能以其他方式进行GC的对象。
我的应用程序中有两种对象,其中一种对象只有一种对应的对象。
这听起来像是一种关系,因此可以使用简单的属性来实现。
这取决于您选择的地图的实施:
-
HashMap使用equals()和hashCode() 。 默认情况下(在Object中)这些都基于对象标识,除非您序列化/反序列化,否则它将正常工作。 通过基于对象内容的equals()和hashCode()的正确实现,您将没有任何问题,只要您在哈希映射中键入时不进行修改即可。
-
TreeMap使用compareTo() 。 没有默认实现,因此您需要提供一个。 同样的限制适用于实现上面的hashCode()和equals()。
您可以使用标准Map,但这样做会在Map中保留对对象的强引用。 如果您的对象在另一个结构中被引用,并且您需要Map只是将它们链接在一起,请考虑使用WeakHashMap。
顺便说一句,你不必重写equals和hashCode,除非你必须考虑一个对象的几个实例相等…
我可以将一个对象用作Map中的一个键,传递它,让它坐在另一个集合中,并随时从Map中检索它的伙伴吗?
是的,这里没问题。
创建一个对象后,我所传递的只是一个标识符,对吧? 所以可能没有问题。 如果我对密钥进行序列化和反序列化怎么办?
没错,你只是传递一个引用 – 它们都指向同一个实际对象。 如果序列化或反序列化对象,则会创建一个新对象。 但是,如果您的对象正确实现了equals和hashCode,您仍然可以使用新的反序列化对象从地图中检索项目。
还有其他警告吗? 我应该使用其他东西来关联对象,就像我自己生成的数字一样吗?
至于警告,是的,当对象在Map中时,你不能改变任何会导致对象的hashCode改变的东西。
任何对象都可以是地图键。 这里重要的是确保为任何将用作映射键的对象覆盖.equals()和.hashCode()。
这样做的原因是,如果不这样做,则equals将被理解为对象相等,并且您能够找到“相等”的映射键的唯一方法是拥有原始对象本身的句柄。
您重写hashcode,因为它需要与equals一致。 这样,您定义为等于哈希的对象相同。
失败点是哈希码和等于函数。 如果它们不能产生一致且正确的返回值,则Map将表现得很奇怪。 有效的Java有一个完整的部分,强烈推荐。
您可以考虑使用Google Collection的BiMap 。