在Java中使用任意对象作为Map键的任何缺点?

时间:2009-03-11 15:21:03

标签: java collections maps

我的应用程序中有两种对象,其中一种对象只有一种对应的对象。

跟踪这种关系的明显选择是Map<type1, type2>,就像HashMap一样。但不知何故,我很怀疑。我可以将一个对象用作Map中的一个键,传递它,将它放在另一个集合中,并随时从Map中检索它的伙伴吗?

创建一个对象后,我传来的只是一个标识符,对吧?所以可能没有问题。如果我对密钥进行序列化和反序列化怎么办?

还有其他警告吗?我应该使用其他东西来关联对象,就像我自己生成的数字一样吗?

8 个答案:

答案 0 :(得分:22)

  1. 关键需要正确实施.equals().hashCode()
  2. 密钥不得以任何方式进行更改,以便在用作密钥时更改.hashCode()
  3. 理想情况下,用作HashMap中的键的任何对象都应该是不可变的。这将自动确保2.始终保持为真。
  4. 当用作关键字和/或值时,可能会保留其他GC对象。

答案 1 :(得分:7)

  

我有两种物品   应用程序中的每个对象   善良只有一个对应   另一种对象。

这听起来像是一种关系,因此可以使用简单的属性来实现。

答案 2 :(得分:3)

这取决于您选择的地图的实施情况:

  • HashMap 使用 equals() hashCode()。默认情况下(在Object中)这些都基于对象标识,除非您序列化/反序列化,否则它将正常工作。通过基于对象内容的equals()和hashCode()的正确实现,您将没有任何问题,只要您在哈希映射中键入时不进行修改。

  • TreeMap 使用 compareTo()。没有默认实现,因此您需要提供一个。同样的限制适用于实现上面的hashCode()和equals()。

答案 3 :(得分:1)

您可以使用标准地图,但这样做会在地图中保留对对象的强引用。如果您的对象在另一个结构中被引用,并且您需要Map只是将它们链接在一起,请考虑使用WeakHashMap。

顺便说一句,你不必重写equals和hashCode,除非你必须考虑一个对象的几个实例是相等的......

答案 4 :(得分:1)

  

我可以将一个对象用作Map中的一个键,传递它,将它放在另一个集合中,并随时从Map中检索它的伙伴吗?

是的,这里没问题。

  

创建一个对象后,我传来的只是一个标识符,对吧?所以可能没有问题。如果我对密钥进行序列化和反序列化怎么办?

没错,你只是传递一个引用 - 它们都指向同一个实际对象。如果序列化或反序列化对象,则会创建一个新对象。但是,如果您的对象正确实现了equals和hashCode,您仍然可以使用新的反序列化对象从地图中检索项目。

  

还有其他警告吗?我应该使用其他东西来关联对象,就像我自己生成的数字一样吗?

至于警告,是的,当对象在Map中时,你不能改变任何会导致对象的hashCode改变的东西。

答案 5 :(得分:0)

任何对象都可以是地图键。这里重要的是确保为任何将用作映射键的对象覆盖.equals()和.hashCode()。

你这样做的原因是,如果不这样做,则equals将被理解为对象相等,并且你能够找到“相等”地图键的唯一方法是拥有原始对象本身的句柄

您覆盖哈希码,因为它需要与equals一致。这样,您定义为等于哈希的对象相同。

答案 6 :(得分:0)

失败点是哈希码和等于函数。如果它们不能产生一致且正确的返回值,则Map的行为会很奇怪。 Effective Java有关于它们的整个部分,并且非常强烈推荐。

答案 7 :(得分:0)

您可以考虑使用Google Collection BiMap