Apakah pemeriksaan nol diperlukan sebelum memanggil instanceof?

1354

Akan null instanceof SomeClasskembali falseatau melempar NullPointerException?

Johan Lübcke
sumber
Ini juga 'penting' atau paling tidak sangat berguna sebagai garis awal 'praktik terbaik' (atau sangat awal) untuk untuk Bandingkan atau Sama atau metode serupa yang dirancang untuk hanya berhasil pada objek bukan nol dari jenis yang sama, dan melindungi Anda terhadap 'kasus konyol' dalam satu baris. lebih sedikit kode = lebih sedikit bug.
13
Untuk mempertimbangkan "apakah ini berguna?" debat - Saya tidak pernah menulis kode Java saya sendiri (jadi jangan mudah tahu di mana spesifikasinya, dan menyusun tes akan sangat non-sepele), tapi saya saat ini secara manual mengkonversi Java ke JavaScript. Kode saya gagal pada referensi nol, dan googling ini biarkan saya melihat jawaban yang diterima, yang mengkonfirmasi bahwa itu adalah perilaku yang diharapkan dan bahwa saya kehilangan cek nol implisit. Sangat berguna, dalam kasus saya.
Scott Mermelstein

Jawaban:

1839

Tidak, pemeriksaan nol tidak diperlukan sebelum menggunakan instanceof.

Ekspresi x instanceof SomeClassadalah falsejika xini null.

Dari Spesifikasi Bahasa Jawa, bagian 15.20.2, "Ketikkan instance operator perbandingan" :

"Pada saat run time, hasil dari instanceofoperator adalah truejika nilai RelationalExpression tidaknull dan referensi dapat dilemparkan ke ReferenceType tanpa menaikkan a ClassCastException. Kalau tidak hasilnya hasilnya false."

Jadi jika operan adalah nol, hasilnya salah.

Andy Thomas
sumber
377
Jawaban ini lebih benar daripada try itkarena perilaku saat ini tidak sama dengan perilaku yang dijamin .
Luke
3
Pertanyaan ini mulai berlaku selama bab Joshua Bloch tentang kesetaraan objek di Effective Java- amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683
Kevin Meredith
17
Secara khusus, dalam Butir 8, ia mencatat bahwa dalam metode equals (), satu instance dari operator melayani dua tujuan - itu memverifikasi bahwa argumen keduanya bukan nol dan dari jenis yang benar. "... [o] kamu tidak perlu cek kosong terpisah."
Andy Thomas
2
@BenThurley - Operator Java instanceofadalah bagian dari Java 1.0, dirilis hampir 20 tahun yang lalu. Mengubah perilaku sekarang dengan cara yang akan merusak kode yang ada tidak mungkin, tidak ada manfaat yang melebihi biaya yang sangat besar. Dua puluh tahun yang lalu, mungkin ada argumen untuk mengembalikan true jika argumen itu bisa dilemparkan, atau melemparkan pengecualian untuk argumen nol. Tetapi definisi-definisi itu akan membutuhkan pemeriksaan nol yang terpisah.
Andy Thomas
3
@BenThurley - Perilaku dijamin oleh spesifikasi Java dulu dan sekarang. Saya pikir poin Luke membahas keterbatasan eksperimen dalam menentukan perilaku yang dijamin saat ini.
Andy Thomas
267

Menggunakan referensi nol sebagai operan pertama yang instanceofkembali false.

Bozho
sumber
268
(Dan sekarang butuh 10 detik untuk menemukan pertanyaan ini di Google)
PL_kolek
73

Pertanyaan yang sangat bagus. Saya hanya mencoba sendiri.

public class IsInstanceOfTest {

    public static void main(final String[] args) {

        String s;

        s = "";

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));

        s = null;

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));
    }
}

Cetakan

true
true
false
false

JLS / 15.20.2. Ketik Contoh Operator Perbandingan

Pada saat run time, hasil dari instanceofoperator adalah truejika nilai RelationalExpression tidak nulldan referensi dapat dilemparkan ke ReferenceType tanpa menaikkan a ClassCastException. Kalau tidak hasilnya adalah false.

API / Kelas # isInstance (Object)

Jika Classobjek ini mewakili antarmuka, metode ini mengembalikan truejika kelas atau superclass dari Objectargumen yang ditentukan mengimplementasikan antarmuka ini; ia mengembalikan falsesebaliknya. Jika Classobjek ini mewakili tipe primitif, metode ini kembali false.

Jin Kwon
sumber
Agak membingungkan. s adalah sebuah String karena dikatakan "String s", s bukan sebuah String karena itu adalah null. Jadi, apa itu?
Kai Wang
1
@ KaiWang shanyalah variabel referensi objek. Ini dapat merujuk objek yang sebenarnya ada ( "") atau merujuk nullreferensi (yang) literal.
Jin Kwon
Saya masih bingung. s mungkin null sekarang, tetapi hanya bisa diarahkan ke instance String nanti. Itu tidak bisa menunjuk ke, seperti, Integer. Jadi itu masih semacam String, bahkan itu adalah nol. Tidak masuk akal ...
Kai Wang
@ KaiWang Anda mengacaukan tipe variabel dengan tipe objek aktual. Variabel bukan instance; mereka secara efektif hanya petunjuk. nullbukan data string, apa pun variabel yang menunjukkannya. s instanceof Stringtidak sama dengan field.getType().equals(String.class), misalnya.
Matius Baca
@KaiWang Anda harus membayangkan bahwa dalam panggilan s instanceof Stringtersebut sakan diganti dengan nilai yang sebenarnya, sehingga akan menjadi "" instanceof Stringdan null instanceof String. Memikirkannya seperti ini mungkin lebih masuk akal.
Timo Türschmann
24

Tidak, tidak. instanceofakan kembali falsejika operan pertamanya adalah null.

RoflcoptrException
sumber
16

Sama seperti berita gembira :

Bahkan akan kembali .(((A)null)instanceof A)false


(Jika pengetikan nulltampak mengejutkan, terkadang Anda harus melakukannya, misalnya dalam situasi seperti ini:

public class Test
{
  public static void test(A a)
  {
    System.out.println("a instanceof A: " + (a instanceof A));
  }

  public static void test(B b) {
    // Overloaded version. Would cause reference ambiguity (compile error)
    // if Test.test(null) was called without casting.
    // So you need to call Test.test((A)null) or Test.test((B)null).
  }
}

Jadi Test.test((A)null)akan dicetak a instanceof A: false.)


PS: Jika Anda sedang merekrut, jangan gunakan ini sebagai pertanyaan wawancara kerja. : D

Attila Tanyi
sumber
7

Tidak ada . Java literal nullbukan turunan dari kelas mana pun. Oleh karena itu tidak dapat menjadi instance dari kelas mana pun. instanceof akan mengembalikan salah satu falseatautrue karena itu <referenceVariable> instanceof <SomeClass>pengembalian falseketika referenceVariablenilai nol.

Pengembang Marius Žilėnas
sumber
5
Penjelasan itu kedengarannya aneh melingkar ... tapi saya tahu apa yang Anda maksud :-)
Kris
@Kris ty untuk komentar saya mengerti maksud Anda :). Diedit sedikit jawabannya :).
Pengembang Marius Žilėnas
1

The instanceofoperator tidak perlu eksplisit nullcek, karena tidak melempar NullPointerExceptionjika operan adalah null.

Pada saat run time, hasil dari instanceofoperator adalah benar jika nilai ekspresi relasional tidak nulldan referensi dapat dilemparkan ke tipe referensi tanpa menaikkan pengecualian pemeran kelas.

Jika operan null, instanceofoperator kembali falsedan karenanya, tidak diperlukan pemeriksaan eksplisit.

Perhatikan contoh di bawah ini,

public static void main(String[] args) {
         if(lista != null && lista instanceof ArrayList) {                     //Violation
                System.out.println("In if block");
         }
         else {
                System.out.println("In else block");
         }
}

Penggunaan yang benar instanceofadalah seperti yang ditunjukkan di bawah ini,

public static void main(String[] args) {
      
         if(lista instanceof ArrayList){                     //Correct way
                  System.out.println("In if block");
         }
            else {
                 System.out.println("In else block");
         }  
}
Nikhil Kumar
sumber