我对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
} }
答案 0 :(得分:4)
您可能知道如果a-b=c
,然后是b-a=-c
。
这里发生的事情非常相似。您似乎已经假设TreeSet
是这样调用compare
方法的:
comparator.compare(s1, s2)
(请注意,我出于说明目的使用了s1
和s2
。它们显然不在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
在内部使用TreeMap
。 put
调用在多个位置进行比较,通常与您放入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;
}
其他实现或方法可能会有不同的行为。