【问题标题】:Why does Java's TreeSet<E> remove(Object) not take an E为什么 Java 的 TreeSet<E> remove(Object) 不采用 E
【发布时间】:2011-12-22 09:03:00
【问题描述】:

来自 Java 6 TreeSet&lt;E&gt; 文档:

boolean remove(Object o):
    Removes the specified element from this set if it is present.

为什么它接受一个 Object 而不是泛型类型 E?唯一可以添加的对象是 E 类型,因此唯一可移除的类型应该是 E 类型。

【问题讨论】:

标签: java generics collections treeset


【解决方案1】:

嗯,每个 E 也是一个对象,也许你现在的 E 不是 E(例如来自事件源),这对你来说很方便。否则,您只需将其强制转换为 E 即可将其删除。

从相等的角度来看,这无关紧要:测试给定对象的引用地址是否等于集合的内容,因此它属于哪个类并不重要。

【讨论】:

    【解决方案2】:

    从发布的第一条评论中得到答案:

    神话:

    一个流行的神话是它是愚蠢和邪恶的,但它是 由于向后兼容性,这是必要的。但是兼容性 论点无关紧要;无论您是否考虑,API 都是正确的 兼容性与否。

    真正的原因:

    Java 集合框架(以及 Google 集合库)从不限制其参数的类型 除非有必要防止收集得到 坏了。

    在这里阅读更多:Why does Set.contains() take an Object, not an E?

    【讨论】:

      【解决方案3】:

      remove()get() 一样,在给定 equal 元素(就.equals() 而言)时需要工作。在 Java 中,不同类的对象可能(在某些情况下是必需的)相等。因此,您不应该限制类型。

      【讨论】:

        【解决方案4】:

        这确实是个问题。如果有人调用remove(o) 并且o 的类型不是E,通常是一个试图删除错误内容的编程错误。类型检查未能保护我们免受错误的影响。

        虽然一个好的 IDE (IntelliJ) 可以检测到此类问题并警告我们,但 API 设计人员应该提供更精确的签名来利用编译器类型检查。 (IDE 在这里作弊 - 它知道 Set.remove() 的含义,因为它是标准 API。IDE 不会为自定义 API 提供相同的帮助)

        对于像contains() 这样的查询API,可以接受一个非E 参数并返回一个微不足道的假。所以我们可以两者兼得

        boolean contains(Object o);
        boolean contains2(E o);
        

        对于像remove() 这样的变异API,它是否应该接受非E 参数是有争议的。然而,鉴于擦除的现实,这场辩论将毫无意义——除了接受非 E 论点并对此保持沉默之外,别无选择。我们仍然可以有两种方法

        boolean remove(Object o);
        boolean remove2(E o);
        

        在大多数情况下,程序员可以调用contains2/remove2 以获得额外的类型安全性。

        【讨论】:

        • 你是说remove2/contains2 是TreeSet 方法吗?我在 api 中没有看到...
        猜你喜欢
        • 2011-09-04
        • 1970-01-01
        • 2012-09-03
        • 2012-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多