JavaRush /Blog Java /Random-MS /Coffee break #168. Mengapa mengatasi kaedah equals dan ha...

Coffee break #168. Mengapa mengatasi kaedah equals dan hashcode dalam Java?

Diterbitkan dalam kumpulan

Mengapa mengatasi kaedah equals dan hashcode dalam Java?

Sumber: Sederhana Artikel ini memfokuskan kepada dua kaedah yang berkait rapat: equals() dan hashcode() . Anda akan belajar cara mereka berinteraksi antara satu sama lain dan cara mengatasinya dengan betul. Coffee break #168.  Mengapa mengatasi kaedah equals dan hashcode dalam Java?  - 1

Mengapa kita mengatasi kaedah equals()?

Di Jawa, kita tidak boleh membebankan tingkah laku pengendali seperti == , += , -+ . Mereka bekerja mengikut proses tertentu. Sebagai contoh, pertimbangkan operasi operator == .

Bagaimanakah pengendali == berfungsi?

Ia menyemak sama ada kedua-dua rujukan yang dibandingkan menunjuk kepada contoh yang sama dalam ingatan. Operator == hanya akan menilai kepada benar jika kedua-dua rujukan mewakili contoh yang sama dalam ingatan. Mari kita lihat kod sampel:
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
      }
Katakan dalam program anda, anda telah mencipta dua objek Orang di tempat yang berbeza dan ingin membandingkannya.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println( person1 == person2 ); --> will print false!
Dari perspektif perniagaan, kedua-duanya kelihatan sama, bukan? Tetapi untuk JVM mereka tidak sama. Memandangkan kedua-duanya dicipta menggunakan kata kunci baharu , tika ini terletak dalam segmen memori yang berbeza. Oleh itu operator == akan mengembalikan false . Tetapi jika kita tidak boleh mengatasi == operator , maka bagaimana kita memberitahu JVM bahawa kita mahu kedua-dua objek ini diperlakukan sama? Di sinilah kaedah .equals() memainkan peranan . Anda boleh mengatasi equals() untuk menyemak sama ada sesetengah objek mempunyai nilai yang sama untuk medan tertentu untuk menganggapnya sama. Anda boleh memilih medan yang hendak dibandingkan. Jika kita mengatakan bahawa dua objek Orang akan sama hanya jika mereka mempunyai umur yang sama dan nama yang sama, maka IDE akan menjana sesuatu seperti ini untuk mencipta equals() secara automatik :
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
Mari kita kembali kepada contoh sebelumnya.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
System.out.println ( person1.equals(person2) ); --> will print true!
Ya, kita tidak boleh membebankan operator == untuk membandingkan objek dengan cara yang kita mahu, tetapi Java memberi kita cara lain - kaedah equals() , yang boleh kita ganti mengikut kehendak kita. Perlu diingat bahawa jika kami tidak menyediakan versi tersuai kami .equals() (juga dikenali sebagai override) dalam kelas kami, maka .equals() yang dipratentukan daripada kelas Object dan operator == akan berkelakuan sama. Kaedah lalai equals() , diwarisi daripada Object , akan menyemak sama ada kedua-dua kejadian yang dibandingkan adalah sama dalam ingatan!

Mengapa kita mengatasi kaedah hashCode()?

Sesetengah struktur data dalam Java, seperti HashSet dan HashMap , menyimpan elemennya berdasarkan fungsi cincang yang digunakan pada elemen tersebut. Fungsi hash ialah hashCode() . Jika kita mempunyai pilihan untuk mengatasi kaedah .equals() , maka kita juga harus mempunyai pilihan untuk mengatasi kaedah hashCode() . Ada sebab untuk ini. Lagipun, pelaksanaan lalai hashCode() , yang diwarisi daripada Object , menganggap semua objek dalam ingatan sebagai unik! Tetapi mari kita kembali kepada struktur data cincang ini. Terdapat peraturan untuk struktur data ini. HashSet tidak boleh mengandungi nilai pendua dan HashMap tidak boleh mengandungi kunci pendua. HashSet dilaksanakan menggunakan HashMap dengan cara yang setiap nilai HashSet disimpan sebagai kunci dalam HashMap . Bagaimanakah HashMap berfungsi ? HashMap ialah tatasusunan asli dengan berbilang segmen. Setiap segmen mempunyai senarai terpaut ( linkedList ). Senarai terpaut ini menyimpan kunci kami. HashMap mencari linkedList yang betul untuk setiap kunci menggunakan kaedah hashCode() , dan kemudian melelang melalui semua elemen linkedList itu dan menggunakan kaedah equals() pada setiap elemen tersebut untuk menyemak sama ada elemen itu terkandung di sana. Kunci pendua tidak dibenarkan. Coffee break #168.  Mengapa mengatasi kaedah equals dan hashcode dalam Java?  - 2Apabila kami meletakkan sesuatu di dalam HashMap , kunci itu disimpan dalam salah satu senarai terpaut ini. Senarai terpaut mana kunci ini akan disimpan dalam ditunjukkan oleh hasil kaedah hashCode() untuk kunci itu. Iaitu, jika key1.hashCode() menghasilkan 4, maka key1 itu akan disimpan dalam segmen ke-4 tatasusunan dalam LinkedList yang sedia ada di sana . Secara lalai, kaedah hashCode() mengembalikan hasil yang berbeza untuk setiap contoh. Jika kita mempunyai equals() lalai yang berkelakuan seperti == , menganggap semua kejadian dalam memori sebagai objek berbeza, maka tidak akan ada masalah. Seperti yang anda ingat, dalam contoh kami sebelum ini, kami mengatakan bahawa kami mahu contoh Orang dianggap sama jika umur dan nama mereka adalah sama.
Person person1 = new Person("Mike", 34);
    Person person2 = new Person("Mike", 34);
    System.out.println ( person1.equals(person2) );  --> will print true!
Sekarang mari kita buat peta untuk menyimpan kejadian ini sebagai kunci dengan rentetan tertentu sebagai pasangan nilai.
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
Dalam kelas Person , kami tidak mengatasi kaedah hashCode , tetapi kami mempunyai kaedah equals yang ditindih . Memandangkan hashCode lalai memberikan hasil yang berbeza untuk contoh Java yang berbeza bagi person1.hashCode() dan person2.hashCode() , terdapat peluang yang tinggi untuk mendapatkan hasil yang berbeza. Peta kami boleh berakhir dengan orang yang berbeza dalam senarai terpaut yang berbeza. Coffee break #168.  Mengapa mengatasi kaedah equals dan hashcode dalam Java?  - 3Ini bertentangan dengan logik HashMap . Lagipun, HashMap tidak boleh mempunyai beberapa kunci yang sama! Intinya ialah hashCode() lalai yang diwarisi daripada kelas Objek tidak mencukupi. Walaupun selepas kita mengatasi kaedah equals() kelas Person . Itulah sebabnya kita perlu mengatasi kaedah hashCode() selepas kita mengatasi equals method . Sekarang mari kita betulkan ini. Kami perlu mengatasi kaedah hashCode() kami supaya ia mengambil kira medan yang sama seperti equals() , iaitu age dan name .
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
@Override
public int hashCode() {
        int prime = 31;
        return prime*Objects.hash(name, age);
    }
Dalam kaedah hashCode() kami menggunakan nilai mudah (anda boleh menggunakan sebarang nilai lain). Walau bagaimanapun, adalah dicadangkan untuk menggunakan nombor perdana untuk mencipta lebih sedikit masalah. Mari cuba simpan kunci ini dalam HashMap kami sekali lagi :
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
person1.hashCode() dan person2.hashCode() akan menjadi sama. Katakan ia adalah 0. HashMap akan pergi ke segmen 0 dan di dalamnya LinkedList akan menyimpan person1 sebagai kunci dengan nilai "1". Dalam kes kedua, apabila HashMap pergi ke baldi 0 sekali lagi untuk menyimpan orang utama2 dengan nilai "2", ia akan melihat bahawa kunci lain yang sama dengannya sudah wujud di sana. Dengan cara ini ia akan menimpa kekunci sebelumnya. Dan hanya orang2 utama yang akan wujud dalam HashMap kami . Beginilah kami mempelajari cara peraturan HashMap berfungsi , yang menyatakan bahawa anda tidak boleh menggunakan berbilang kunci yang sama! Walau bagaimanapun, perlu diingat bahawa kejadian yang tidak sama rata boleh mempunyai kod cincang yang sama dan tika yang sama mesti mengembalikan kod cincang yang sama.Coffee break #168.  Mengapa mengatasi kaedah equals dan hashcode dalam Java?  - 4
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION