Как стать автором
Обновить

Комментарии 18

Об ООП: не существует способа расширить класс, порождающий экземпляры, и добавить к нему новый аспект, сохранив при этом соглашения для метода equals. (с)

НЛО прилетело и опубликовало эту надпись здесь

Спасибо вам за вопрос. Метод реализует отношение эквивалентности. Соглашения включают рефлексивность, симметричность, транзитивность, консистентность и отличие от нуля. Проблема: при добавлении аспекта нарушается хотя бы одно из этих соглашений.

Многие классы, включая классы коллекций, полагаются на то, что объекты, передаваемые им, подчиняются соглашениям (контракту) для этого метода.

…если только в методе базового класса нет сравнения типов. Но такое сравнение будет работать небыстро.

О, приветствую, ждал вас в этом треде, вы совершенно правы, удачное замечание.

А почему не быстро? Возможность downcast вроде бы означает хранение типа в рантайме… Так сложно два указателя на тип сравнить?

Вроде и не сложно, но какие-то заморочки были, какие — не помню.

Присаживайтесь поудобнее, начнём. Вопрос в том, используется == или вызов метода equals. В последнем случае накладные расходы выше. Пример более быстрого сравнения, начиная с Java 5 - сравнение членов перечисления Enum.

Во-первых, hashСode, и имена в Java case sensitive. Это все, что нужно знать о качестве данной статьи. Ну и во-вторых, в этом месте практически ничего не менялось с выпуска версии 1.0, т.е. с января 1996 года. То есть, статья опоздала примерно лет на 25.

После версии 1.0 добавились, например, Arrays.hashCode(), Objects.hashCode(), Objects.hash() .

Ну, вообще-то как раз про них тут и ни слова.
Реализация .hashcode() по умолчанию?
Насколько я понял, точно так никто в этом и не разобрался.


Ага, ага. Только ответ ищется за две минуты, и содержит ссылку на код. А для тех кто читал Хабр, прежде чем начал писать, несложно и на хабре найти парочку статей, гораздо глубже этой.

Легко проследить, что такое определение не противоречит математической идеологии.

Легко заметить, что противоречит:

симметричным (для любых xy выполняется: если x = y, то y = x)

String a = "Test";
String b = null;
a.equals(b)	// false
b.equals(a)	// NPE

Строгую математическую семантику соблюдает Objects.equals(). И именно его нужно было использовать с самого начала для оператора "==". Однако создателям Java казалось очень важным каждый обращать внимание пользователей на то, как они реализовали equals(), и что сравнивать строки при помощи "==" в их языке хоть и можно, но будет неправильно. Даром что ссылочное сравнение используется в одном случае из ста. Но уж теперь ничего не поделаешь.

Иногда ещё и equals переопределяют так, что при сравнении типов сравнивают их неправильно через instanceof, а не через getClass. И тогда вполне может быть, что

a.equals(b) // true
b.equals(a) // false

Сравнивая через getClass, вы подразумеваете экземпляр строго одного типа (ведь через instanceof можете более гибко сравнить подтипы)?

Да, именно это имею в виду.

Если один класс наследуется от другого, то при реализации equals через instanceof это правило симметрии нарушается.

Пару замечаний чисто про математику:

Возможно есть такое элемент из X, и даже возможно не один, что он не сопоставлен никакому элементу из Y

тогда эта функция не определена на всём X. Другое дело что не всем Y могут найтись из X в hashCode, а это запросто. Тогда это не сюрьекция.

И второе: считаю уместным отметить, что любому отображению соответствует отношение эквивалентности по правилу: два элемента эквивалентны если и только если их образы отображений совпадают. Это даёт наглядный пример, как можно устроить equals через hashCode. Ни в коем случае к этому не призываю.

Верно и обратное: если есть отношение эквивалентности, то ему соответствует отображение исходного множества в его фактор-множество по этой эквивалентности. Но это так ;-)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории