Manakah dari berikut ini yang lebih baik?
a instanceof B
atau
B.class.isAssignableFrom(a.getClass())
Satu-satunya perbedaan yang saya tahu adalah, ketika 'a' adalah null, yang pertama mengembalikan false, sedangkan yang kedua melempar pengecualian. Selain itu, apakah mereka selalu memberikan hasil yang sama?
java
instanceof
reflection
Megamug
sumber
sumber
Jawaban:
Saat menggunakan
instanceof
, Anda perlu mengetahui kelasB
pada waktu kompilasi. Saat menggunakannyaisAssignableFrom()
bisa dinamis dan berubah saat runtime.sumber
a instanceof Bref.getClass()
. bagaimana ini bisa menjadi jawaban yang diterima dengan sedikit penjelasan (atau ketiadaannya)?a instanceof Bref
tidaka instanceof Bref.class
. Argumen kedua ke instance dari operator adalah nama kelas, bukan ekspresi yang menyelesaikan ke instance objek kelas.B.class.isAssignableFrom(a.getClass())
, B dikenal, dana instanceof B
lebih baik. Baik?instanceof
hanya dapat digunakan dengan tipe referensi, bukan tipe primitif.isAssignableFrom()
dapat digunakan dengan objek kelas apa saja:Lihat http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
sumber
Berbicara dalam hal kinerja:
TL; DR
Gunakan Instance atau instanceof yang memiliki kinerja serupa. isAssignableFrom sedikit lebih lambat.
Diurutkan berdasarkan kinerja:
Berdasarkan tolok ukur 2000 iterasi pada JAVA 8 Windows x64, dengan 20 iterasi pemanasan.
Dalam teori
Dengan menggunakan bytecode viewer yang lembut, kita dapat menerjemahkan masing-masing operator menjadi bytecode.
Dalam konteks:
JAWA:
Bytecode:
JAWA:
Bytecode:
JAWA:
Bytecode:
Mengukur berapa banyak instruksi bytecode yang digunakan oleh masing-masing operator, kita dapat mengharapkan instance dan Instance menjadi lebih cepat daripada IssignableFrom . Namun, kinerja aktual TIDAK ditentukan oleh bytecode tetapi oleh kode mesin (yang bergantung pada platform). Mari kita lakukan patokan mikro untuk masing-masing operator.
Patokan
Kredit: Seperti yang disarankan oleh @ aleksandr-dubinsky, dan terima kasih kepada @yura untuk memberikan kode dasar, berikut ini adalah patokan JMH (lihat panduan tuning ini ):
Memberi hasil berikut (skor adalah sejumlah operasi dalam satuan waktu , sehingga semakin tinggi skor semakin baik):
Peringatan
instanceof
dalam konteks kode Anda mungkin dioptimalkan lebih mudah daripadaisInstance
misalnya ...Untuk memberi Anda contoh, ambil loop berikut:
Berkat JIT, kode ini dioptimalkan pada beberapa titik dan kami mendapatkan:
Catatan
Awalnya posting ini sedang melakukan benchmark sendiri menggunakan for loop di JAWA mentah, yang memberikan hasil tidak dapat diandalkan karena beberapa optimasi seperti Just In Time dapat menghilangkan loop. Jadi sebagian besar mengukur berapa lama yang dibutuhkan kompiler JIT untuk mengoptimalkan loop: lihat Tes kinerja terlepas dari jumlah iterasi untuk lebih jelasnya
Pertanyaan-pertanyaan Terkait
sumber
instanceof
adalah bytecode yang pada dasarnya menggunakan logika yang sama dengancheckcast
(bytecode di belakang casting). Secara inheren akan lebih cepat daripada opsi lain, terlepas dari tingkat optimasi JITC.isAssignableFrom()
dinamis.Setara dengan lebih langsung
a instanceof B
adalahKarya ini (kembali palsu) saat
a
ininull
juga.sumber
Terlepas dari perbedaan dasar yang disebutkan di atas, ada perbedaan halus inti antara instanceof operator dan metodeAssignableFrom di Kelas.
Baca
instanceof
sebagai "apakah ini (bagian kiri) adalah contoh dari ini atau setiap subkelas dari ini (bagian kanan)" dan dibacax.getClass().isAssignableFrom(Y.class)
sebagai "Dapatkah saya menulisX x = new Y()
". Dengan kata lain, instanceof operator memeriksa apakah objek kiri sama atau subkelas dari kelas kanan, sementaraisAssignableFrom
memeriksa apakah kita dapat menetapkan objek dari kelas parameter (dari) ke referensi kelas di mana metode ini dipanggil.Perhatikan bahwa keduanya menganggap instance aktual bukan tipe referensi.
Pertimbangkan contoh 3 kelas A, B dan C di mana C meluas B dan B meluas A.
sumber
b instanceof A
setara denganA.class.isAssignableFrom(b.getClass())
(seperti OP perhatikan). Teladan Anda benar tetapi tidak relevan.new Y()
mungkin tidak legal jikaY
abstrak atau tanpa konstruktor default publik, Anda dapat mengatakanX x = (Y)null
legal jika dan hanya jikax.getClass().isAssignableFrom(Y.class)
benar.Ada juga perbedaan lain:
null instanceof X
false
tidak peduli apa Xnull.getClass (). isAssignableFrom (X) akan melempar NullPointerException
sumber
null instanceof X
(di mana X adalah beberapa kelas yang dikenal pada waktu kompilasi) akan selalu kembalifalse
.X.class.isAssignableFrom(null.getClass())
seharusnya tidak? Tapi ya, memanggilgetClass()
referensi nol akan menghasilkan NPE.getClass()
tidak boleh digunakan denganisAssignableFrom
di tempat pertama - operasi ini dimaksudkan untuk situasi yang tidak memiliki objek. Jika Anda memiliki referensi obyeka
, penggunaana instanceof SomeClass
(jika Anda melakukan tahu jenisSomeClass
) atausomeObject.getClass().isInstance(a)
(jika Anda tidak tahu jenissomeObject
).Masih ada perbedaan lain. Jika tipe (Kelas) yang diuji melawan bersifat dinamis, misal diteruskan sebagai parameter metode, maka instanceof tidak akan memotongnya untuk Anda.
tetapi Anda dapat melakukannya:
Ups, saya melihat jawaban ini sudah dibahas. Mungkin contoh ini bermanfaat bagi seseorang.
sumber
this
),clazz.isInstance(this)
akan lebih baik dalam contoh Anda.Utas ini memberi saya beberapa wawasan tentang
instanceof
perbedaannyaisAssignableFrom
, jadi saya pikir saya akan membagikan sesuatu milik saya sendiri.Saya telah menemukan bahwa menggunakan
isAssignableFrom
menjadi satu-satunya (mungkin bukan satu-satunya, tetapi mungkin cara termudah) untuk bertanya pada diri sendiri apakah referensi dari satu kelas dapat mengambil contoh dari yang lain, ketika seseorang memiliki contoh dari kedua kelas untuk melakukan perbandingan.Oleh karena itu, saya tidak menemukan menggunakan
instanceof
operator untuk membandingkan penugasan untuk menjadi ide yang baik ketika semua yang saya miliki adalah kelas, kecuali saya berpikir untuk membuat instance dari salah satu kelas; Saya pikir ini akan menjadi ceroboh.sumber
instanceof tidak dapat digunakan dengan tipe primitif atau tipe generik. Seperti dalam kode berikut:
Kesalahannya adalah: Tidak dapat melakukan instanceof terhadap parameter tipe T. Gunakan objek penghapusan itu sebagai gantinya karena informasi tipe umum lebih lanjut akan dihapus saat runtime.
Tidak dikompilasi karena penghapusan tipe menghapus referensi runtime. Namun, kode di bawah ini akan mengkompilasi:
sumber
Pertimbangkan situasi berikut. Misalkan Anda ingin memeriksa apakah tipe A adalah kelas super dari jenis obj, Anda dapat memilih salah satu
... A.class.isAssignableFrom (obj.getClass ()) ...
ATAU
... obj contoh dari A ...
Tetapi solusi isAssignableFrom mengharuskan jenis objek terlihat di sini. Jika ini bukan masalahnya (misalnya, jenis keberatan mungkin dari kelas dalam pribadi), opsi ini keluar. Namun, solusi instance akan selalu bekerja.
sumber
obj
dalam contoh ini) dari jenis apa pun maka Anda dapat memanggilgetClass()
metode publik di atasnya untuk mendapatkan metadata refleksi untuk kelas pelaksana. Ini benar bahkan jika tipe kelas implementasi itu tidak akan terlihat secara hukum di lokasi itu pada waktu kompilasi. Tidak apa-apa saat runtime karena, bagi Anda untuk memegangobj
referensi, beberapa jalur kode yang akhirnya memang memiliki akses legal ke kelas yang dibuat dan memberikan (bocor?) Kepada Anda.Kode pseudo di atas adalah definisi, jika referensi tipe / kelas A dapat diberikan dari referensi tipe / kelas B. Ini adalah definisi rekursif. Bagi sebagian orang mungkin bermanfaat, bagi yang lain mungkin membingungkan. Saya menambahkannya kalau-kalau ada yang merasa berguna. Ini hanya upaya untuk menangkap pemahaman saya, itu bukan definisi resmi. Ini digunakan dalam implementasi Java VM tertentu dan berfungsi untuk banyak contoh program, jadi sementara saya tidak dapat menjamin bahwa ia menangkap semua aspek isAssignableFrom, itu tidak sepenuhnya mati.
sumber
Berbicara dalam hal kinerja "2" (dengan JMH):
Memberikan:
Sehingga kita dapat menyimpulkan: instanceof secepat isinstance () dan isAssignableFrom () tidak jauh (+ 0,9% waktu executon). Jadi tidak ada perbedaan nyata apa pun yang Anda pilih
sumber
Bagaimana dengan beberapa contoh untuk menunjukkannya dalam aksi ...
sumber
beberapa tes yang kami lakukan di tim kami menunjukkan bahwa
A.class.isAssignableFrom(B.getClass())
bekerja lebih cepat daripadaB instanceof A
. ini bisa sangat berguna jika Anda perlu memeriksa ini pada sejumlah besar elemen.sumber
instanceof
, saya percaya Anda memiliki masalah desain yang serius ...