JavaRush /Blog Jawa /Random-JV /Setara lan kontrak kode hash utawa apa wae
Aleksandr Zimin
tingkat
Санкт-Петербург

Setara lan kontrak kode hash utawa apa wae

Diterbitake ing grup
Akèh-akèhé saka programer Jawa, mesthi, ngerti sing cara equalssing hashCoderaket related kanggo saben liyane, lan iku saranake kanggo override loro cara iki ing kelas konsisten. Nomer sing rada cilik ngerti kenapa iki lan apa akibat sing bisa kedadeyan yen aturan iki dilanggar. Aku ngusulake kanggo nimbang konsep metode kasebut, mbaleni tujuane lan ngerti sebabe disambungake. Aku nulis artikel iki, kaya sing sadurunge babagan ngemot kelas, kanggo aku supaya pungkasane mbukak kabeh rincian masalah kasebut lan ora bali menyang sumber pihak katelu. Mula, aku bakal seneng menehi kritik sing mbangun, amarga yen ana kesenjangan ing endi wae, kudu diilangi. Artikel kasebut, sayangé, ternyata cukup dawa.

padha karo aturan override

Ana cara equals()sing dibutuhake ing Jawa kanggo ngonfirmasi utawa mbantah kasunyatan manawa rong obyek sing asale padha kanthi logis padha . Yaiku, nalika mbandhingake rong obyek, programer kudu ngerti apa lapangan sing penting padha . Ora perlu kabeh kolom kudu padha, amarga metode kasebut equals()nuduhake kesetaraan logis . Nanging kadhangkala ora perlu nggunakake metode iki. Kaya sing dikandhakake, cara paling gampang kanggo nyegah masalah nggunakake mekanisme tartamtu yaiku ora nggunakake. Sampeyan uga kudu dicathet yen sampeyan ngilangi kontrak, equalssampeyan bakal kelangan pangerten babagan carane obyek lan struktur liyane bakal sesambungan karo obyek sampeyan. Lan banjur nemokake sabab saka kesalahan bakal angel banget.

Nalika ora kanggo override cara iki

  • Nalika saben instance saka kelas unik.
  • Kanggo luwih akeh, iki ditrapake kanggo kelas sing nyedhiyakake prilaku tartamtu tinimbang dirancang kanggo nggarap data. Kayata, contone, minangka kelas Thread. Kanggo dheweke equals, implementasine metode sing diwenehake dening kelas Objectluwih saka cukup. Conto liyane yaiku kelas enum ( Enum).
  • Nalika nyatane kelas kasebut ora dibutuhake kanggo nemtokake kesetaraan saka kedadeyan kasebut.
  • Contone, kanggo kelas java.util.Randomana ora perlu kanggo mbandhingaké kedadean saka kelas karo saben liyane, nemtokake apa padha bisa bali urutan padha nomer acak. Mung amarga sifat kelas iki ora nuduhake prilaku kasebut.
  • Nalika kelas sampeyan ndawakake wis duwe implementasine dhewe saka cara equalslan prilaku implementasine iki cocog karo sampeyan.
  • Contone, kanggo kelas Set, List, Mapimplementasine equalsing AbstractSet, AbstractListlan AbstractMapmungguh.
  • Lan pungkasanipun, ana ora perlu kanggo override equalsnalika orane katrangan saka kelas privateutawa package-privatelan sampeyan manawa ing cara iki ora bakal disebut.

padha kontrak

Nalika ngatasi cara, equalspangembang kudu netepi aturan dhasar sing ditetepake ing spesifikasi basa Jawa.
  • Refleksivity
  • kanggo sembarang nilai tartamtu x, expression x.equals(x)kudu bali true.
    Diwenehi - tegese kuwix != null
  • simetri
  • kanggo sembarang nilai tartamtu xlan y, x.equals(y)kudu bali truemung yen y.equals(x)bali true.
  • Transitivity
  • kanggo sembarang nilai diwenehi x, ylan z, yen x.equals(y)bali truelan y.equals(z)bali true, x.equals(z)kudu bali Nilai true.
  • Konsistensi
  • kanggo sembarang nilai diwenehi, xlan ytelpon bola-bali x.equals(y)bakal bali ing Nilai saka telpon sadurungé kanggo cara iki, kasedhiya yen kothak digunakake kanggo mbandhingaké loro obyek ora ngganti antarane telpon.
  • Perbandingan null
  • kanggo sembarang nilai tartamtu xtelpon x.equals(null)kudu bali false.

padha karo nglanggar kontrak

Akeh kelas, kayata saka Java Collections Framework, gumantung saka implementasine metode kasebut equals(), mula sampeyan ora kudu nglirwakake, amarga Pelanggaran kontrak cara iki bisa nyebabake operasi aplikasi sing ora rasional, lan ing kasus iki bakal angel nemokake alasane. Miturut prinsip refleksivitas , saben obyek kudu padha karo awake dhewe. Yen prinsip iki dilanggar, nalika kita nambah obyek menyang koleksi banjur nggoleki kanthi nggunakake metode, contains()kita ora bakal bisa nemokake obyek sing mung ditambahake menyang koleksi. Kondisi simetri nyatakake yen rong obyek kudu padha tanpa dipikirake urutane dibandhingake. Contone, yen sampeyan duwe kelas sing ngemot mung siji lapangan saka jinis senar, iku bakal salah kanggo mbandhingaké equalslapangan iki karo senar ing cara. Amarga ing kasus mbandhingake mbalikke, cara kasebut bakal ngasilake nilai kasebut false.
// Нарушение симметричности
public class SomeStringify {
    private String s;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof SomeStringify) {
            return s.equals(((SomeStringify) o).s);
        }
        // нарушение симметричности, классы разного происхождения
        if (o instanceof String) {
            return s.equals(o);
        }
        return false;
    }
}
//Правильное определение метода equals
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    return o instanceof SomeStringify &&
            ((SomeStringify) o).s.equals(s);
}
Saking kawontenan transivitas menika menawi wonten kalih saking telu objek ingkang sami, ing kasus menika telunipun kedah sami. Prinsip iki bisa gampang dilanggar nalika perlu kanggo nggedhekake kelas dhasar tartamtu kanthi nambahake komponen sing migunani . Contone, menyang kelas Pointkaro koordinat xlan ysampeyan kudu nambah werna titik kanthi nggedhekake. Kanggo nindakake iki, sampeyan kudu ngumumake kelas ColorPointkanthi lapangan sing cocog color. Mangkono, yen ing kelas lengkap kita nelpon equalscara tiyang sepah, lan ing tiyang sepah kita nganggep mung koordinat xlan dibandhingake y, banjur loro TCTerms saka werna nanging karo koordinat padha bakal dianggep padha, kang ora bener. Ing kasus iki, perlu kanggo ngajar kelas asale kanggo mbedakake warna. Kanggo nindakake iki, sampeyan bisa nggunakake rong cara. Nanging siji bakal nglanggar aturan simetri , lan kaloro - transitivity .
// Первый способ, нарушая симметричность
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof ColorPoint)) return false;
    return super.equals(o) && ((ColorPoint) o).color == color;
}
Ing kasus iki, telpon point.equals(colorPoint)bakal bali Nilai true, lan comparison colorPoint.equals(point)bakal bali false, amarga ngarepake obyek saka "sawijining" kelas. Mangkono, aturan simetri dilanggar. Cara liya melu nindakake mriksa "wuta" ing kasus nalika ora ana data bab werna titik, IE kita duwe kelas Point. Utawa mriksa werna yen informasi bab iku kasedhiya, sing, mbandhingaké obyek saka kelas ColorPoint.
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof Point)) return false;

    // Слепая проверка
    if (!(o instanceof ColorPoint))
        return super.equals(o);

    // Полная проверка, включая цвет точки
    return super.equals(o) && ((ColorPoint) o).color == color;
}
Prinsip transitivity dilanggar ing kene kaya ing ngisor iki. Ayo ngomong ana definisi obyek ing ngisor iki:
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
Mangkono, senadyan podo p1.equals(p2)lan wareg p2.equals(p3), p1.equals(p3)iku bakal bali Nilai false. Ing wektu sing padha, cara liya, miturut pendapatku, katon kurang atraktif, amarga Ing sawetara kasus, algoritma bisa uga wuta lan ora nindakake perbandingan kanthi lengkap, lan sampeyan bisa uga ora ngerti babagan iki. A dicokot saka puisi Umumé, aku ngerti, ora ana solusi konkrit kanggo masalah iki. Ana panemu saka siji penulis sing duwe wewenang sing jenenge Kay Horstmann yen sampeyan bisa ngganti panggunaan operator kasebut instanceofkanthi telpon metode getClass()sing ngasilake kelas obyek kasebut lan, sadurunge sampeyan mbandhingake obyek kasebut, priksa manawa ana jinis sing padha. , lan ora nggatekake kasunyatan asal-usule. Mangkono, aturan simetri lan transitivity bakal wareg. Nanging ing wektu sing padha, ing sisih liya barricade ana penulis liyane, ora kurang dihormati ing bunderan sudhut, Joshua Bloch, sing pracaya pendekatan iki nglanggar prinsip substitusi Barbara Liskov. Prinsip iki nyatakake yen "kode panggilan kudu nganggep kelas dhasar kanthi cara sing padha karo subkelas tanpa ngerti . " Lan ing solusi sing diusulake dening Horstmann, prinsip iki jelas dilanggar, amarga gumantung saka implementasine. Cekakipun, cetha bilih prakara iku peteng. Sampeyan uga kudu dicathet yen Horstmann njlentrehake aturan kanggo ngetrapake pendekatan lan nulis ing basa Inggris sing jelas yen sampeyan kudu mutusake strategi nalika ngrancang kelas, lan yen pengujian kesetaraan bakal ditindakake mung dening superclass, sampeyan bisa nindakake iki kanthi nindakake. operasi kasebut instanceof. Yen ora, nalika semantik mriksa owah-owahan gumantung saka kelas sing diturunake lan implementasine metode kasebut kudu dipindhah mudhun hirarki, sampeyan kudu nggunakake metode getClass(). Joshua Bloch, ing siji, ngusulake kanggo ninggalake warisan lan nggunakake komposisi obyek dening kalebu ColorPointkelas ing kelas Pointlan nyediakake cara akses asPoint()kanggo njupuk informasi khusus bab titik. Iki bakal supaya ora nglanggar kabeh aturan, nanging, ing mratelakake panemume, iku bakal nggawe kode luwih angel kanggo ngerti. Pilihan katelu nggunakake generasi otomatis saka cara padha nggunakake IDE. Idea, kanthi cara, ngasilake generasi Horstmann, ngidini sampeyan milih strategi kanggo ngetrapake metode ing superclass utawa ing turunane. Pungkasan, aturan konsistensi sabanjure nyatakake yen obyek kasebut xora yowah, nelpon maneh x.equals(y)kudu ngasilake nilai sing padha karo sadurunge. Aturan pungkasan yaiku ora ana obyek sing padha karo null. Kabeh wis jelas ing kene null- iki kahanan sing durung mesthi, apa obyek kasebut padha karo kahanan sing durung mesthi? Ora jelas, yaiku false.

Algoritma umum kanggo nemtokake padha

  1. Priksa kesetaraan referensi obyek thislan paramèter metode o.
    if (this == o) return true;
  2. Priksa manawa link kasebut ditetepake o, yaiku apa null.
    Yen ing mangsa ngarep, nalika mbandhingake jinis obyek, operator bakal digunakake instanceof, item iki bisa dilewati, amarga parameter iki bali falseing kasus iki null instanceof Object.
  3. Mbandhingake jinis obyek thisnggunakake ooperator instanceofutawa metode getClass(), dipandu dening katrangan ing ndhuwur lan intuisi sampeyan dhewe.
  4. Yen cara equalsditindhes ing subkelas, priksa manawa sampeyan nelponsuper.equals(o)
  5. Ngonversi jinis parameter omenyang kelas sing dibutuhake.
  6. Tindakake perbandingan kabeh bidang obyek sing penting:
    • kanggo jinis primitif (kajaba floatlan double), nggunakake operator==
    • kanggo kolom referensi sampeyan kudu nelpon caraequals
    • kanggo susunan, sampeyan bisa nggunakake pengulangan siklik utawa caraArrays.equals()
    • kanggo jinis floatlan doubleiku perlu kanggo nggunakake cara comparison saka kelas pambungkus cocog Float.compare()lanDouble.compare()
  7. Lan pungkasane, wangsulana telung pitakonan: apa metode sing diimplementasine simetris ? Transitif ? Setuju ? Loro prinsip liyane ( refleksivitas lan kepastian ) biasane ditindakake kanthi otomatis.

Aturan nolak HashCode

Hash minangka nomer sing digawe saka obyek sing nggambarake kahanane ing sawetara wektu. Nomer iki digunakake ing Jawa utamane ing tabel hash kayata HashMap. Ing kasus iki, fungsi hash kanggo entuk nomer adhedhasar obyek kudu dileksanakake kanthi cara kanggo njamin distribusi unsur sing relatif rata ing tabel hash. Lan uga kanggo nyilikake kemungkinan tabrakan nalika fungsi ngasilake nilai sing padha kanggo tombol beda.

Kode hash kontrak

Kanggo ngleksanakake fungsi hash, spesifikasi basa nemtokake aturan ing ngisor iki:
  • nelpon cara hashCodeluwih saka sapisan ing obyek padha kudu bali Nilai hash padha, kasedhiya yen kothak obyek melu ngitung Nilai wis ora diganti.
  • nelpon cara hashCodeing rong obyek kudu tansah ngasilake nomer sing padha yen obyek padha (nelpon cara equalsing obyek iki bali true).
  • nelpon cara hashCodeing rong obyek sing ora padha kudu ngasilake nilai hash sing beda. Sanajan syarat iki ora wajib, kudu dianggep yen implementasine bakal duwe efek positif ing kinerja tabel hash.

Cara sing padha lan hashCode kudu diganti bebarengan

Adhedhasar kontrak sing diterangake ing ndhuwur, mula yen ngganti metode ing kode sampeyan equals, sampeyan kudu tansah ngilangi metode kasebut hashCode. Wiwit nyatane loro kedadean saka kelas beda amarga padha ing wilayah memori beda, padha kudu dibandhingake miturut sawetara kritéria logis. Mulane, rong obyek sing padha karo logis kudu ngasilake nilai hash sing padha. Apa sing kedadeyan yen mung siji saka cara kasebut ditimpa?
  1. equalsya hashCodeora

    Contone, kita nemtokake cara kanthi bener equalsing kelas, lan hashCodemutusake kanggo ninggalake metode kasebut kaya sing ana ing kelas Object. Banjur saka sudut pandang metode, equalsrong obyek kasebut bakal padha kanthi logis, dene saka sudut pandang metode hashCodeora ana sing padha. Lan kanthi mangkono, kanthi nempatake obyek ing tabel hash, kita duwe risiko ora bisa bali kanthi kunci.
    Contone, kaya iki:

    Map<Point, String> m = new HashMap<>();
    m.put(new Point(1, 1),Point A);
    // pointName == null
    String pointName = m.get(new Point(1, 1));

    Temenan, obyek sing diselehake lan obyek sing digoleki minangka rong obyek sing beda, sanajan kanthi logis padha. Nanging, amarga padha duwe nilai hash sing beda amarga kita nglanggar kontrak, kita bisa ujar manawa kita ilang obyek ing endi wae ing weteng meja hash.

  2. hashCodeya equalsora.

    Apa sing kedadeyan yen kita ngilangi metode kasebut hashCodelan equalsmarisi implementasine metode kasebut saka kelas Object. Kaya sing sampeyan ngerteni, equalsmetode standar mung mbandhingake penunjuk menyang obyek, nemtokake manawa padha nuduhake obyek sing padha. Ayo nganggep manawa hashCodekita wis nulis cara kasebut miturut kabeh kanon, yaiku, digawe nggunakake IDE, lan bakal ngasilake nilai hash sing padha kanggo obyek sing identik. Temenan, kanthi nindakake iki, kita wis nemtokake sawetara mekanisme kanggo mbandhingake rong obyek.

    Mula, conto saka paragraf sadurunge kudu ditindakake kanthi teori. Nanging kita isih ora bisa nemokake obyek ing tabel hash. Sanajan kita bakal cedhak karo iki, amarga paling sethithik kita bakal nemokake basket meja hash sing obyek kasebut bakal ana.

    Kanggo nggoleki obyek kanthi sukses ing tabel hash, saliyane kanggo mbandhingake nilai hash kunci kasebut, penentuan kesetaraan logis kunci karo obyek sing digoleki uga digunakake. Sing, equalsora ana cara kanggo nindakake tanpa overriding cara.

Algoritma umum kanggo nemtokake kode hash

Kene, misale jek kula, sampeyan kudu ora sumelang banget lan generate cara ing IDE favorit. Amarga kabeh iki owah-owahan saka bit menyang tengen lan kiwa ing panelusuran rasio emas, IE, distribusi normal - iki kanggo bolo rampung wangkal. Wong, Aku sangsi sing aku bisa nindakake luwih apik lan luwih cepet saka Idea padha.

Tinimbang kesimpulan

Mangkono, kita weruh manawa metode equalsnduweni hashCodeperan sing wis ditemtokake ing basa Jawa lan dirancang kanggo entuk karakteristik kesetaraan logis saka rong obyek. Ing kasus metode kasebut, equalsiki nduweni hubungan langsung karo mbandhingake obyek, ing kasus sing hashCodeora langsung, yen perlu, ayo ngomong, kanggo nemtokake lokasi kira-kira obyek ing tabel hash utawa struktur data sing padha supaya bisa nambah kacepetan nggoleki obyek. Saliyane kontrak , equalsana hashCodesyarat liyane sing ana gandhengane karo perbandingan obyek. Iki minangka konsistensi metode compareToantarmuka Comparablekanthi equals. Persyaratan iki mbutuhake pangembang tansah bali x.equals(y) == truenalika x.compareTo(y) == 0. Sing, kita waca sing comparison logis saka rong obyek ngirim ora mbantah ngendi wae ing aplikasi lan kudu tansah konsisten.

Sumber

Jawa Efektif, Edisi Kedua. Joshua Blok. Terjemahan gratis saka buku sing apik banget. Jawa, perpustakaan profesional. Jilid 1. Dasar. Kay Horstmann. A teori sethitik kurang lan laku liyane. Nanging kabeh ora dianalisis kanthi rinci kaya Bloch. Senajan ana tampilan ing padha (). Struktur data ing gambar. HashMap Artikel sing migunani banget ing piranti HashMap ing Jawa. Tinimbang ndeleng sumber.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION