【问题标题】:Implement remove(Object o) in generic collection在泛型集合中实现 remove(Object o)
【发布时间】:2018-10-27 02:39:47
【问题描述】:

我正在编写一个基于二叉树模型的通用集合。

class MyTree <T extends Comparable<T>> extends AbstractCollection<T>{...}

底层Node&lt;T&gt; 类(以及其他)包含以下方法:

public Node<T> getLeft()  // left Node
public Node<T> getRight() // right Node
public T getValue()       // value stored in the Node

我想重写接口AbstractCollection&lt;T&gt; 的方法boolean contains(Object o) 以便能够检查Object 的类型不是T

对于 O(log n) 中的树遍历,泛型类型 T 必须实现 Comparable&lt;T&gt;,因此它具有方法 compareTo(T t)

我的代码:

@Override
public boolean contains(Object o){
    T t = (T) o; // produces warning (see below)
    BSNode<T> currentNode = this.root;
    while(currentNode != null){
        if(currentNode.getValue().equals(o)) {return true;}
        if(currentNode.getValue().compareTo(t) < 0)  {currentNode = currentNode.getRight();}
        if(currentNode.getValue().compareTo(t) > 0)  {currentNode = currentNode.getLeft();}
    }
    return false;
}

问题是我不能只将Object o 转换为T t 以使用compareTo(T t)。从技术上讲,Object 可以转换为T,但由于T 是泛型类型,我会收到以下警告:

warning: [unchecked] unchecked cast
          T t = (T) o;
                    ^
required: T
found:    Object
where T is a type-variable:
  T extends Comparable<T> declared in class MyTree

有人可以吗

  1. 确认我可以使用@SuppressWarnings("unchecked") 安全地忽略警告,
  2. 建议我如何安全地将Object 转换为T
  3. 请解释为什么以上两点都不能满足,这样我就可以停止思考如何完成这项工作?

非常感谢!

【问题讨论】:

  • 我不认为 Object 可以安全地转换为 T ,因为它可能不是 T 类型的对象,而是其他类型的对象。另外,如果您要定义 T 类型的集合,为什么要将 Object 传递给您的 contains()
  • 不相关: 不要调用equals 一次和compareTo 两次,只需调用compareTo 一次:int cmp = currentNode.getValue().compareTo(t); if (cmp == 0) { return true; } currentNode = (cmp &lt; 0 ? currentNode.getRight() : currentNode.getLeft()); --- 记住,equals 和 @ 987654349@ 可能是相对昂贵的电话。
  • @Andreas 我实际上计划在一切正常后执行此操作。这里没有展示equals(Object o)compareTo(T) 的不同参数类型,也不是为了展示该方法在不添加那一小层抽象的情况下应该如何工作。无论如何感谢您的建议。 :)
  • @LuisMuñoz 通常可以将Object o 转换为T t,因为Object.equals(Object o) 并不严格禁止不同类型的Object 相等。这就是AbstractCollection 实现contains(Object o) 的原因。另见here

标签: java generics collections comparable


【解决方案1】:

如果您想进行不受限制的搜索,则需要进行强制转换。您可以添加instanceof 来保护演员表免受异常影响,但这也不理想。

考虑如下更改T 的边界:

class MyTree <T extends Comparable<? super T>> extends AbstractCollection<T>{...}

由于您进行了覆盖,因此非常需要抑制警告。演员表应如下所示:

@SuppressWarnings("unchecked")
Comparable<? super T> t = (Comparable<? super T>) o;

请参阅java.util.TreeMapgetEntry 方法的来源,以了解如何在Java source 中完成它(他们这样做是出于同样的原因 - 需要覆盖带有签名的方法以采用Object) .

【讨论】:

  • 非常感谢您的回答,它促使我仔细研究 Java 中的泛型,现在一切正常,我什至明白为什么。实际上instanceof 不仅不理想,它不适用于泛型(由于类型擦除)。另外感谢java.util.TreeMap源代码的推荐,我什至不知道有OpenJDK之类的东西,也没有考虑过看看一些源代码的可能性。
  • @NiklasMertsch 您可以使用here 中描述的所谓“类型令牌”技巧对泛型执行instanceof。本质上,调用者需要为T 类型提供Class&lt;T&gt; 的实例,从而使您的代码可以访问isInstance(obj) 方法。这与这个问题无关,当类型擦除似乎妨碍您使用 Java 泛型时,请记住一件好事:-)
猜你喜欢
  • 2012-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多