在为 Java 中的对象计算哈希值时如何考虑对象本身?

How can I take into consideration the object itself when calculating a hash for an object in Java?

当我开始研究一些算法问题时,我觉得它很有趣。如果我有两个列表(所以是两个不同的对象),具有相同的值,则哈希码是相同的。经过一番阅读,我明白这就是它的行为方式。例如:

        List<String> lst1 = new LinkedList<>(Arrays.asList("str1", "str2"));
        List<String> lst2 = new LinkedList<>(Arrays.asList("str1", "str2"));
        System.out.println(lst1.hashCode() + " " + lst2.hashCode());
        ...........
        Result: 2640541 2640541

例如,我的目的是区分列表中的 lst1 和 lst2。

是否有一种结构(例如 HashSet)在计算某物的哈希码时考虑实际对象而不仅仅是对象内部的值?

通常不在集合中,因为您通常希望所有相同项目的两个集合相等(这就是为什么他们这样实现它 - 等于 return true 并且哈希码相同) .

您可以对列表进行子类化,但不这样做,这不会广泛有用,而且如果其他程序员阅读您的代码,会造成很多混乱。在这种情况下,您只需要等于 return == 的结果,并将 hashCode 设为 return 引用的整数值(与 Object.equals 所做的相同)。

是的,您可以使用 java 的 java.util.IdentityHashMap, or guava's identity hash set

两个列表的哈希值must be equal,因为对象是相等的。但是上面的标识映射和设置是基于列表对象的标识,而不是它们的散列。

If I have two lists (so two different objects), with the same values, the hashcode is the same. After some reading, I understand that this is how it should behave.

是的,这是 java.util.List 规范的一部分。

Is there a structure (like a HashSet for example) that takes into consideration the actual object and not only the values inside the object when calculating the hashcode for something?

My purpose would be to differentiate between lst1 and lst2 in a list for example

这里的“在列表中”是什么意思不清楚。例如,Collection.contains()List.equals() 是在术语或成员的 equals() 方法中定义的,List.remove(Object) 的行为也是如此。虽然是不同的对象,但您的两个 List 将相互比较相等,因此这些方法不会直接区分它们,也不会直接区分它们,也不会作为另一个列表的成员。但是,您始终可以比较它们的引用相等性 (==),以确定它们不是同一对象,尽管彼此 equals()

对于考虑成员对象身份的集合,您可以考虑java.util.IdentityHashMap。两个这样的映射具有成对 equals() 彼此但不相同的键和关联值将不会相互比较 equals()。此类集合通常具有彼此不同的哈希码,但不能保证这一点。但是请注意,IdentityHashMap 文档中的警告尽管它实现了 Map API,但许多行为细节与该接口的要求不一致。


另请注意

  • 以上大部分内容仅与成员类型覆盖 equals()hashCode() 的集合相关。 Object 的实现或继承自 Object 在引用相等的基础上区分对象,因此普通集合 类 对您来说并不奇怪。

  • 不需要相同的字符串文字来表示不同的对象,因此示例代码中的 lst1lst2 实际上可能包含相同的元素,在引用相等的意义上.