【问题标题】:Java Treeset: "Cannot Resolve Constructor" for ComparatorJava Treeset:比较器的“无法解析构造函数”
【发布时间】:2016-12-06 05:42:39
【问题描述】:

由于某种原因,我的比较器没有被我的树集接受。请帮忙?

树集类:

public class PQTreeQueue<Integer> extends AbstractQueue<Integer>{

private TreeSet<Integer> _pqTree;

public PQTreeQueue() {
    noZeroComparator noZero = new noZeroComparator();
    _pqTree = new TreeSet<Integer>(noZero);
}

比较器类(在另一个文件中定义)

public class noZeroComparator implements Comparator<Integer> {

@Override
public int compare(Integer e0, Integer e1) {
    if (e0.compareTo(e1) >= 0) {
        return -1;
    } else {
        return 1;
    }
}

【问题讨论】:

  • 旁注:从不返回 0 的比较器不是有效的比较器。我不知道你想通过编写一个永远不会返回 0 的比较器来完成什么,但这会导致问题。
  • 我在回答中添加了一条注释,解释了为什么这不是一个有效的比较器。

标签: java constructor integer comparator treeset


【解决方案1】:

错误在这一行:

public class PQTreeQueue<Integer> extends AbstractQueue<Integer>

这(第一部分)是声明泛型类的语法。当你声明一个泛型类时,尖括号中的标识符是一个类型参数。就像Java中的声明一样

public class ArrayList<E> ...

除了你调用你的类型参数Integer而不是E。编译器对待 Integer 的方式与对待 E 的方式相同,尽管它变成了可以替换为任何实际类型的类型参数,并且名称 Integer 在 Java 中用于其他事物这一事实毫无意义.泛型类型与Integer 失去所有联系。在这个类中的其他任何地方,Integer 将引用类型变量,而不是实际的 java.lang.Integer

如果你删除&lt;Integer&gt;

public class PQTreeQueue extends AbstractQueue<Integer>

一切都应该工作。 (除了一个永远不会返回 0 的比较器将无法工作的事实。如果您调用 compare(x, x) 会发生什么?它会说 x &gt; x 吗?)

MORE 关于比较器要求的信息:数学规则是比较器强制执行总排序,这意味着函数必须遵守总排序规则(包括传递性)。根据the javadoc for compare(),“实施者必须确保sgn(compare(x, y)) == -sgn(compare(y, x)) 用于所有x 和y。”这尤其意味着sgn(compare(x,x)) == -sgn(compare(x,x)),并且只有compare(x,x) == 0 才有可能。这证明了从不返回 0 的比较器违反了规则,因为当两个参数都是 == 时,compare 必须返回 0。 [对于不是== 但根据.equals() 相等的参数,该规则较弱; javadoc 并没有说你不能这样做,但它确实说它可能会导致诸如排序集和映射之类的事情表现得很奇怪。见http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html.]

【讨论】:

    【解决方案2】:

    您定义了TreeSet,泛型参数为整数。您指定的 TreeSet 构造函数需要 comparator 其泛型参数是 Integer 的超类型或 Integer 本身。 该构造函数的定义:-

    TreeSet<E>(comparator<? super E>);
    

    所以最好不要将整数作为通用参数传递给TreeSet。创建您自己的类,如Integer,然后创建comparator,并将泛型参数作为您自己的comparator 的类,以及与自定义整数类的泛型参数相同的类。

    public class MyInterger {
        int value = 0;
    
          public int compareTo(MyInterger anotherInteger) {
                return compare(this.value, anotherInteger.value);
            }
    
          public static int compare(int x, int y) {
                return (x < y) ? -1 : ((x == y) ? 0 : 1);
            }
    }
    
    
    public class noZeroComparator implements Comparator<MyInterger> {
    
    @Override
    public int compare(MyInterger e0, MyInterger e1) {
        if (e0.compareTo(e1) >= 0) {
            return -1;
        } else {
            return 1;
        }
    }
    
    }
    
    
    
    public class PQTreeQueue<MyInterger> extends AbstractQueue<MyInterger>{
    
    private TreeSet<MyInterger> _pqTree;
    
    public PQTreeQueue() {
    
        noZeroComparator noZero = new noZeroComparator();
        _pqTree = new TreeSet<MyInterger>(noZero);
    }
    

    【讨论】:

    • 为什么会这样?用户想要自定义比较,他/她不想返回 0,只返回 -1 或 1。你的代码可以实现吗?
    • 1) 您误诊了问题。只要Integer 没有被意外地重新定义为问题中的方式,在预期Comparator&lt;? super Integer&gt; 的地方使用Comparator&lt;Integer&gt; 并没有错。 2) 您重复了 OP 的错误,即使用不正确的类型参数定义 PQTreeQueue
    • 我在答案中添加了信息,解释了为什么编写只返回 -1 或 1 的比较器是错误的。
    • 接受为 PQTreeQueue 提供错误的类型参数。我的回答并没有说他不应该使用比较器,我确实在我的回答中提到:“通用参数是整数的超类型或整数本身”。但是用户可能需要对他/她的 {PQTreeQueue} 进行一些自定义比较,他/她不想返回 0(可能是他/她不希望在树中包含相等的项目,如果比较器返回 0 则不会包含)在这种情况下,他/她不能依赖:标准整数比较方法应该做什么。
    • type参数是“接受”,但是不对。参数隐藏同名类型。在您的示例中,PQTreeQueue&lt;MyInterger&gt; 导致另一个 MyInterger 被隐藏,因此它不能在您的课程中使用。在您的类中使用MyInterger引用您在上面声明的类型。这显然不是本意。
    猜你喜欢
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 2018-06-30
    • 2015-05-05
    • 2017-02-28
    • 2016-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多