为什么在包含 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
.
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
.