Как по умолчанию .equals и .hashCode будут работать для моих классов?

106

Скажем, у меня есть собственный класс

public class MyObj { /* ... */ }

У него есть некоторые атрибуты и методы. Он НЕ реализует равенства, НЕ реализует hashCode.

Каковы реализации по умолчанию после вызова equals и hashCode? Из класса объекта? А какие они? Как будет работать равенство по умолчанию? Как будет работать хэш-код по умолчанию и что вернет? == просто проверит, ссылаются ли они на один и тот же объект, так что это просто, но как насчет методов equals () и hashCode ()?

Алексей
источник

Ответы:

94

Да, реализация по умолчанию - это Object (вообще говоря, если вы наследуете от класса, который переопределил equals и / или hashCode, то вместо этого вы будете использовать эту реализацию).

Из документации:

equals

Метод equals для класса Object реализует наиболее различающее возможное отношение эквивалентности для объектов; то есть для любых ненулевых ссылочных значений x и y этот метод возвращает true тогда и только тогда, когда x и y относятся к одному и тому же объекту (x == y имеет значение true).

hashCode

Насколько это разумно практично, метод hashCode, определенный классом Object, действительно возвращает отдельные целые числа для отдельных объектов. (Обычно это реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется для языка программирования JavaTM.)

Этьен де Мартель
источник
50

Из Objectодной из реализаций JVM:

public boolean equals(Object object) {
    return this == object;
}

public int hashCode() {
    return VMMemoryManager.getIdentityHashCode(this);
}

В обоих случаях это просто сравнение адресов памяти рассматриваемых объектов.

Брэд Мейс
источник
7
Какая версия JDK это от? In v6u23 ea:public native int hashCode();
хачик
@kha - Вы правы, я думаю, что нашел одну из нативных реализаций, чтобы посмотреть, что она на самом деле сделала
Брэд Мейс
10

Существуют реализации по умолчанию equals()и hashCode()в Object. Если вы не предоставите свою собственную реализацию, они будут использоваться. Ибо equals()это означает ==сравнение: объекты будут равны, только если они являются одним и тем же объектом. Ибо hashCode()у Javadoc есть хорошее объяснение.

Для получения дополнительной информации см. Эффективная Java, Глава 3 (pdf), пункт 8.

Йорн
источник
1

Да, из Objectкласса, поскольку ваш класс неявно расширяет Object. equalsпросто возвращается this == obj. hashCodeреализация родная. Угадайте - возвращает указатель на объект.

хачик
источник
2
Это указатель на объект, расположенный в памяти, но не адрес объекта в памяти. GC может перемещать объект в памяти, и хэш-код останется прежним.
Джереми
@ Джереми Спасибо. stackoverflow.com/questions/2427631/… может быть интересным.
хачик
1

Если вы не предоставите свою собственную реализацию, будет использоваться реализация, производная от Object. Это нормально, если вы не планируете помещать экземпляры класса, например, в HashSet (любую коллекцию, которая фактически использует hashCode ()) или что-то, что необходимо для проверки равенства объектов (например, метод HashSet contains ()). В противном случае он будет работать неправильно, если вы об этом просите.

Довольно легко предоставить собственную реализацию этих методов благодаря HashCodeBuilder и EqualsBuilder от Apache Commons Lang .

Павел Дыда
источник
(a) Почему вы говорите, что реализация equals класса Object по умолчанию не будет правильно работать с HashSet? Это противоречит другим ответам на этой странице. (б) Спасибо за ссылки Commons Lang.
Basil Bourque
1
@Basil: Не думаю, что это противоречит. Конечно, реализация по умолчанию будет работать ... как-то, но не так, как вы ожидаете. То есть, поскольку equals () использует ссылочное равенство, два идентичных объекта в противном случае будут «разными» с точки зрения реализации по умолчанию. В результате у вас может оказаться два разных экземпляра одного и того же объекта в вашем Set. И довольно типичное использование Наборов - это когда вы хотите удалить дубликаты ...
Павел Дида
@ PawełDyda: поведение по умолчанию обычно правильно для изменяемых типов. Если Fooи Barявляются ссылками на два разных экземпляра изменяемого типа, и существует метод (например SomeMutatingMethod), который Foo.SomeMutatingMethod()не влияет так Barже, как он Foo, это различие должно быть достаточным, чтобы рассматривать объекты как неравные.
supercat
0

IBM developerworks говорит:

В этой реализации по умолчанию две ссылки равны, только если они относятся к одному и тому же объекту. Точно так же реализация hashCode () по умолчанию, предоставляемая Object, получается путем сопоставления адреса памяти объекта с целочисленным значением.

Однако, чтобы быть уверенным в точных деталях реализации версии Java конкретного поставщика, вероятно, лучше всего посмотреть в качестве источника (если он доступен)

хвастун
источник