Java比较器接口

时间:2019-02-16 10:30:02

标签: java java-8 comparator ocpjp

我对Comparator接口及其方法比较有误解 这是下面的代码,我想知道为什么compare方法返回-33我相信它应该返回33

import java.util.*;
public class Sorted implements Comparable<Sorted>, Comparator<Sorted> {
private int num;
private String text;

Sorted(int n, String t) {
    this.num = n;
    this.text = t;
}

public String toString() {
    return "" + num;
}

public int compareTo(Sorted s) {
    return text.compareTo(s.text);
}

public int compare(Sorted s1, Sorted s2) {
    System.out.println(s1.num-s2.num); // return -33
    return s1.num - s2.num;
}
public static void main(String[] args) {
    Sorted s1 = new Sorted(88, "a");
    Sorted s2 = new Sorted(55, "b");
    TreeSet<Sorted> t1 = new TreeSet<>();
    t1.add(s1); t1.add(s2);
    TreeSet<Sorted> t2 = new TreeSet<>(s1);
    t2.add(s1); t2.add(s2);
    System.out.println(t1 + " " + t2);
    System.out.println(s1.num-s2.num); // prints 33
} }

2 个答案:

答案 0 :(得分:4)

您可能知道如果a-b=c,然后是b-a=-c

这里发生的事情非常相似。您似乎已经假设TreeSet是这样调用compare方法的:

comparator.compare(s1, s2)

(请注意,我出于说明目的使用了s1s2。它们显然不在TreeSet的范围内。s1与您的{{1 }}和s1是与您的s2`相同的实例。)

但是它也可以这样调用s2

compare

不是吗?

如果以第二种方式调用它,那么将预期comparator.compare(s2, s1) 的结果。

编辑:

我查看了-33的源代码,发现它调用TreeSet.add并将您要添加的项目作为键。如果您深入研究TreeMap.put,将会发现:

TreeMap.put

这表明Comparator<? super K> cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); // <--- "key" is the key passed into this method // "t" is an element that is already in the map if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } 确实按照我的描述调用了TreeSet

编辑:

正如Holger在评论中所说,您不应通过减去两个整数来实现compare。相反,您应该使用Comparator

Integer.compare

实际上,根本不需要实现return Integer.compare(s1.num, s2.num); ,创建Comparator时可以传入Comparator.comparingInt(s -> s.num)

TreeMap

答案 1 :(得分:0)

compare(Sorted s1, Sorted s2)中的s1和s2是局部变量定义,请勿将它们与main()中的定义混淆。 TreeSet如何比较这两个元素还没有定义(从算法上仅由实现决定)。

compare(s1, s2) //yields 33
compare(s2, s1) //yields -33

TreeSet在内部使用TreeMapput调用在多个位置进行比较,通常与您放入TreeSet中的元素作为第一个元素进行比较。因此put(s2)将呼叫compare(s2, s1)。请参见下面的代码摘录:

public V put(K key, V value) {    
        Entry<K,V> t = root;    
        if (t == null) {
            compare(key, key); // type (and possibly null) check       
            root = new Entry<>(key, value, null);  
            size = 1;
            modCount++;    
            return null;    
        }    
        int cmp;    
        Entry<K,V> parent;    
        // split comparator and comparable paths    
        Comparator<? super K> cpr = comparator;    
        if (cpr != null) {    
            do {
                parent = t;    
                cmp = cpr.compare(key, t.key);    
                if (cmp < 0)   
                    t = t.left;    
                else if (cmp > 0)    
                    t = t.right;    
                else    
                    return t.setValue(value);    
            } while (t != null);    
        }    
        else {   
            if (key == null)    
                throw new NullPointerException();    
            @SuppressWarnings("unchecked")    
                Comparable<? super K> k = (Comparable<? super K>) key;   
            do {    
                parent = t;    
                cmp = k.compareTo(t.key);    
                if (cmp < 0)
                     t = t.left; 
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);    
            } while (t != null);    
        }    
        Entry<K,V> e = new Entry<>(key, value, parent);    
        if (cmp < 0)
                parent.left = e;    
        else    
            parent.right = e;    
        fixAfterInsertion(e);    
        size++;    
        modCount++;

        return null;
    }

其他实现或方法可能会有不同的行为。