Транзитивный характер метода равенства - программирование

Транзитивный характер метода равенства

Контракт для метода equals(object) определяет следующие 4 свойства: Reflexive, Symmetric, Transitive и Consistent. Хотя я понимаю опасность не следовать Рефлексивному, Симметричному и Согласованному, и могу определенно согласиться с его добром следовать за транзитивным, мне было интересно, какой вред он принесет, если он нарушит транзитивную собственность?

В частности, какой из библиотеки Java (или различных сторонних библиотек) требует, чтобы зависимость от equals была транзитивной для правильной работы? По моему мнению, структура Collections будет работать, если будут хорошо реализованы другие 3 свойства.

4b9b3361

Ответ 1

Предположим, что три объекта a, b, c с

a == a, b == b, c == c (reflexive)
a == b, b == a
b == c, c == b
a != c, c != a

(Псевдокод, x == y означает x.equals(y)).

Теперь добавим объекты в набор:

Set s = new HashSet(); // Set implementation doesn't matter
s.add(b); // s = [b]
s.add(a); // s doesn't change, because a == b
s.add(c); // s doesn't change, because c == b

В отличие от этого, если бы мы добавляли их в другом порядке:

Set s = new HashSet();
s.add(a); // s = [a]
s.add(b); // s doesn't change, because b == a
s.add(c); // s = [a,c], because c != a

Это явно противоречит интуиции и не соответствует поведению, которое можно было бы ожидать от набора. Например, это означало бы, что объединение двух множеств (т.е. Состояние s после s.addAll(someOtherSet)) может зависеть от реализации (порядка элементов) некоторого OrtherSet.

Ответ 2

В настоящий момент я не знаю о Java API, который имеет проблемы с отсутствием транзитивности. (Я все еще размышляю для примера).

Но независимо от этого, транзитивность требуется для равенства, потому что это математическое алгебраическое определение отношения равенства. http://en.wikipedia.org/wiki/Equality_(mathematics)

Если транзитивности нет, метод не следует называть равным, потому что это вводит в заблуждение, принимая во внимание ожидаемое, когда вы слышите/читаете "равенство". Это противоречило бы принципу наименьшего удивления. http://en.wikipedia.org/wiki/Principle_of_least_astonishment

[EDIT]

Интересная вещь в этом состоит в том, что строго математическое выражение "равенство", определенное методом равных java, не является равенством, а скорее более общим отношением эквивалентности http://en.wikipedia.org/wiki/Equivalence_relation, поскольку разные объекты также могут быть "равны" в соответствии с java, что противоречит антисимметричному свойству, требуемому для истинного равенства.

Вывод:

.equals в Java - это отношение эквивалентности (которое по-прежнему требует транзитивности)

== в Java - отношение равенства (или идентичности)

Ответ 3

Рассмотрим объект a == b == c с a!= c (нетранзитивное равенство)

Первой проблемой будет контракт hashcode(), который требует, чтобы хэш-коды были равны, если объекты равны. И вы сможете добавить a и c в один и тот же набор - это может привести к тонким проблемам в неожиданных местах.

Ответ 4

Integer a = new Integer(1);
Integer b = new Integer(1);

a == 1 истинно, b == 1 истинно, но a == b неверно.