Mengapa saya perlu mengganti metode equals dan hashCode di Java?

383

Baru-baru ini saya membaca Dokumen Pekerjaan Pengembang ini .

Dokumen ini adalah tentang mendefinisikan hashCode()dan equals()secara efektif dan benar, namun saya tidak dapat mengetahui mengapa kita perlu mengganti kedua metode ini.

Bagaimana saya bisa mengambil keputusan untuk menerapkan metode ini secara efisien?

Shashi
sumber
4
Ada dua artikel hebat di programming.guide menjelaskan persis ini: Kapan saya harus menimpa sama? dan Mengapa Anda harus selalu mengganti kode hash saat menimpa sama dengan . (Peringatan, jawaban yang diterima sebenarnya salah.)
aioobe
Case Override hanya sama dengan: dua objek yang sama akan memiliki kode hash yang berbeda = objek yang sama masuk dalam ember berbeda (duplikasi). Case Override only hashcode: dua objek yang sama akan memiliki kode hash yang sama = objek yang sama masuk dalam ember yang sama (duplikasi).
VdeX

Jawaban:

524

Joshua Bloch berkata di Java Efektif

Anda harus mengganti kode hash () di setiap kelas yang menimpa sama dengan (). Kegagalan untuk melakukannya akan mengakibatkan pelanggaran terhadap kontrak umum untuk Object.hashCode (), yang akan mencegah kelas Anda berfungsi dengan baik bersama dengan semua koleksi berbasis hash, termasuk HashMap, HashSet, dan Hashtable.

Mari kita coba memahaminya dengan contoh apa yang akan terjadi jika kita menimpanya equals()tanpa mengesampingkan hashCode()dan berusaha menggunakan a Map.

Katakanlah kita memiliki kelas seperti ini dan bahwa dua objek MyClasssama jika mereka importantFieldsama (dengan hashCode()dan equals()dihasilkan oleh gerhana)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

Timpa saja equals

Jika hanya equalsdiganti, maka ketika Anda menelepon myMap.put(first,someValue)dulu akan hash ke beberapa ember dan ketika Anda menyebutnya myMap.put(second,someOtherValue)akan hash ke beberapa ember lainnya (karena mereka memiliki yang berbeda hashCode). Jadi, meskipun mereka sama, karena mereka tidak hash ke ember yang sama, peta tidak bisa menyadarinya dan mereka berdua tetap di peta.


Meskipun tidak perlu untuk menimpa equals()jika kita menimpa hashCode(), mari kita lihat apa yang akan terjadi dalam kasus khusus ini di mana kita tahu bahwa dua objek MyClasssama jika mereka importantFieldsama tetapi kita tidak menimpa equals().

Timpa saja hashCode

Bayangkan Anda memiliki ini

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

Jika Anda hanya menimpanya hashCodemaka saat Anda memanggilnya myMap.put(first,someValue)butuh lebih dulu, hitung hashCodedan simpan dalam ember yang diberikan. Kemudian ketika Anda memanggilnya myMap.put(second,someOtherValue)harus ganti dulu dengan yang kedua sesuai Dokumentasi Peta karena keduanya sama (sesuai dengan kebutuhan bisnis).

Tetapi masalahnya adalah bahwa sama tidak didefinisikan ulang, jadi ketika peta hash seconddan beralih melalui ember mencari jika ada objek ksedemikian rupa sehingga second.equals(k)benar tidak akan menemukan apa pun yang second.equals(first)akan terjadi false.

Semoga itu jelas

Lombo
sumber
5
dapatkah Anda menjelaskan sedikit lebih banyak, dalam kasus kedua, mengapa objek kedua harus dimasukkan ke dalam ember lain?
Hussain Akhtar Wahid 'Ghouri'
57
Saya tidak suka jawaban ini karena itu menunjukkan bahwa Anda tidak dapat menimpa kode hash () tanpa mengabaikan equals (), yang sama sekali tidak benar. Anda mengatakan kode contoh Anda (bagian "ganti kode hash saja") tidak akan berfungsi karena Anda mendefinisikan dua objek Anda sama, tetapi - maaf - definisi ini hanya ada di kepala Anda. Dalam contoh pertama Anda, Anda memiliki dua objek tidak sama dengan kode hash yang sama, dan itu sah menurut hukum. Jadi alasan Anda perlu mengganti equals () bukan karena Anda telah mengganti kode hash (), tetapi karena Anda ingin memindahkan definisi "equals" dari kepala Anda ke kode.
user2543253
11
if you think you need to override one, then you need to override both of themsalah. Anda perlu mengganti hashCodejika kelas Anda menimpa equalstetapi sebaliknya tidak benar.
akhil_mittal
4
Saya pikir itu benar-benar ok untuk menimpa hanya kode hash () tanpa mengabaikan equals () juga. Ini juga yang ditulis dalam Java Efektif : books.google.fr/...
Johnny
2
@PhantomReference, perhatikan bahwa hanya mengesampingkan equalsakan melanggar kontrak yang tercantum dalam javadoc Object: "Jika dua objek sama dengan equals(Object)metode, maka memanggil hashCodemetode pada masing-masing dua objek harus menghasilkan hasil bilangan bulat yang sama." Tentu, tidak semua bagian dari semua kontrak dijalankan dalam semua kode, tapi tetap saja, secara resmi itu merupakan pelanggaran dan saya menganggapnya sebagai bug yang menunggu untuk terjadi.
aioobe
264

Koleksi seperti HashMapdan HashSetmenggunakan nilai kode hash suatu objek untuk menentukan bagaimana ia harus disimpan di dalam koleksi, dan kode hash digunakan lagi untuk menemukan objek dalam koleksi.

Pengambilan hashing adalah proses dua langkah:

  1. Temukan ember yang tepat (menggunakan hashCode())
  2. Cari ember untuk elemen yang tepat (menggunakan equals())

Berikut adalah contoh kecil tentang mengapa kita harus mengesampingkan equals()dan hashcode().

Pertimbangkan Employeekelas yang memiliki dua bidang: usia dan nama.

public class Employee {

    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

Sekarang buat kelas, masukkan Employeeobjek ke dalam HashSetdan uji apakah objek itu ada atau tidak.

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

Ini akan mencetak yang berikut:

false
employee.hashCode():  321755204  employee2.hashCode():375890482

Sekarang hashcode()metode uncomment , jalankan hal yang sama dan hasilnya adalah:

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

Sekarang dapatkah Anda melihat mengapa jika dua objek dianggap sama, kode hash mereka juga harus sama? Jika tidak, Anda tidak akan pernah dapat menemukan objek karena metode kode hash default di kelas Object hampir selalu muncul dengan nomor unik untuk setiap objek, bahkan jika equals()metode tersebut ditimpa sedemikian rupa sehingga dua atau lebih objek dianggap sama . Tidak masalah seberapa sama objeknya jika kode hash mereka tidak mencerminkan hal itu. Jadi sekali lagi: Jika dua objek sama, kode hash mereka harus sama juga.

rajeev pani ..
sumber
4
Contoh sempurna. Jelas menunjukkan perbedaannya!
coderpc
3
nice menjelaskan @rajeev
VdeX
2
@VikasVerma sama dengan objek akan memiliki kode hash yang sama tidak berarti objek yang tidak sama akan memiliki kode hash yang tidak sama. Bagaimana jika objek sebenarnya berbeda, tetapi kode hashnya sama?
Ravi
1
menjelaskan dengan sangat baik :)
Rahul
4
jauh lebih baik daripada jawaban yang diterima! Terima kasih
kayu apung
50

Anda harus mengganti kode hash () di setiap kelas yang menimpa sama dengan (). Kegagalan untuk melakukannya akan mengakibatkan pelanggaran terhadap kontrak umum untuk Object.hashCode (), yang akan mencegah kelas Anda berfungsi dengan baik bersama dengan semua koleksi berbasis hash, termasuk HashMap, HashSet, dan Hashtable.


   dari Java Efektif , oleh Joshua Bloch

Dengan mendefinisikan equals()dan hashCode()secara konsisten, Anda dapat meningkatkan kegunaan kelas Anda sebagai kunci dalam koleksi berbasis hash. Seperti dijelaskan API doc untuk hashCode: "Metode ini didukung untuk kepentingan hashtable seperti yang disediakan oleh java.util.Hashtable."

Jawaban terbaik untuk pertanyaan Anda tentang bagaimana menerapkan metode ini secara efisien adalah menyarankan Anda untuk membaca Bab 3 Java Efektif .

JuanZe
sumber
4
Ini jawaban yang benar. Untuk menjadi akibat wajar, tentu saja, bahwa jika Anda tidak pernah menggunakan kelas dalam koleksi berbasis hash, maka tidak masalah bahwa Anda belum diimplementasikan hashCode().
langsing
1
Dalam kasus yang lebih kompleks, Anda tidak pernah tahu apakah koleksi yang Anda gunakan menggunakan hash, jadi menjauhlah dari "tidak masalah bahwa Anda belum menerapkan kode hash ()"
Victor Sergienko
1
Bisakah saya mengganti kode hash () tanpa mengabaikan sama dengan ()?
Johnny
@StasS, ya, bertentangan dengan apa yang dikatakan jawaban yang diterima. Lihat penjelasan di bagian kedua artikel ini: Mengapa Anda harus selalu menimpa
kode
22

Sederhananya, metode equals di Object memeriksa persamaan referensi, di mana dua instance kelas Anda masih bisa secara semantik sama ketika propertinya sama. Ini misalnya penting ketika meletakkan objek Anda ke dalam wadah yang menggunakan kode equal dan hash, seperti HashMap dan Set . Katakanlah kita memiliki kelas seperti:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

Kami membuat dua instance dengan id yang sama :

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

Tanpa mengabaikan sama dengan yang kita dapatkan:

  • a.equals (b) salah karena mereka adalah dua contoh yang berbeda
  • a.equals (a) benar karena ini adalah contoh yang sama
  • b.equals (b) benar karena ini adalah contoh yang sama

Benar? Yah mungkin, jika ini yang Anda inginkan. Tetapi katakanlah kita ingin objek dengan id yang sama menjadi objek yang sama, terlepas dari apakah itu dua contoh yang berbeda. Kami menimpa sama dengan (dan kode hash):

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

Sedangkan untuk menerapkan equals dan hashcode saya dapat merekomendasikan menggunakan metode pembantu Guava

crunchdog
sumber
20

Identitas bukanlah kesetaraan.

  • sama dengan ==identitas tes operator .
  • equals(Object obj) metode membandingkan uji kesetaraan (yaitu kita perlu memberi tahu persamaan dengan mengesampingkan metode)

Mengapa saya perlu mengganti metode equals dan hashCode di Java?

Pertama kita harus memahami penggunaan metode equals.

Untuk perbedaan identitas antara dua objek, kita perlu mengganti metode equals.

Sebagai contoh:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

Sekarang metode hashCode dapat dimengerti dengan mudah.

hashCode menghasilkan integer untuk menyimpan objek dalam struktur data seperti HashMap , HashSet .

Asumsikan kita memiliki metode override sama Customerdengan di atas

customer1.equals(customer2);  // returns true by our own logic

Saat bekerja dengan struktur data ketika kita menyimpan objek dalam ember (ember adalah nama yang bagus untuk folder). Jika kami menggunakan teknik hash bawaan, untuk di atas dua pelanggan itu menghasilkan dua kode hash yang berbeda. Jadi kita menyimpan objek identik yang sama di dua tempat berbeda. Untuk menghindari masalah seperti ini, kita harus mengganti metode kode hash juga berdasarkan prinsip-prinsip berikut.

  • contoh yang tidak sama mungkin memiliki kode hash yang sama.
  • instance yang sama harus mengembalikan kode hash yang sama.
Premraj
sumber
3
Ini yang saya cari sejak 1 jam terakhir. Awesome mate (y)
Adnan
13

Baiklah, saya jelaskan konsepnya dengan kata-kata yang sangat sederhana.

Pertama dari perspektif yang lebih luas, kami memiliki koleksi, dan hashmap adalah salah satu struktur data dalam koleksi.

Untuk memahami mengapa kita harus mengganti metode equals dan hashcode, jika perlu terlebih dahulu memahami apa itu hashmap dan apa yang dilakukan.

Hashmap adalah struktur data yang menyimpan pasangan nilai kunci data dalam mode array. Katakanlah [], di mana setiap elemen dalam 'a' adalah pasangan nilai kunci.

Juga setiap indeks dalam array di atas dapat ditautkan daftar sehingga memiliki lebih dari satu nilai pada satu indeks.

Sekarang mengapa hashmap digunakan? Jika kita harus mencari di antara array besar kemudian mencari masing-masing jika tidak akan efisien, jadi apa teknik hash memberitahu kita yang memungkinkan pra proses array dengan beberapa logika dan kelompok elemen-elemen berdasarkan pada logika itu yaitu Hashing

misalnya: kami memiliki larik 1,2,3,4,5,6,7,8,9,10,11 dan kami menerapkan fungsi hash mod 10 sehingga 1,11 akan dikelompokkan bersama. Jadi jika kita harus mencari 11 dalam array sebelumnya maka kita harus mengulangi array lengkap tetapi ketika kita mengelompokkannya kita membatasi ruang lingkup iterasi kita sehingga meningkatkan kecepatan. Datastruktur yang digunakan untuk menyimpan semua informasi di atas dapat dianggap sebagai array 2d untuk kesederhanaan

Sekarang selain dari hashmap di atas juga memberi tahu bahwa itu tidak akan menambahkan Duplikat di dalamnya. Dan ini adalah alasan utama mengapa kita harus mengganti kode equals dan hash

Jadi ketika itu mengatakan yang menjelaskan kerja internal hashmap, kita perlu menemukan metode apa yang hashmap miliki dan bagaimana cara mengikuti aturan di atas yang saya jelaskan di atas

sehingga hashmap memiliki metode yang disebut sebagai put (K, V), dan menurut hashmap harus mengikuti aturan di atas untuk mendistribusikan array secara efisien dan tidak menambahkan duplikat apa pun.

jadi apa yang dilakukan adalah bahwa ia pertama-tama akan menghasilkan kode hash untuk kunci yang diberikan untuk memutuskan indeks mana nilai harus masuk. jika tidak ada yang hadir pada indeks itu maka nilai baru akan ditambahkan di sana, jika ada sesuatu yang sudah ada di sana maka nilai baru harus ditambahkan setelah akhir daftar tertaut pada indeks itu. tapi ingat tidak ada duplikat yang harus ditambahkan sesuai perilaku hashmap yang diinginkan. jadi katakanlah Anda memiliki dua objek Integer aa = 11, bb = 11. karena setiap objek berasal dari kelas objek, implementasi standar untuk membandingkan dua objek adalah membandingkan objek dan bukan nilai di dalam objek. Jadi dalam kasus di atas baik secara semantik sama akan gagal tes kesetaraan, dan kemungkinan bahwa dua objek yang memiliki kode hash dan nilai yang sama yang sama akan ada sehingga membuat duplikat. Jika kita menimpanya maka kita dapat menghindari menambahkan duplikat. Anda juga bisa merujukDetail bekerja

import java.util.HashMap;


public class Employee {

String name;
String mobile;
public Employee(String name,String mobile) {
    this.name=name;
    this.mobile=mobile;
}

@Override
public int hashCode() {
    System.out.println("calling hascode method of Employee");
    String str=this.name;
    Integer sum=0;
    for(int i=0;i<str.length();i++){
        sum=sum+str.charAt(i);
    }
    return sum;

}
@Override
public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    System.out.println("calling equals method of Employee");
    Employee emp=(Employee)obj;
    if(this.mobile.equalsIgnoreCase(emp.mobile)){

        System.out.println("returning true");
        return true;
    }else{
        System.out.println("returning false");
        return false;
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Employee emp=new Employee("abc", "hhh");
    Employee emp2=new Employee("abc", "hhh");
    HashMap<Employee, Employee> h=new HashMap<>();
    //for (int i=0;i<5;i++){
        h.put(emp, emp);
        h.put(emp2, emp2);

    //}

    System.out.println("----------------");
    System.out.println("size of hashmap: "+h.size());


}

}
Chetan
sumber
Saya memiliki satu kebingungan, mengapa kita perlu mengganti metode equals ketika kita mengganti metode kode hash dalam kasus HashMap? Bagaimanapun, hashmap menggantikan nilai jika kode hash objek sama.
Vikas Verma
@VikasVerma hashmap tidak menggantikan nilai apa pun jika kode hash objek sama, hanya menentukan indeks di mana objek yang baru ditambahkan ke hashmap harus ditempatkan. Sekarang bisa ada objek pada indeks, jadi untuk menghindari duplikasi kita mengganti metode equals dan kita menulis logika untuk mendefinisikan kapan dua objek dalam perbandingan harus diperlakukan sama. Jika tidak diganti maka meskipun objek yang memiliki nilai yang sama akan disimpan karena referensi kedua objek akan berbeda
Chetan
11

hashCode() :

Jika Anda hanya mengganti metode kode hash, tidak akan terjadi apa-apa. Karena selalu mengembalikan baru hashCodeuntuk setiap objek sebagai kelas Object.

equals() :

Jika Anda hanya mengganti metode yang sama, a.equals(b)itu benar artinya hashCodea dan b harus sama tetapi tidak terjadi. Karena Anda tidak mengganti hashCodemetode.

Catatan: hashCode()metode kelas Object selalu mengembalikan yang baru hashCodeuntuk setiap objek.

Jadi, ketika Anda perlu menggunakan objek Anda di koleksi berbasis hashing, harus menimpa keduanya equals()dan hashCode().

Rinkal Gupta
sumber
Itu poin yang menarik, tentang menimpa hanya kode hash () . Tidak apa-apa, kan? Atau mungkinkah ada kasus yang bermasalah juga?
Johnny
1
Ini adalah jawaban yang menyesatkan dan salah. Overriding (= only =) hashCode () memastikan bahwa setiap objek yang sedang dipakai dari masing-masing kelas dengan properti yang sama memiliki kode hash yang sama. Tetapi tidak akan berguna karena tidak satu pun dari mereka akan sama satu sama lain.
mfaisalhyder
8

Java menempatkan aturan itu

"Jika dua objek sama menggunakan metode kelas sama dengan metode, maka metode kode hash harus memberikan nilai yang sama untuk dua objek ini."

Jadi, jika di kelas kita kita menimpa equals()kita harus mengganti hashcode()metode juga untuk mengikuti aturan ini. Kedua metode, equals()dan hashcode(), digunakan dalam Hashtable, misalnya, untuk menyimpan nilai sebagai pasangan nilai-kunci. Jika kita menimpa satu dan bukan yang lain, ada kemungkinan bahwa Hashtablemungkin tidak berfungsi seperti yang kita inginkan, jika kita menggunakan objek seperti itu sebagai kunci.

Ritesh Kaushik
sumber
6

Karena jika Anda tidak menimpanya, Anda akan menggunakan implentasi default di Object.

Mengingat bahwa nilai kesetaraan dan hascode pada umumnya membutuhkan pengetahuan tentang apa yang membuat objek mereka umumnya perlu didefinisikan ulang di kelas Anda untuk memiliki makna yang nyata.

PaulJWilliams
sumber
6

Untuk menggunakan objek kelas kita sendiri sebagai kunci dalam koleksi seperti HashMap, Hashtable dll., Kita harus mengganti kedua metode (hashCode () dan equals ()) dengan memiliki kesadaran tentang kerja koleksi internal. Kalau tidak, itu mengarah pada hasil yang salah yang tidak kita harapkan.

Prashanth
sumber
6

Menambah jawaban @Lombo

Kapan Anda perlu mengganti equals ()?

Implementasi default Objects equals () adalah

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

yang berarti dua objek akan dianggap sama hanya jika mereka memiliki alamat memori yang sama yang hanya akan benar jika Anda membandingkan objek dengan dirinya sendiri.

Tetapi Anda mungkin ingin mempertimbangkan dua objek yang sama jika mereka memiliki nilai yang sama untuk satu atau lebih dari propertinya (Lihat contoh yang diberikan dalam jawaban @Lombo).

Jadi Anda akan mengesampingkan equals()dalam situasi ini dan Anda akan memberikan kondisi Anda sendiri untuk kesetaraan.

Saya telah berhasil mengimplementasikan equals () dan itu berfungsi dengan baik. Jadi mengapa mereka meminta untuk mengganti kode hash () juga?

Baiklah. Selama Anda tidak menggunakan Koleksi berbasis "Hash" pada kelas yang ditentukan pengguna, tidak apa-apa. Tetapi beberapa waktu di masa depan Anda mungkin ingin menggunakan HashMapatau HashSetdan jika Anda tidak overridedan "menerapkan dengan benar" kode kode () , koleksi berbasis Hash ini tidak akan berfungsi sebagaimana dimaksud.

Timpa hanya sama dengan (Tambahan untuk jawaban @Lombo)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

Pertama-tama, HashMap memeriksa apakah kode hash secondsama dengan first. Hanya jika nilainya sama, ia akan melanjutkan untuk memeriksa kesetaraan dalam ember yang sama.

Tapi di sini kode hash berbeda untuk 2 objek ini (karena mereka memiliki alamat memori yang berbeda-dari implementasi standar). Oleh karena itu bahkan tidak akan peduli untuk memeriksa kesetaraan.

Jika Anda memiliki breakpoint di dalam metode override yang sama dengan () Anda, itu tidak akan masuk jika mereka memiliki kode hash yang berbeda. contains()memeriksa hashCode()dan hanya jika mereka sama itu akan memanggil equals()metode Anda .

Mengapa kita tidak bisa melakukan pemeriksaan HashMap untuk kesetaraan di semua ember? Jadi tidak ada keharusan bagi saya untuk menimpa kode hash () !!

Maka Anda kehilangan titik Koleksi berbasis Hash. Pertimbangkan yang berikut ini:

Your hashCode() implementation : intObject%9.

Berikut ini adalah kunci-kunci yang disimpan dalam bentuk ember.

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

Katakan, Anda ingin tahu apakah peta tersebut berisi kunci 10. Apakah Anda ingin mencari semua kotak? atau Apakah Anda ingin mencari hanya satu ember?

Berdasarkan kode hash, Anda akan mengidentifikasi bahwa jika 10 ada, itu harus ada di Bucket 1. Jadi hanya Bucket 1 yang akan dicari !!

pengguna104309
sumber
5
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • put ('key', 'value') akan menghitung nilai hash menggunakan hashCode()untuk menentukan ember dan menggunakan equals()metode untuk menemukan apakah nilai tersebut sudah ada dalam Bucket. Jika tidak akan ditambahkan lagi maka akan diganti dengan nilai saat ini
  • get ('key') akan digunakan hashCode()untuk menemukan Entri (ember) terlebih dahulu dan equals()untuk menemukan nilai dalam Entri

jika Keduanya ditimpa,

Peta < A >

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

jika sama tidak ditimpa

Peta < A >

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

Jika kode hash tidak diganti

Peta < A >

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

Kontrak Setara HashCode

  1. Dua kunci yang sama menurut metode yang sama harus menghasilkan kode hash yang sama
  2. Dua Kunci yang menghasilkan kode hash yang sama tidak perlu sama (Dalam contoh di atas semua angka genap menghasilkan Kode hash yang sama)
bharanitharan
sumber
4

Pertimbangkan koleksi bola dalam ember yang semuanya berwarna hitam. Pekerjaan Anda adalah mewarnai bola-bola itu sebagai berikut dan menggunakannya untuk permainan yang sesuai,

Untuk Tenis - Kuning, Merah. Untuk Cricket - White

Sekarang ember memiliki bola dalam tiga warna Kuning, Merah dan Putih. Dan sekarang Anda melakukan pewarnaan. Hanya Anda yang tahu warna untuk permainan mana.

Mewarnai bola - Hashing. Memilih bola untuk permainan - Sama.

Jika Anda melakukan pewarnaan dan seseorang memilih bola untuk kriket atau tenis, mereka tidak akan keberatan dengan warnanya !!!

bharanitharan
sumber
4

Saya melihat ke penjelasan "Jika Anda hanya menimpa kode hash maka ketika Anda memanggilnya myMap.put(first,someValue)butuh lebih dulu, hitung kode hash-nya dan simpan dalam ember yang diberikan. Lalu ketika Anda memanggilnya myMap.put(first,someOtherValue)harus ganti dulu dengan yang kedua sesuai Dokumentasi Peta karena mereka sama (sesuai dengan definisi kami). " :

Saya pikir waktu ke-2 ketika kita menambahkan myMapmaka itu harus menjadi objek 'kedua' sepertimyMap.put(second,someOtherValue)

Narinder
sumber
4

1) Kesalahan umum ditunjukkan pada contoh di bawah ini.

public class Car {

    private String color;

    public Car(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if(obj==null) return false;
        if (!(obj instanceof Car))
            return false;   
        if (obj == this)
            return true;
        return this.color.equals(((Car) obj).color);
    }

    public static void main(String[] args) {
        Car a1 = new Car("green");
        Car a2 = new Car("red");

        //hashMap stores Car type and its quantity
        HashMap<Car, Integer> m = new HashMap<Car, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Car("green")));
    }
}

Mobil hijau tidak ditemukan

2. Masalah yang disebabkan oleh kode hash ()

Masalahnya disebabkan oleh metode un-override hashCode(). Kontrak antara equals()dan hashCode()adalah:

  1. Jika dua objek sama, maka mereka harus memiliki kode hash yang sama.
  2. Jika dua objek memiliki kode hash yang sama, mereka mungkin atau mungkin tidak sama.

    public int hashCode(){  
      return this.color.hashCode(); 
    }
Neeraj Gahlawat
sumber
4

Ini berguna saat menggunakan Objek Nilai . Berikut ini adalah kutipan dari Portland Pattern Repository :

Contoh objek nilai adalah hal-hal seperti angka, tanggal, uang, dan string. Biasanya, mereka adalah benda kecil yang digunakan cukup luas. Identitas mereka didasarkan pada negara mereka daripada pada identitas objek mereka. Dengan cara ini, Anda dapat memiliki banyak salinan dari objek nilai konseptual yang sama.

Jadi saya dapat memiliki banyak salinan dari suatu objek yang mewakili tanggal 16 Januari 1998. Setiap salinan ini akan sama satu sama lain. Untuk objek kecil seperti ini, seringkali lebih mudah untuk membuat yang baru dan memindahkannya daripada bergantung pada satu objek untuk mewakili tanggal.

Objek nilai harus selalu menimpa .equals () di Java (atau = di Smalltalk). (Ingatlah untuk mengganti .hashCode () juga.)

Ionuț G. Stan
sumber
3

Asumsikan Anda memiliki kelas (A) yang menggabungkan dua lainnya (B) (C), dan Anda perlu menyimpan instance (A) di dalam hashtable. Implementasi default hanya memungkinkan membedakan instance, tetapi tidak dengan (B) dan (C). Jadi, dua contoh A bisa sama, tetapi standar tidak memungkinkan Anda membandingkannya dengan cara yang benar.

Dewfy
sumber
3

Metode sama dengan dan kode hash didefinisikan dalam kelas objek. Secara default jika metode equals mengembalikan nilai true, maka sistem akan melangkah lebih jauh dan memeriksa nilai kode hash. Jika kode hash dari 2 objek juga sama, maka objek akan dianggap sama. Jadi jika Anda menimpa hanya metode sama dengan, maka meskipun metode sama menimpa menunjukkan 2 objek menjadi sama, sistem kode hash yang ditentukan mungkin tidak menunjukkan bahwa 2 objek sama. Jadi kita perlu mengganti kode hash juga.

Aarti
sumber
Jika metode equals mengembalikan true, tidak perlu memeriksa kode hash. Namun, jika dua objek memiliki kode hash yang berbeda, seseorang harus dapat menganggapnya sebagai berbeda tanpa harus memanggil sama. Lebih lanjut, pengetahuan bahwa tidak ada hal-hal dalam daftar yang memiliki kode hash tertentu menyiratkan bahwa tidak ada hal-hal di daftar yang dapat mencocokkan objek nay dengan kode hash itu. Sebagai contoh sederhana, jika seseorang memiliki daftar objek yang kode hashnya adalah bilangan genap, dan daftar objek yang bilangan ganjilnya, tidak ada objek yang kode hashnya adalah bilangan genap akan berada di daftar kedua.
supercat
Jika seseorang memiliki dua objek X dan Y yang "sama dengan" metode menunjukkan mereka cocok, tetapi kode hash X adalah bilangan genap dan kode hash Y adalah angka ganjil, koleksi seperti yang dijelaskan di atas yang mencatat bahwa kode hash objek Y aneh dan disimpan pada daftar kedua tidak akan dapat menemukan kecocokan untuk objek X. Akan mengamati bahwa kode hash X adalah genap, dan karena daftar kedua tidak memiliki objek dengan kode hash genap bernomor, itu tidak akan mengganggu untuk mencari sesuatu yang cocok dengan X, meskipun Y akan cocok dengan X. Apa yang harus Anda katakan ...
supercat
... akan banyak koleksi yang akan menghindari membandingkan hal-hal yang kode hashnya menyiratkan bahwa mereka tidak dapat sama. Mengingat dua objek yang kode hashnya tidak diketahui, seringkali lebih cepat untuk membandingkannya secara langsung daripada menghitung kode hash mereka, jadi tidak ada jaminan bahwa hal-hal yang melaporkan kode hash yang tidak sama tetapi pengembalian trueuntuk equalstidak akan dianggap cocok. Di sisi lain, jika koleksi terjadi perhatikan bahwa sesuatu tidak dapat memiliki kode hash yang sama, mereka cenderung tidak menyadari bahwa mereka sama.
supercat
3

Metode Persamaan dan Hashcode di Jawa

Mereka adalah metode kelas java.lang.Object yang merupakan kelas super dari semua kelas (kelas kustom juga dan yang lainnya didefinisikan dalam java API).

Penerapan:

public boolean equals (Object obj)

kode hash int publik ()

masukkan deskripsi gambar di sini

public boolean equals (Object obj)

Metode ini hanya memeriksa apakah dua referensi objek x dan y merujuk ke objek yang sama. Yaitu memeriksa apakah x == y.

Itu refleksif: untuk setiap nilai referensi x, x. sama dengan (x) harus mengembalikan true.

Itu simetris: untuk setiap nilai referensi x dan y, x.equals (y) harus mengembalikan true jika dan hanya jika y.equals (x) mengembalikan true.

Ini transitif: untuk setiap nilai referensi x, y, dan z, jika x.equals (y) mengembalikan true dan y.equals (z) mengembalikan true, maka x.equals (z) harus mengembalikan true.

Ini konsisten: untuk setiap nilai referensi x dan y, beberapa pemanggilan x.equals (y) secara konsisten mengembalikan true atau secara konsisten menghasilkan false, asalkan tidak ada informasi yang digunakan dalam perbandingan yang setara dengan objek yang dimodifikasi.

Untuk setiap nilai referensi non-null x, x.equals (null) harus mengembalikan false.

kode hash int publik ()

Metode ini mengembalikan nilai kode hash untuk objek di mana metode ini dipanggil. Metode ini mengembalikan nilai kode hash sebagai integer dan didukung untuk kepentingan hash kelas koleksi berbasis seperti Hashtable, HashMap, HashSet dll. Metode ini harus diganti di setiap kelas yang menimpa metode equals.

Kontrak umum kode hash adalah:

Setiap kali ia dipanggil pada objek yang sama lebih dari sekali selama eksekusi aplikasi Java, metode kode hash harus secara konsisten mengembalikan integer yang sama, asalkan tidak ada informasi yang digunakan dalam perbandingan yang setara dengan objek yang dimodifikasi.

Bilangan bulat ini tidak harus tetap konsisten dari satu eksekusi aplikasi ke eksekusi aplikasi lainnya yang sama.

Jika dua objek sama menurut metode equals (Objek), maka memanggil metode hashCode pada masing-masing dua objek harus menghasilkan hasil integer yang sama.

Tidak diperlukan bahwa jika dua objek tidak sama menurut metode equals (java.lang.Object), maka memanggil metode hashCode pada masing-masing dua objek harus menghasilkan hasil integer yang berbeda. Namun, programmer harus menyadari bahwa menghasilkan hasil integer yang berbeda untuk objek yang tidak sama dapat meningkatkan kinerja hashtables.

Objek yang sama harus menghasilkan kode hash yang sama selama mereka sama, namun objek yang tidak sama tidak perlu menghasilkan kode hash yang berbeda.

Sumber:

JavaRanch

Gambar

Affy
sumber
Gambar (tautan video) dalam mode pribadi. Jadikan publik untuk menonton.
UdayKiran Pulipati
2

Dalam contoh di bawah ini, jika Anda mengomentari override untuk sama atau kode hash di kelas Person, kode ini akan gagal untuk mencari pesanan Tom. Menggunakan implementasi standar kode hash dapat menyebabkan kegagalan dalam pencarian hashtable.

Apa yang saya miliki di bawah ini adalah kode sederhana yang menarik pesanan orang oleh Orang. Orang sedang digunakan sebagai kunci dalam hashtable.

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

    public Person(String name, int age, String socialSecurityNumber) {
        this.name = name;
        this.age = age;
        this.socialSecurityNumber = socialSecurityNumber;
    }

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}
developer747
sumber
2

Kelas string dan kelas pembungkus memiliki implementasi equals()dan hashCode()metode yang berbeda dari kelas Obyek. equals () metode kelas Object membandingkan referensi objek, bukan isinya. metode hashCode () dari kelas Object mengembalikan kode hash yang berbeda untuk setiap objek apakah isinya sama.

Ini menyebabkan masalah ketika Anda menggunakan koleksi Peta dan kuncinya adalah tipe Persistent, tipe StringBuffer / builder. Karena mereka tidak menimpa equals () dan hashCode () tidak seperti kelas String, equals () akan mengembalikan false ketika Anda membandingkan dua objek yang berbeda walaupun keduanya memiliki konten yang sama. Ini akan membuat hashMap menyimpan kunci konten yang sama. Menyimpan kunci konten yang sama berarti melanggar aturan Peta karena Peta sama sekali tidak mengizinkan kunci duplikat. Oleh karena itu Anda mengganti metode equals () dan juga hashCode () di kelas Anda dan memberikan implementasi (IDE dapat menghasilkan metode ini) sehingga mereka bekerja sama dengan String's equals () dan hashCode () dan mencegah kunci konten yang sama.

Anda harus mengganti metode hashCode () bersama dengan equals () karena equals () bekerja sesuai kode hash.

Selain itu meng-overhode metode hashCode () bersama dengan equals () membantu untuk membuat equals () - hashCode () kontrak: "Jika dua objek sama, maka mereka harus memiliki kode hash yang sama."

Kapan Anda perlu menulis implementasi khusus untuk hashCode ()?

Seperti yang kita ketahui bahwa kerja internal HashMap adalah prinsip Hashing. Ada beberapa ember tempat entri disimpan. Anda mengkustomisasi implementasi kode hash () sesuai kebutuhan Anda sehingga objek kategori yang sama dapat disimpan ke dalam indeks yang sama. ketika Anda menyimpan nilai-nilai ke dalam pengumpulan Peta menggunakan put(k,v)metode, implementasi internal put () adalah:

put(k, v){
hash(k);
index=hash & (n-1);
}

Berarti, ini menghasilkan indeks dan indeks dihasilkan berdasarkan kode hash objek kunci tertentu. Jadi buat metode ini menghasilkan kode hash sesuai kebutuhan Anda karena entri kode hash yang sama akan disimpan ke dalam ember atau indeks yang sama.

Itu dia!

Arun Raaj
sumber
1

hashCode()Metode digunakan untuk mendapatkan integer unik untuk objek yang diberikan. Bilangan bulat ini digunakan untuk menentukan lokasi bucket, ketika objek ini perlu disimpan di beberapa HashTable, HashMapseperti struktur data. Secara default, hashCode()metode Object mengembalikan dan representasi integer dari alamat memori tempat objek disimpan.

The hashCode()Metode benda yang digunakan saat kita memasukkan mereka ke dalam HashTable, HashMapatau HashSet. Lebih lanjut tentang HashTablesdi Wikipedia.org untuk referensi.

Untuk memasukkan entri apa pun dalam struktur data peta, kita membutuhkan kunci dan nilai. Jika kedua kunci dan nilai adalah tipe data yang hashCode()ditentukan pengguna, kunci akan menentukan di mana harus menyimpan objek secara internal. Ketika perlu mencari objek dari peta juga, kode hash kunci akan menentukan di mana mencari objek.

Kode hash hanya menunjuk ke "area" tertentu (atau daftar, bucket dll) secara internal. Karena objek kunci yang berbeda berpotensi memiliki kode hash yang sama, kode hash itu sendiri bukanlah jaminan bahwa kunci yang tepat ditemukan. The HashTablekemudian iterates daerah ini (semua kunci dengan kode hash yang sama) dan menggunakan kunci ini equals()metode untuk menemukan kunci yang tepat. Setelah kunci kanan ditemukan, objek yang disimpan untuk kunci itu dikembalikan.

Jadi, seperti yang bisa kita lihat, kombinasi dari hashCode()dan equals()metode digunakan ketika menyimpan dan ketika mencari objek di a HashTable.

CATATAN:

  1. Selalu gunakan atribut yang sama dari objek untuk menghasilkan hashCode()dan equals()keduanya. Seperti dalam kasus kami, kami telah menggunakan id karyawan.

  2. equals() harus konsisten (jika objek tidak dimodifikasi, maka ia harus tetap mengembalikan nilai yang sama).

  3. Kapanpun a.equals(b), maka a.hashCode()harus sama dengan b.hashCode().

  4. Jika Anda menimpa satu, maka Anda harus menimpa yang lain.

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html

Paramesh Korrakuti
sumber
hashCode()tidak digunakan untuk mengembalikan integer unik untuk setiap objek. Itu tidak mungkin. Anda sendiri telah membantahnya dalam kalimat kedua paragraf keempat.
Marquis of Lorne
@ EJP, sebagian besar kode waktu () akan mengembalikan interger unik untuk dua objek yang berbeda. Tetapi ada kemungkinan collide hascode untuk dua objek yang berbeda, konsep ini disebut sebagai Hashcode Collision . Silakan lihat: tech.queryhome.com/96931/…
Paramesh Korrakuti
1

IMHO, sesuai aturan mengatakan - Jika dua objek sama maka mereka harus memiliki hash yang sama, yaitu objek yang sama harus menghasilkan nilai hash yang sama.

Diberikan di atas, default equals () dalam Object adalah == yang melakukan perbandingan pada alamat, hashCode () mengembalikan alamat dalam integer (hash pada alamat aktual) yang lagi berbeda untuk Objek yang berbeda.

Jika Anda perlu menggunakan Objek kustom di koleksi berbasis Hash, Anda harus mengganti sama dengan equals () dan hashCode (), contoh Jika saya ingin mempertahankan HashSet dari Objek Karyawan, jika saya tidak menggunakan kode hash yang lebih kuat dan sama dengan Saya dapat mengakhiri mengesampingkan dua Objek Karyawan yang berbeda, ini terjadi ketika saya menggunakan usia sebagai kode hash (), namun saya harus menggunakan nilai unik yang bisa menjadi ID Karyawan.

Cleonjoys
sumber
1

Untuk membantu Anda memeriksa Objek duplikat, kami membutuhkan kode yang sama dengan dan kode hash.

Karena kode hash selalu mengembalikan angka, maka selalu cepat untuk mengambil objek menggunakan angka daripada kunci alfabet. Bagaimana cara kerjanya? Asumsikan kita membuat objek baru dengan melewatkan beberapa nilai yang sudah tersedia di beberapa objek lain. Sekarang objek baru akan mengembalikan nilai hash yang sama dengan objek lain karena nilai yang diteruskan sama. Setelah nilai hash yang sama dikembalikan, JVM akan pergi ke alamat memori yang sama setiap kali dan jika dalam kasus ada lebih dari satu objek hadir untuk nilai hash yang sama akan menggunakan metode equals () untuk mengidentifikasi objek yang benar.

Tavash
sumber
1

Ketika Anda ingin menyimpan dan mengambil objek kustom Anda sebagai kunci di Peta, maka Anda harus selalu menimpa sama dengan dan kode hash di Objek kustom Anda. Misalnya:

Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");

Di sini p1 & p2 akan dipertimbangkan karena hanya satu objek dan mapukuran hanya akan 1 karena keduanya sama.

Ambrish Rajput
sumber
1
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

Kelas Tes

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

Dalam Object class equals (Object obj) digunakan untuk membandingkan perbandingan alamat, itu sebabnya ketika di kelas Test jika Anda membandingkan dua objek maka sama dengan metode memberi false tetapi ketika kita menimpa kode hash () itu dapat membandingkan konten dan memberikan hasil yang tepat.

Manash Ranjan Dakua
sumber
dan kelas Tes I ditambahkan dalam program di bawah ini.
Manash Ranjan Dakua
Dalam Object class equals (Object obj) digunakan untuk membandingkan perbandingan alamat, itu sebabnya ketika di kelas Test jika Anda membandingkan dua objek maka sama dengan metode memberi false tetapi ketika kita menimpa kode hash () itu dapat membandingkan konten dan memberikan hasil yang tepat.
Manash Ranjan Dakua
1
Anda dapat menggunakan tautan edit tepat di bawah jawaban ini untuk menambah jawaban Anda .. Tolong jangan tambahkan jawaban sebagai dua jawaban yang tidak lengkap
Suraj Rao
1

Jika Anda menimpa equals()dan tidak hashcode(), Anda tidak akan menemukan masalah kecuali Anda atau orang lain menggunakan tipe kelas dalam koleksi hash seperti HashSet. Orang-orang sebelum saya dengan jelas menjelaskan teori yang didokumentasikan beberapa kali, saya hanya di sini untuk memberikan contoh yang sangat sederhana.

Pertimbangkan kelas yang equals()kebutuhannya berarti sesuatu yang disesuaikan: -

    public class Rishav {

        private String rshv;

        public Rishav(String rshv) {
            this.rshv = rshv;
        }

        /**
        * @return the rshv
        */
        public String getRshv() {
            return rshv;
        }

        /**
        * @param rshv the rshv to set
        */
        public void setRshv(String rshv) {
            this.rshv = rshv;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Rishav) {
                obj = (Rishav) obj;
                if (this.rshv.equals(((Rishav) obj).getRshv())) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            return rshv.hashCode();
        }

    }

Sekarang pertimbangkan kelas utama ini: -

    import java.util.HashSet;
    import java.util.Set;

    public class TestRishav {

        public static void main(String[] args) {
            Rishav rA = new Rishav("rishav");
            Rishav rB = new Rishav("rishav");
            System.out.println(rA.equals(rB));
            System.out.println("-----------------------------------");

            Set<Rishav> hashed = new HashSet<>();
            hashed.add(rA);
            System.out.println(hashed.contains(rB));
            System.out.println("-----------------------------------");

            hashed.add(rB);
            System.out.println(hashed.size());
        }

    }

Ini akan menghasilkan output berikut: -

    true
    -----------------------------------
    true
    -----------------------------------
    1

Saya senang dengan hasilnya. Tetapi jika saya belum menimpa hashCode(), itu akan menyebabkan mimpi buruk karena objek Rishavdengan konten anggota yang sama tidak akan lagi diperlakukan sebagai unik karena hashCodeakan berbeda, seperti yang dihasilkan oleh perilaku default, inilah hasilnya: -

    true
    -----------------------------------
    false
    -----------------------------------
    2
91StarSky
sumber
0

Kedua metode didefinisikan dalam kelas Object. Dan keduanya dalam implementasi yang paling sederhana. Jadi ketika Anda membutuhkan Anda ingin menambahkan beberapa implementasi untuk metode ini maka Anda harus menimpa di kelas Anda.

Untuk Ex: equals () metode dalam objek hanya memeriksa kesetaraannya pada referensi. Jadi jika Anda perlu membandingkan kondisinya juga maka Anda dapat menimpanya seperti yang dilakukan dalam kelas String.

GuruKulki
sumber
-3

Bah - "Anda harus mengganti kode hash () di setiap kelas yang menimpa sama dengan ()."

[dari Java Efektif, oleh Joshua Bloch?]

Bukankah ini yang salah? Mengganti kode hash kemungkinan menyiratkan Anda sedang menulis kelas hash-key, tetapi mengganti kode hash tentu saja tidak. Ada banyak kelas yang tidak digunakan sebagai kunci hash, tetapi memang menginginkan metode pengujian kesetaraan logis untuk beberapa alasan lain. Jika Anda memilih "sama dengan" untuk itu, Anda kemudian dapat diberi mandat untuk menulis implementasi kode hash dengan penerapan aturan ini secara berlebihan. Semua yang berhasil adalah menambahkan kode yang belum diuji dalam basis kode, kejahatan menunggu seseorang untuk tersandung di masa depan. Juga menulis kode yang tidak Anda butuhkan adalah anti-gesit. Itu hanya salah (dan ide yang dihasilkan mungkin tidak akan sesuai dengan hasil kerajinan tangan Anda).

Tentunya mereka harus mengamanatkan Interface pada objek yang ditulis untuk digunakan sebagai kunci? Apapun, Objek seharusnya tidak menyediakan kode hash () dan equals () imho. Mungkin mendorong banyak koleksi hash yang rusak.

Tapi bagaimanapun, saya pikir "aturan" ditulis kembali ke depan. Sementara itu, saya akan terus menghindari penggunaan "sama dengan" untuk metode pengujian kesetaraan :-(

Alan Dobbie
sumber