问题描述
我不确定如何提出这个问题.但是,这两行代码有什么不同呢?
I wasn't sure on how to ask this question. But, what is the different between these 2 lines of code?
Set<Integer> a = new HashSet<Integer>(); for (int i = 0; i < 100; i++) { a.add(i); a.remove(i - 1); } System.out.println(a.size());
我预计 99 是输出
输出为 1
Set<Short> a = new HashSet<Short>(); for (Short i = 0; i < 100; i++) { a.add(i); a.remove(i - 1); } System.out.println(a.size());
我预计 99 是输出
输出为 100
推荐答案
表达式 i - 1 的类型是 int 因为整数算术表达式中的所有操作数都是扩大到至少 int.Set
The type of the expression i - 1 is int because all operands in an integer arithmetic expression are widened to at least int. Set<Short> has add(Short) and remove(Object) so there's no casting/autoboxing needed on the remove call. Therefore you are trying to remove Integers from a set of Shorts.
请注意,由于这个原因,声明 Set
Note that for this reason it almost never makes sense to declare a Set<Number>:
final Set<Number> ns = new HashSet<>(); final short s = 1; ns.add(s); ns.add(s+0); ns.add(s+0L); System.out.println(ns); // prints [1, 1, 1]
作为奖励回合,如果您将 set 实现更改为 TreeSet,魔法就会消失,它会抛出 ClassCastException,从而放弃这个技巧.
As a bonus round, if you change the set implementation to TreeSet, the magic disappears and it throws a ClassCastException, giving away the trick.
在本质上,这个问题与相等是对称关系这一事实有关,它不能区分右手边和左手边.这些语义是 Java 的单一调度方法无法实现的.
Deep down, this issue has to do with the fact that equality is a symmetric relation, which must not distinguish the right hand side from the left hand side. These semantics are impossible to achieve with Java's single-dispatch methods.