Saya menggunakan Eclipse untuk menghasilkan .equals()
dan .hashCode()
, dan ada opsi berlabel "Gunakan 'instanceof' untuk membandingkan jenis". Defaultnya adalah opsi ini tidak dicentang dan digunakan .getClass()
untuk membandingkan jenis. Apakah ada alasan aku harus lebih .getClass()
lebih instanceof
?
Tanpa menggunakan instanceof
:
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Menggunakan instanceof
:
if (obj == null)
return false;
if (!(obj instanceof MyClass))
return false;
Saya biasanya memeriksa instanceof
opsi, lalu masuk dan menghapus if (obj == null)
centang " ". (Itu mubazir karena objek nol akan selalu gagal instanceof
.) Apakah ada alasan itu ide yang buruk?
java
eclipse
equals
instanceof
Tidur
sumber
sumber
x instanceof SomeClass
salah jikax
itunull
. Oleh karena itu, sintaks kedua tidak memerlukan pemeriksaan nol.Jawaban:
Jika Anda menggunakan
instanceof
, membuat Andaequals
pelaksanaannyafinal
akan melestarikan kontrak simetri metode:x.equals(y) == y.equals(x)
. Jikafinal
tampaknya membatasi, hati-hati memeriksa gagasan Anda tentang kesetaraan objek untuk memastikan bahwa implementasi utama Anda sepenuhnya mempertahankan kontrak yang ditetapkan olehObject
kelas.sumber
final
tampaknya membatasi" (pada keduanyaequals
danhashCode
) kemudian gunakangetClass()
kesetaraan alih-alihinstanceof
untuk menjaga persyaratan simetri dan transitivitasequals
kontrak.Josh Bloch mendukung pendekatan Anda:
Lihat juga jawaban SO ini .
Java bab 3 yang efektif juga membahas hal ini.
sumber
getClass
tidak melanggar LSP, karena LSP hanya terkait dengan apa yang dapat dilakukan dengan instance yang ada - bukan jenis instance apa yang dapat dibangun. Kelas yang dikembalikan olehgetClass
adalah properti yang tidak dapat diubah dari instance objek. LSP tidak menyiratkan bahwa harus dimungkinkan untuk membuat subclass di mana properti itu menunjukkan kelas apa pun selain yang membuatnya.Angelika Langers Rahasia yang sederajat membahas hal itu dengan diskusi panjang dan terperinci untuk beberapa contoh umum dan terkenal, termasuk oleh Josh Bloch dan Barbara Liskov, menemukan beberapa masalah di sebagian besar dari mereka. Dia juga masuk ke dalam
instanceof
vsgetClass
. Beberapa kutipan darinyasumber
Alasan penggunaannya
getClass
adalah untuk memastikan properti simetris dariequals
kontrak. Dari equals 'JavaDocs:Dengan menggunakan instanceof, mungkin tidak simetris. Perhatikan contohnya: Anjing memanjang Hewan. Animal
equals
melakukaninstanceof
pengecekan Animal. Anjingequals
tidak sebuahinstanceof
cek dari anjing. Berikan Animal sebuah and Dog d (dengan bidang lain yang sama):Ini melanggar properti simetris.
Untuk benar-benar mengikuti kontrak equal, simetri harus dipastikan, dan karenanya kelas harus sama.
sumber
a.equals(c)
danb.equals(c)
, kemudiana.equals(b)
(pendekatan naif untuk membuat kapanDog.equals
saja tetapi memeriksa bidang tambahan ketika itu adalah contoh Anjing tidak akan melanggar simetri tetapi akan melanggar transitivitas)return super.equals(object)
!(object instanceof Dog)
getClass()
cek kesetaraan, atau Anda bisa menggunakaninstanceof
cek jika Andaequals
danhashCode
metodefinal
.Ini adalah semacam perdebatan agama. Kedua pendekatan memiliki masalah mereka.
Bloch memiliki saran lain yang relevan dalam Effective Java Second Edition :
sumber
getClass
akan melanggar LSP, kecuali kelas dasar secara khusus mendokumentasikan sarana yang memungkinkan untuk membuat instance dari subclass berbeda yang membandingkan sama. Pelanggaran LSP apa yang Anda lihat?getClass()
tidak boleh dianggap bermakna di luar fakta bahwa kelas tersebut dapat dikonversi ke kelas dasar, pengembalian darigetClass()
harus dianggap seperti properti lainnya yang harus cocok untuk instance yang sama.Perbaiki saya jika saya salah, tetapi getClass () akan berguna ketika Anda ingin memastikan instance Anda BUKAN subkelas dari kelas yang Anda bandingkan. Jika Anda menggunakan instanceof dalam situasi itu Anda TIDAK bisa tahu itu karena:
sumber
Jika Anda ingin memastikan hanya kelas yang cocok maka gunakan
getClass() ==
. Jika Anda ingin mencocokkan subclass makainstanceof
diperlukan.Juga, instanceof tidak akan cocok dengan nol tetapi aman untuk dibandingkan dengan nol. Jadi Anda tidak perlu membatalkannya.
sumber
Itu tergantung jika Anda mempertimbangkan apakah subkelas dari kelas yang diberikan sama dengan induknya.
di sini saya akan menggunakan 'instanceof', karena saya ingin LastName dibandingkan dengan FamilyName
di sini saya akan menggunakan 'getClass', karena kelas sudah mengatakan bahwa dua instance tidak setara.
sumber
instanceof berfungsi untuk instance dari kelas yang sama atau subkelasnya
ArryaList dan RoleList keduanya adalah instance dari List
Sementara
getClass () == o.getClass () akan benar hanya jika kedua objek (ini dan o) milik kelas yang persis sama.
Jadi tergantung pada apa yang Anda perlu membandingkan Anda bisa menggunakan satu atau yang lain.
Jika logika Anda adalah: "Satu objek sama dengan yang lain hanya jika mereka berdua kelas yang sama" Anda harus pergi untuk "sama", yang saya pikir sebagian besar kasus.
sumber
Kedua metode memiliki masalah mereka.
Jika subkelas mengubah identitas, maka Anda perlu membandingkan kelas mereka yang sebenarnya. Jika tidak, Anda melanggar properti simetris. Misalnya, berbagai jenis
Person
s tidak boleh dianggap setara, bahkan jika mereka memiliki nama yang sama.Namun, beberapa subclass tidak mengubah identitas dan ini perlu digunakan
instanceof
. Sebagai contoh, jika kita memiliki banyakShape
objek yang tidak dapat diubah , maka aRectangle
dengan panjang dan lebar 1 harus sama dengan unitSquare
.Dalam praktiknya, saya pikir kasus sebelumnya lebih mungkin benar. Biasanya, subclassing adalah bagian mendasar dari identitas Anda dan menjadi persis seperti orang tua Anda, kecuali Anda dapat melakukan satu hal kecil tidak membuat Anda sama.
sumber
Sebenarnya instanceof memeriksa di mana objek milik beberapa hierarki atau tidak. mis: Objek mobil milik kelas Vehical. Jadi "Mobil baru () instance dari Vehical" mengembalikan true. Dan "Mobil baru (). GetClass (). Sama dengan (Vehical.class)" mengembalikan false, meskipun objek Mobil milik kelas Vehical tetapi dikategorikan sebagai tipe yang terpisah.
sumber