equals
sing hashCode
raket 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 caraequals()
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, equals
sampeyan 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
- Nalika nyatane kelas kasebut ora dibutuhake kanggo nemtokake kesetaraan saka kedadeyan kasebut. Contone, kanggo kelas
- Nalika kelas sampeyan ndawakake wis duwe implementasine dhewe saka cara
equals
lan prilaku implementasine iki cocog karo sampeyan. Contone, kanggo kelas - Lan pungkasanipun, ana ora perlu kanggo override
equals
nalika orane katrangan saka kelasprivate
utawapackage-private
lan sampeyan manawa ing cara iki ora bakal disebut.
Thread
. Kanggo dheweke equals
, implementasine metode sing diwenehake dening kelas Object
luwih saka cukup. Conto liyane yaiku kelas enum ( Enum
).
java.util.Random
ana 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.
Set
, List
, Map
implementasine equals
ing AbstractSet
, AbstractList
lan AbstractMap
mungguh.
padha kontrak
Nalika ngatasi cara,equals
pangembang kudu netepi aturan dhasar sing ditetepake ing spesifikasi basa Jawa.
- Refleksivity kanggo sembarang nilai tartamtu
- simetri kanggo sembarang nilai tartamtu
- Transitivity kanggo sembarang nilai diwenehi
- Konsistensi kanggo sembarang nilai diwenehi,
- Perbandingan null kanggo sembarang nilai tartamtu
x
, expression x.equals(x)
kudu bali true
.
Diwenehi - tegese kuwi
x != null
x
lan y
, x.equals(y)
kudu bali true
mung yen y.equals(x)
bali true
.
x
, y
lan z
, yen x.equals(y)
bali true
lan y.equals(z)
bali true
, x.equals(z)
kudu bali Nilai true
.
x
lan y
telpon 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.
x
telpon x.equals(null)
kudu bali false
.
padha karo nglanggar kontrak
Akeh kelas, kayata saka Java Collections Framework, gumantung saka implementasine metode kasebutequals()
, 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é equals
lapangan 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 Point
karo koordinat x
lan y
sampeyan kudu nambah werna titik kanthi nggedhekake. Kanggo nindakake iki, sampeyan kudu ngumumake kelas ColorPoint
kanthi lapangan sing cocog color
. Mangkono, yen ing kelas lengkap kita nelpon equals
cara tiyang sepah, lan ing tiyang sepah kita nganggep mung koordinat x
lan 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 instanceof
kanthi 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 ColorPoint
kelas ing kelas Point
lan 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 x
ora y
owah, 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
- Priksa kesetaraan referensi obyek
this
lan paramèter metodeo
.if (this == o) return true;
- Priksa manawa link kasebut ditetepake
o
, yaiku apanull
.
Yen ing mangsa ngarep, nalika mbandhingake jinis obyek, operator bakal digunakakeinstanceof
, item iki bisa dilewati, amarga parameter iki balifalse
ing kasus ikinull instanceof Object
. - Mbandhingake jinis obyek
this
nggunakakeo
operatorinstanceof
utawa metodegetClass()
, dipandu dening katrangan ing ndhuwur lan intuisi sampeyan dhewe. - Yen cara
equals
ditindhes ing subkelas, priksa manawa sampeyan nelponsuper.equals(o)
- Ngonversi jinis parameter
o
menyang kelas sing dibutuhake. - Tindakake perbandingan kabeh bidang obyek sing penting:
- kanggo jinis primitif (kajaba
float
landouble
), nggunakake operator==
- kanggo kolom referensi sampeyan kudu nelpon cara
equals
- kanggo susunan, sampeyan bisa nggunakake pengulangan siklik utawa cara
Arrays.equals()
- kanggo jinis
float
landouble
iku perlu kanggo nggunakake cara comparison saka kelas pambungkus cocogFloat.compare()
lanDouble.compare()
- kanggo jinis primitif (kajaba
- 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 kayataHashMap
. 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
hashCode
luwih saka sapisan ing obyek padha kudu bali Nilai hash padha, kasedhiya yen kothak obyek melu ngitung Nilai wis ora diganti. - nelpon cara
hashCode
ing rong obyek kudu tansah ngasilake nomer sing padha yen obyek padha (nelpon caraequals
ing obyek iki balitrue
). - nelpon cara
hashCode
ing 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 sampeyanequals
, 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?
-
equals
yahashCode
oraContone, kita nemtokake cara kanthi bener
equals
ing kelas, lanhashCode
mutusake kanggo ninggalake metode kasebut kaya sing ana ing kelasObject
. Banjur saka sudut pandang metode,equals
rong obyek kasebut bakal padha kanthi logis, dene saka sudut pandang metodehashCode
ora 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.
-
hashCode
yaequals
ora.Apa sing kedadeyan yen kita ngilangi metode kasebut
hashCode
lanequals
marisi implementasine metode kasebut saka kelasObject
. Kaya sing sampeyan ngerteni,equals
metode standar mung mbandhingake penunjuk menyang obyek, nemtokake manawa padha nuduhake obyek sing padha. Ayo nganggep manawahashCode
kita 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,
equals
ora 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 metodeequals
nduweni hashCode
peran sing wis ditemtokake ing basa Jawa lan dirancang kanggo entuk karakteristik kesetaraan logis saka rong obyek. Ing kasus metode kasebut, equals
iki nduweni hubungan langsung karo mbandhingake obyek, ing kasus sing hashCode
ora 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 , equals
ana hashCode
syarat liyane sing ana gandhengane karo perbandingan obyek. Iki minangka konsistensi metode compareTo
antarmuka Comparable
kanthi equals
. Persyaratan iki mbutuhake pangembang tansah bali x.equals(y) == true
nalika x.compareTo(y) == 0
. Sing, kita waca sing comparison logis saka rong obyek ngirim ora mbantah ngendi wae ing aplikasi lan kudu tansah konsisten.
GO TO FULL VERSION