Refleksi array Java: isArray vs instanceof

177

Apakah ada perbedaan preferensi atau perilaku antara menggunakan:

if(obj.getClass().isArray()) {}

dan

if(obj instanceof Object[]) {}

?

David Citron
sumber

Jawaban:

203

Dalam kebanyakan kasus, Anda harus menggunakan instanceofoperator untuk menguji apakah suatu objek adalah sebuah array.

Secara umum, Anda menguji jenis objek sebelum menurunkan ke jenis tertentu yang dikenal pada waktu kompilasi. Sebagai contoh, mungkin Anda menulis beberapa kode yang dapat bekerja dengan a Integer[]atau a int[]. Anda ingin menjaga gips Anda dengan instanceof:

if (obj instanceof Integer[]) {
    Integer[] array = (Integer[]) obj;
    /* Use the boxed array */
} else if (obj instanceof int[]) {
    int[] array = (int[]) obj;
    /* Use the primitive array */
} else ...

Pada tingkat JVM, instanceofoperator menerjemahkan ke kode byte "instanceof" tertentu , yang dioptimalkan di sebagian besar implementasi JVM.

Dalam kasus yang lebih jarang, Anda mungkin menggunakan refleksi untuk menelusuri grafik objek dari tipe yang tidak dikenal. Dalam kasus seperti ini, isArray()metode ini dapat membantu karena Anda tidak tahu tipe komponen pada waktu kompilasi; Anda mungkin, misalnya, menerapkan semacam mekanisme serialisasi dan dapat meneruskan setiap komponen array ke metode serialisasi yang sama, apa pun jenisnya.

Ada dua kasus khusus: referensi nol dan referensi ke array primitif.

Referensi nol akan menyebabkan instanceofhasil false, sedangkan isArraylemparan a NullPointerException.

Diterapkan ke array primitif, instanceofhasil falsekecuali jenis komponen pada operan kanan sama persis dengan jenis komponen. Sebaliknya, isArray()akan kembali trueuntuk semua jenis komponen.

erickson
sumber
7
Ya, tapi berapa banyak perbedaan yang akan terjadi? Itu kedengarannya seperti optimasi mikro bagi saya.
Michael Myers
2
@Dims Jika Anda menegaskan bahwa obj instanceof int[]hasil falseketika Anda menetapkan int[]untuk obj, Anda keliru.
erickson
4
Maaf saya maksudkan itu obj instanceof Object[]menghasilkan falsejika Object obj = new int[7].
Dims
3
Benar, di Jawa, tipe data primitif bukanlah objek, dan tidak diperluas java.lang.Object, sehingga masuk akal. Tetapi instanceofmasih bisa digunakan untuk menguji array primitif.
erickson
4
-1: Secara umum, karena array primitif adalah array, panggilan isArray()harus digunakan. Dalam kasus khusus yang sangat tidak umum hanya memiliki array objek, instanceofmemberikan alternatif kinerja tinggi.
Sam Harwell
33

Dalam kasus terakhir, jika obj adalah nol, Anda tidak akan mendapatkan NullPointerException tetapi false.

Burkhard
sumber
8

Jika objbertipe int[]say, maka itu akan memiliki array Classtetapi tidak menjadi turunan dari Object[]. Jadi apa yang ingin Anda lakukan obj. Jika Anda akan melemparkannya, ikuti instanceof. Jika Anda akan menggunakan refleksi, gunakan .getClass().isArray().

Tom Hawtin - tackline
sumber
4

getClass().isArray() secara signifikan lebih lambat di Sun Java 5 atau 6 JRE daripada di IBM.

Begitu banyak menggunakan clazz.getName().charAt(0) == '['itu lebih cepat di Sun JVM.

Sebastien Tardif
sumber
10
Apakah Anda memiliki statistik, studi kasus, atau bukti lain yang dapat Anda tautkan?
David Citron
4

Baru-baru ini saya mengalami masalah dalam memutakhirkan aplikasi Groovy dari JDK 5 ke JDK 6. Penggunaan isArray()gagal di JDK6:

MissingMethodException:
No signature of sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl.isArray() ...

Mengubah untuk instanceof Object[]memperbaiki ini.

dturanski
sumber
Ini tidak masuk akal. isArrayadalah metode Class, tidak Type, jadi tentu saja GenericArrayTypeImpltidak memiliki metode itu. Dan getClasstidak pernah dapat mengembalikan non- Class Type, jadi Anda (atau Groovy ??) pasti telah melakukan kesalahan untuk mendapatkan ini, seperti menganggap setiap Typeis a Class.
kaqqao
3

Refleksi array Java adalah untuk kasus-kasus di mana Anda tidak memiliki instance Kelas yang tersedia untuk melakukan "instanceof" pada. Misalnya, jika Anda menulis semacam kerangka injeksi, yang menyuntikkan nilai ke instance kelas baru, seperti yang dilakukan JPA, maka Anda perlu menggunakan fungsionalitas isArray ().

Saya menulis blog tentang ini pada awal Desember. http://blog.adamsbros.org/2010/12/08/java-array-reflection/

Trenton D. Adams
sumber
2

Jika Anda pernah memiliki pilihan antara solusi reflektif dan solusi non-reflektif, jangan pernah memilih yang reflektif (melibatkan objek Class). Bukannya itu "salah" atau apa pun, tetapi apa pun yang melibatkan refleksi umumnya kurang jelas dan kurang jelas.

Bill K.
sumber
Er, well, "instanceof" adalah semacam refleksi (atau, setidaknya, introspeksi) juga, tapi saya mengerti maksud Anda.
David Citron
Juga, umumnya lebih lambat.
Fisikawan Gila
0

Tidak ada perbedaan dalam perilaku yang saya dapat temukan di antara keduanya (selain dari null-case yang jelas). Mengenai versi mana yang lebih disukai, saya akan memilih yang kedua. Ini adalah cara standar untuk melakukan ini di Jawa.

Jika itu membingungkan pembaca kode Anda (karena String[] instanceof Object[]itu benar), Anda mungkin ingin menggunakan yang pertama untuk lebih eksplisit jika pengulas kode terus bertanya tentang hal itu.

hazzen
sumber