Это цитата из книги Java Generics and Collections:
В принципе, все, что нужно знать клиенту, - это как соблюдать свою сторону контракта; если это не удается, все ставки сняты, и нет необходимости говорить, что именно сделает поставщик.
Итак, ответ: да, это может произойти, но только если вы не соблюдаете свою сторону контракта с Java. Здесь вы можете сказать, что Java нарушила симметричное свойство равенства, но если это произойдет, убедитесь, что вы первый разорвали контракт с некоторыми другими интерфейсами. Java уже задокументировала это поведение.
Как правило, вы должны читать документацию по интерфейсам Comparator
и Comparable
, чтобы правильно использовать их в отсортированных коллекциях.
На этот вопрос каким-то образом дан ответ в документе Эффективное третье издание Java, пункт 14 на страницах 66-68.
Это цитата из книги при определении контракта на реализацию интерфейса Comparable
(обратите внимание, что это только часть всего контракта):
• Настоятельно рекомендуется, но не обязательно, чтобы (x.compareTo (y) == 0) == (x.equals (y)). Вообще говоря, любой класс, реализующий интерфейс Comparable и нарушающий это условие, должен четко указывать на этот факт. Рекомендуемый язык - «Примечание: этот класс имеет естественный порядок, несовместимый с equals».
В нем говорится: Настоятельно рекомендуется, но не обязательно, это означает, что вам разрешено иметь классы, для которых x.compareTo(y)==0
не означает _5 _. (Но если это реализовано таким образом, вы не можете использовать их в качестве элемент в отсортированных коллекциях, это как раз тот случай с BigDecimal
)
Стоит упомянуть параграф книги, описывающий эту часть контракта интерфейса Comparable
:
Это сильное предложение, а не истинное требование, оно просто утверждает, что проверка равенства, наложенная методом compareTo, обычно должна возвращать те же результаты, что и метод equals. Если это положение соблюдается, порядок, установленный методом compareTo, считается совместимым с equals. Если он нарушен, порядок считается несовместимым с равным. Класс, чей метод compareTo устанавливает порядок, несовместимый с equals, по-прежнему будет работать, но отсортированные коллекции, содержащие элементы класса, могут не подчиняться общему контракту соответствующих интерфейсов сбора (Collection, Set или Map). Это связано с тем, что общие контракты для этих интерфейсов определены в терминах метода equals, но в отсортированных коллекциях вместо equals используется проверка на равенство, налагаемая compareTo. Если это произойдет, это не катастрофа, но об этом нужно знать.
На самом деле у нас есть несколько классов в самой Java, которые не следовали этой рекомендации. BigDecimal
- один из них, и об этом упоминается в книге.
Например, рассмотрим класс BigDecimal, чей метод compareTo несовместим с equals. Если вы создаете пустой экземпляр HashSet, а затем добавляете новые BigDecimal (1.0) и новые BigDecimal (1.00), набор будет содержать два элемента, потому что два экземпляра BigDecimal, добавленные в набор, не равны при сравнении с использованием метода equals. Однако если вы выполните ту же процедуру с использованием TreeSet вместо HashSet, набор будет содержать только один элемент, поскольку два экземпляра BigDecimal равны при сравнении с использованием метода compareTo. (Подробности см. В документации BigDecimal.)
Однако такое поведение задокументировано в BigDecimal
Документация. Давайте посмотрим на эту часть документации:
Примечание: следует проявлять осторожность, если объекты BigDecimal используются в качестве ключей в SortedMap или элементы в SortedSet, поскольку естественный порядок BigDecimal несовместим с equals. См. Comparable, SortedMap или SortedSet для получения дополнительной информации.
Поэтому, хотя вы можете написать код, подобный приведенному ниже, вам не следует этого делать, потому что класс BigDecimal
запрещает такое использование:
Set<BigDecimal> treeSet = new TreeSet<>();
Set<BigDecimal> hashSet = new HashSet<>();
treeSet.add(new BigDecimal("1.00"));
treeSet.add(new BigDecimal("2.0"));
hashSet.add(new BigDecimal("1.00"));
hashSet.add(new BigDecimal("2.00"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true
Обратите внимание, что Comparable
будет использоваться как естественный порядок элементов, когда вы не передадите какой-либо компаратор в TreeSet
или TreeMap
, то же самое может произойти, когда вы передадите Comparator
в этот конструктор класса. Это упоминается в Comparator
документации:
Упорядочение, наложенное компаратором c на набор элементов S, называется согласованным с равенством тогда и только тогда, когда c.compare (e1, e2) == 0 имеет то же логическое значение, что и e1.equals (e2) для каждого e1 и e2 в S.
Следует проявлять осторожность при использовании компаратора, способного устанавливать порядок, несовместимый с равенством, для упорядочивания отсортированного набора (или отсортированной карты). Предположим, что отсортированный набор (или отсортированная карта) с явным компаратором c используется с элементами (или ключами), взятыми из набора S. Если порядок, наложенный c на S, несовместим с equals, отсортированный набор (или отсортированная карта) будет вести себя странно. В частности, отсортированный набор (или отсортированная карта) будет нарушать общий договор для набора (или карты), который определяется в терминах равенства.
Итак, учитывая этот документ Comparator
, следующий пример, приведенный @Aniket Sahrawat, не поддерживается для работы:
TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HashSet<String> hashSet = new HashSet<>();
treeSet.addAll(List.of("A", "b"));
hashSet.addAll(List.of("A", "B"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true
Вкратце ответ: да, это может произойти, но только если вы нарушите задокументированный контракт одного из вышеупомянутых интерфейсов (SortedSet
, Comparable
, Comparator
).
person
Tashkhisi
schedule
22.08.2020