来自 Java 6TreeSet<E>
文档:
boolean remove(Object o):
Removes the specified element from this set if it is present.
为什么这接受 Object 而不是泛型类型 E?唯一可以添加的对象是 E 类型,因此唯一可移除的类型应该是 E 类型。
来自 Java 6TreeSet<E>
文档:
boolean remove(Object o):
Removes the specified element from this set if it is present.
为什么这接受 Object 而不是泛型类型 E?唯一可以添加的对象是 E 类型,因此唯一可移除的类型应该是 E 类型。
从发布的第一条评论中得到答案:
神话:
一个流行的神话是它既愚蠢又邪恶,但由于向后兼容,它是必要的。但是兼容性论点是无关紧要的;无论您是否考虑兼容性,API 都是正确的。
真实原因:
统一地,Java 集合框架(以及 Google 集合库)的方法从不限制其参数的类型,除非有必要防止集合被破坏。
在此处阅读更多内容:为什么 Set.contains() 采用 Object,而不是 E?
remove()
,当给定一个相等的元素(根据)时,likeget()
需要工作。在 Java 中,不同类的对象可能(并且在某些情况下是必需的)相等。因此,您不应该限制类型。.equals()
好吧,每个 E 也是一个对象,也许你现在的 E 不是 E(例如来自事件源),这对你来说很方便。否则,您只需将其强制转换为 E 即可将其删除。
从相等的角度来看,这无关紧要:如果给定对象的引用地址等于集合的内容,则测试它的引用地址,因此它属于哪个类并不重要。
这确实是个问题。如果有人调用remove(o)
ando
的 type is not E
,这通常是一个试图删除错误内容的编程错误。类型检查未能保护我们免受错误的影响。
虽然一个好的 IDE (IntelliJ) 可以检测到此类问题并警告我们,但 API 设计人员应该提供更精确的签名来利用编译器类型检查。(IDE 在这里作弊 - 它知道 的含义,Set.remove()
因为它是标准 API。IDE 不会为自定义 API 提供相同的帮助)
对于类似的查询 API contains()
,可以接受一个非E
参数并返回一个微不足道的 false。所以我们可以同时拥有
boolean contains(Object o);
boolean contains2(E o);
对于类似的变异 API remove()
,它是否应该接受非E
参数是有争议的。然而,鉴于擦除的现实,这场辩论将毫无意义——除了接受非 E 论点并对此保持沉默之外,别无选择。我们仍然可以有两种方法
boolean remove(Object o);
boolean remove2(E o);
在大多数情况下,程序员可以要求contains2/remove2
额外的类型安全。