Pull to refresh

Comments 18

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

UFO just landed and posted this here

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

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

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

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

А почему не быстро? Возможность 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. Ни в коем случае к этому не призываю.

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

Sign up to leave a comment.

Articles