Яким чином .equals та .hashCode працюватимуть для моїх занять?


106

Скажіть, у мене є власний клас

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

Він має деякі атрибути та методи. НЕ реалізує рівних, НЕ реалізує хеш-код.

Як тільки ми називаємо рівняння та хеш-код, що таке реалізація за замовчуванням? З класу «Об’єкти»? А що вони? Як будуть працювати рівні за замовчуванням? Як буде працювати хеш-код за замовчуванням і що повернеться? == просто перевірять, чи посилаються вони на один і той же об'єкт, тому це легко, але як щодо методів рівних () та hashCode ()?

Відповіді:


94

Так, реалізація за замовчуванням - це Object (загалом кажучи; якщо ви успадковуєте клас, який переосмислюється рівним та / або hashCode, то замість цього ви будете використовувати цю реалізацію).

З документації:

equals

Метод рівнянь для класу Object реалізує найбільш дискримінаційне можливе відношення еквівалентності на об'єктах; тобто для будь-яких ненульових опорних значень x і y цей метод повертає істинні, якщо і лише тоді, коли x і y посилаються на один і той же об'єкт (x == y має значення true).

hashCode

Наскільки це практично практично, метод хеш-коду, визначений класом Object, повертає окремі цілі числа для різних об'єктів. (Зазвичай це реалізується шляхом перетворення внутрішньої адреси об'єкта в ціле число, але ця техніка реалізації не потрібна мові програмування JavaTM.)


50

З Objectоднієї з реалізацій JVM:

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

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

В обох випадках це лише порівняння адрес пам'яті об'єктів, про які йдеться.


7
З якої версії JDK це? В v6u23 ea:public native int hashCode();
хачик

@kha - Ти маєш рацію, я думаю, що я відшукав одну з власних реалізацій, щоб побачити, що це насправді
Бред Мейс

10

Є реалізовані за замовчуванням реалізації equals()та hashCode()в Object. Якщо ви не надасте власну реалізацію, вони будуть використані. Бо equals()це означає ==порівняння: об’єкти будуть рівними лише у тому випадку, якщо вони точно однакові. Для hashCode(), то Javadoc має гарне пояснення.

Для отримання додаткової інформації див. Ефективна Java, глава 3 (pdf), пункт 8.


1

Так, з Objectкласу, оскільки ваш клас неявно поширює об’єкт. equalsпросто повертається this == obj. hashCodeреалізація є рідною. Лише здогадка - вона повертає вказівник на об’єкт.


2
Це вказівник на об'єкт, що знаходиться в пам'яті, але це не адреса пам'яті об'єкта. GC може переміщувати об’єкт навколо в пам'яті, і хеш-код залишатиметься колишнім.
Джеремі

@Jeremy Дякую stackoverflow.com/questions/2427631/… може бути цікавим.
хачик

1

Якщо ви не надаєте власну реалізацію, буде використано одне похідне від Object. Це нормально, якщо ви не плануєте розміщувати екземпляри свого класу в, наприклад, HashSet (будь-яка колекція, яка фактично використовує hashCode ()), або щось, для чого потрібно перевірити рівність об'єкта (тобто метод HashSet's містить ()). В іншому випадку він буде працювати неправильно, якщо це те, про що ви просите.

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


(а) Чому ви вважаєте, що "за замовчуванням реалізація" рівних "класу" Об'єкт "не працюватиме правильно з HashSet? Це суперечить іншим відповідям на цій сторінці. (b) Дякуємо за посилання Commons Lang.
Василь Бурк

1
@Basil: Я не думаю, що це суперечить. Звичайно реалізація за замовчуванням спрацювала б… якось, але не так, як ви очікуєте. Тобто, оскільки рівняння () використовує опорну рівність, два ідентичні об'єкти будуть "різними" в очах реалізації за замовчуванням. Як результат, у вашому наборі може виникнути два різних екземпляри абсолютно тієї самої речі. І досить типове використання Sets - це коли ви хочете усунути дублікати ...
Paweł Dyda

@ PawełDyda: поведінка за замовчуванням, як правило, правильна для змінних типів. Якщо Fooі Barє посилання на два різних екземпляри мутаційного типу, і існує такий метод (наприклад SomeMutatingMethod), щоFoo.SomeMutatingMethod() не впливає так Barсамо, як це відбувається Foo, цієї різниці має бути достатньо, щоб вважати об'єкти нерівними.
supercat

0

IBM- розробник каже:

У цій реалізації за замовчуванням дві посилання рівні, лише якщо вони посилаються на точно той самий об'єкт. Аналогічно, реалізація за замовчуванням hashCode (), що надається Object, отримується шляхом зіставлення адреси пам'яті об'єкта на ціле число.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.