Mengapa variabel "Kelas" tidak dapat diteruskan ke instanceof?

89

Mengapa kode ini tidak dapat dikompilasi?

    public boolean isOf(Class clazz, Object obj){
        if(obj instanceof clazz){
            return true;
        }else{
            return false;
        }
    }

Mengapa saya tidak bisa meneruskan variabel kelas ke instanceof?

eric2323223
sumber

Jawaban:

131

The instanceofOperator bekerja pada jenis referensi, seperti Integer, dan bukan pada objek, seperti new Integer(213). Anda mungkin menginginkan sesuatu seperti

clazz.isInstance(obj)

Catatan tambahan: kode Anda akan lebih ringkas jika Anda menulis

public boolean isOf(Class clazz, Object obj){
    return clazz.isInstance(obj)
}

Tidak terlalu yakin apakah Anda membutuhkan metode lagi.

Robert Munteanu
sumber
Saya tahu kodenya sama sekali tidak berguna, saya hanya ingin menunjukkan kebingungan saya :)
eric2323223
6
Integeradalah tidak literal kelas. Integer.classakan menjadi literal kelas (lihat § 15.8.2 dari JLS: java.sun.com/docs/books/jls/third_edition/html/… ). The instanceofOperator mengambil "ReferenceType" (alias nama jenis) seperti yang ditentukan § 15.20.2 dari JLS: java.sun.com/docs/books/jls/third_edition/html/...
Joachim Sauer
3
Saya akan menggunakan clazz.isInstance(obj)karena objek sudah disediakan.
Donal Fellows
13

instanceofhanya dapat digunakan dengan nama kelas eksplisit (dinyatakan pada waktu kompilasi). Untuk melakukan pemeriksaan runtime , Anda harus melakukan:

clazz.isInstance(obj)

Ini memiliki keuntungan kecil clazz.isAssignableFrom(..)karena menangani kasus dengan obj == nulllebih baik.

Eyal Schneider
sumber
5

Seperti yang telah disebutkan orang lain, Anda tidak dapat mengirimkan variabel kelas ke instanceofkarena variabel kelas mereferensikan instance dari Objek , sedangkan tangan kanan instanceofharus berupa tipe . Artinya, instanceoftidak berarti "y adalah turunan dari Objek x", itu berarti "y adalah turunan dari tipe X". Jika Anda tidak tahu perbedaan antara Objek dan tipe, pertimbangkan:

Object o = new Object();

Di sini, tipenya adalah Object, dan omerupakan referensi ke instance Objek dengan tipe itu. Jadi:

if(o instanceof Object)

valid tapi

if(o instanceof o)

bukan karena odi sisi kanan adalah Object, bukan tipe.

Lebih spesifik untuk kasus Anda, instance kelas bukanlah tipe, itu adalah Objek (yang dibuat untuk Anda oleh JVM). Dalam metode Anda, Classadalah tipe, tetapi clazzmerupakan Objek (yah, referensi ke Objek)

Yang Anda butuhkan adalah cara untuk membandingkan Objek dengan Objek Kelas. Ternyata ini populer jadi ini disediakan untuk Anda sebagai metode Object Kelas: isInstance().

Berikut adalah Java Doc untuk isInstance, yang menjelaskan hal ini dengan lebih baik:

public boolean isInstance(Object obj)

Menentukan apakah Objek yang ditentukan kompatibel dengan tugas dengan objek yang diwakili oleh Kelas ini. Metode ini adalah padanan dinamis dari operator instanceof bahasa Java. Metode ini mengembalikan nilai true jika argumen Objek yang ditentukan adalah bukan nol dan dapat dilemparkan ke tipe referensi yang diwakili oleh objek Kelas ini tanpa memunculkan ClassCastException. Ia mengembalikan false jika tidak.

Secara khusus, jika objek Kelas ini mewakili kelas yang dideklarasikan, metode ini mengembalikan nilai true jika argumen Objek yang ditentukan adalah turunan dari kelas yang diwakili (atau salah satu subkelasnya); itu mengembalikan false jika tidak. Jika objek Kelas ini mewakili kelas larik, metode ini mengembalikan nilai true jika argumen Objek yang ditentukan dapat diubah menjadi objek dari kelas larik dengan konversi identitas atau dengan konversi referensi yang melebar; itu mengembalikan false jika tidak. Jika objek Kelas ini mewakili antarmuka, metode ini mengembalikan nilai true jika kelas atau superclass apa pun dari argumen Objek yang ditentukan mengimplementasikan antarmuka ini; itu mengembalikan false jika tidak. Jika objek Kelas ini mewakili tipe primitif, metode ini mengembalikan nilai salah.

Parameter: obj - objek untuk diperiksa
Returns: true jika obj adalah turunan dari kelas ini
Sejak: JDK1.1

Rick Hanlon II
sumber
3

Pertama, instanceofmensyaratkan bahwa operan di sebelah kanan adalah kelas aktual (misalnya obj instanceof Objectatau obj instanceof Integer) dan bukan variabel tipe Class. Kedua, Anda telah membuat kesalahan pemula yang cukup umum yang seharusnya tidak Anda lakukan ... pola berikut:

if ( conditional_expression ) {
    kembali benar;
} lain{
    return false;
}

Hal di atas dapat direfraktor menjadi:

return conditional_expression ;

Anda harus selalu melakukan pemfaktoran ulang itu, karena ini menghilangkan pernyataan if ... else yang berlebihan. Demikian pula, ekspresi tersebut dapat diubah menjadi hasil yang sama.return conditional_expression ? true : false;

Michael Aaron Safyan
sumber
2
Itu tidak salah. Mungkin kikuk tapi total oke. Mungkin Anda menginginkan kode tambahan sebelum kembali di masa mendatang ...
Tanggal