为什么在包含 1l 的 HashSet<Long> 上调用时 .contains(1) return 为 false?

Why does .contains(1) return false when called on a HashSet<Long> that contains 1l?

public static void main(String[] args) {
    List<Long> list = Arrays.asList(1l,2l,3l);
    Set<Long> set = new HashSet<>(list);
    System.out.println(set); // [1, 2, 3]
    System.out.println(set.contains(1)); // false
}

set 包含 {1,2,3},但是当我调用 set.contains(1) 时 returns false。为什么 1 不自动转换为 1l?我认为这可能与 Java 自动装箱和转换问题有关。

因为 contains 由于遗留原因被定义为 contains(Object),而不是 contains(T)int 1,强制转换为对象,装箱为 Integer

评论中提到因为long不是int,所以集合中不会包含它,但我相信有更具体的答案可以专门针对这种情况给出。

如果我们查看 HashSet 源代码,我们会发现它的 contains 方法回退到 HashMap 的 containsKey 方法。调查一下,我们发现基本检查是这样的:

if (e.hash == hash && e.key.equals(key))

一个简单的检查将验证这两个值将产生相同的散列,但下面的直接检查将失败。

new Integer(1).equals(new Long(1l));

发生这种情况的原因正是评论中提到的。当您使用 Integer(或 Long)equals() 方法时,Java 要做的第一件事是检查类型是否相同。它 不会 进行任何转换。类型不同,因此结果为假。为避免这种情况,请先将整数转换为 long,然后再检查集合是否包含它。

请注意,此行为不同于使用原始类型比较 1 == 1l。 Java 不会将它们包装在对象中,也不会使用对象 .equals() 方法,因此跳过此评估。转换发生,结果是 true.