Bagaimana default .equals dan .hashCode akan berfungsi untuk kelas saya?

106

Katakanlah saya memiliki kelas saya sendiri

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

Ini memiliki beberapa atribut dan metode. Ini TIDAK mengimplementasikan sama, JANGAN mengimplementasikan kode hash.

Setelah kita memanggil sama dengan dan kode hash, apa implementasi defaultnya? Dari kelas Object? Dan apakah itu? Bagaimana cara kerja default sama? Bagaimana hashCode default akan bekerja dan apa yang akan dikembalikan? == hanya akan memeriksa apakah mereka merujuk ke objek yang sama, jadi itu mudah, tetapi bagaimana dengan metode equals () dan hashCode ()?

alexeypro
sumber

Jawaban:

94

Ya, implementasi default adalah Object (secara umum; jika Anda mewarisi dari kelas yang didefinisikan ulang sama dan / atau hashCode, Anda akan menggunakan implementasi itu sebagai gantinya).

Dari dokumentasi:

equals

Metode sama untuk kelas Objek mengimplementasikan kemungkinan relasi ekivalen yang paling diskriminatif pada objek; yaitu, untuk nilai referensi non-null x dan y, metode ini mengembalikan true jika dan hanya jika x dan y merujuk ke objek yang sama (x == y memiliki nilai true).

hashCode

Sebanyak praktis, metode hashCode yang didefinisikan oleh Objek kelas tidak mengembalikan bilangan bulat berbeda untuk objek berbeda. (Ini biasanya diterapkan dengan mengubah alamat internal objek menjadi bilangan bulat, tetapi teknik implementasi ini tidak diperlukan oleh bahasa pemrograman JavaTM.)

Etienne de Martel
sumber
50

Dari Objectsalah satu implementasi JVM:

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

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

Dalam kedua kasus itu hanya membandingkan alamat memori dari objek yang dimaksud.

Brad Mace
sumber
7
Dari versi JDK apa? Masuk v6u23 ea:public native int hashCode();
khachik
@kha - Anda benar, saya rasa saya melacak salah satu implementasi asli untuk melihat apa yang sebenarnya dilakukannya
Brad Mace
10

Ada implementasi default dari equals()dan hashCode()di Object. Jika Anda tidak menyediakan implementasi Anda sendiri, itu akan digunakan. Sebab equals(), ini berarti ==perbandingan: objek hanya akan sama jika mereka adalah objek yang persis sama. Sebab hashCode(), Javadoc punya penjelasan yang bagus.

Untuk informasi lebih lanjut, lihat Efektif Java, Bab 3 (pdf), item 8.

Jorn
sumber
1

Ya, dari Objectkelas karena kelas Anda memperluas Object secara implisit. equalshanya kembali this == obj. hashCodeimplementasi asli. Hanya tebakan - ini mengembalikan penunjuk ke objek.

khachik
sumber
2
Ini adalah penunjuk ke objek yang terletak di memori, tetapi ini bukan alamat memori dari objek tersebut. GC dapat memindahkan objek di dalam memori dan kode hash akan tetap sama.
Jeremy
@ Terima kasih. stackoverflow.com/questions/2427631/… mungkin menarik.
khachik
1

Jika Anda tidak menyediakan implementasi Anda sendiri, implementasi yang berasal dari Object akan digunakan. Tidak apa-apa, kecuali jika Anda berencana untuk memasukkan instance kelas Anda ke, yaitu HashSet (koleksi apa pun yang benar-benar menggunakan hashCode ()), atau sesuatu yang perlu memeriksa persamaan objek (yaitu metode berisi () HashSet). Jika tidak, itu akan bekerja secara tidak benar, jika itu yang Anda minta.

Sangat mudah untuk menyediakan implementasi Anda sendiri untuk metode ini berkat HashCodeBuilder dan EqualsBuilder dari Apache Commons Lang .

Paweł Dyda
sumber
(a) Mengapa Anda mengatakan 'implementasi default' kelas Objek 'sama' tidak akan berfungsi dengan benar dengan HashSet? Itu bertentangan dengan jawaban lain di halaman ini. (b) Terima kasih atas tautan Commons Lang.
Basil Bourque
1
@Basil: Saya rasa itu tidak bertentangan. Tentu saja implementasi default akan bekerja ... entah bagaimana, tapi tidak seperti yang Anda harapkan. Artinya, karena equals () menggunakan persamaan referensi, dua objek yang identik akan menjadi "berbeda" di mata implementasi default. Akibatnya, Anda mungkin memiliki dua contoh berbeda dari hal yang persis sama di Set Anda. Dan penggunaan Set yang agak khas adalah ketika Anda ingin menghilangkan duplikat ...
Paweł Dyda
@ PawełDyda: Perilaku default umumnya benar untuk tipe yang bisa berubah. Jika Foodan Baradalah referensi ke dua contoh berbeda dari tipe yang bisa berubah, dan ada metode (misalnya SomeMutatingMethod) yang Foo.SomeMutatingMethod()tidak mempengaruhi Barcara yang sama Foo, perbedaan itu harus cukup untuk menganggap objek sebagai tidak sama.
supercat
0

Karya pengembang IBM mengatakan:

Di bawah implementasi default ini, dua referensi sama hanya jika mereka merujuk ke objek yang sama persis. Demikian pula, implementasi default hashCode () yang disediakan oleh Object diturunkan dengan memetakan alamat memori objek ke nilai integer.

Namun, untuk memastikan detail implementasi yang tepat untuk versi Java vendor tertentu, sebaiknya lihat sebagai sumber (jika tersedia)

brabster
sumber