Интерфейс Java Comparator
У меня неправильное представление об интерфейсе Comparator, и его метод сравнения приведен в следующем коде, и мне интересно, зачем сравнивать метод return -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 ответа
Вы, наверное, знаете, что если a-b=c
затем b-a=-c
,
То, что здесь происходит, очень похоже. Вы, кажется, предположили, что TreeSet
это называет compare
метод как это:
comparator.compare(s1, s2)
(Обратите внимание, что я использовал s1
а также s2
в демонстрационных целях. Они явно не входят в сферу TreeSet
, s1
это тот же экземпляр, что и ваш 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
действительно звонит compare
как я описал.
РЕДАКТИРОВАТЬ:
Как сказал Хольгер в комментариях, вам не следует реализовывать Comparator
вычитая два целых числа. Вместо этого вы должны использовать Integer.compare
:
return Integer.compare(s1.num, s2.num);
На самом деле, нет необходимости реализовывать Comparator
вообще, вы можете пройти в Comparator.comparingInt(s -> s.num)
когда вы создаете TreeMap
:
TreeSet<Sorted> t1 = new TreeSet<>(Comparator.comparingInt(s -> s.num));
S1 и S2 в compare(Sorted s1, Sorted 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;
}
Другие реализации или методы могут иметь другое поведение.