Operator 'instanceof' berperilaku berbeda untuk antarmuka dan kelas

88

Saya ingin mengetahui tentang perilaku instanceofoperator berikut di Jawa.

interface C {}

class B {}

public class A {
    public static void main(String args[]) {
        B obj = new B();
        System.out.println(obj instanceof A);      //Gives compiler error
        System.out.println(obj instanceof C);      //Gives false as output
    }
}

Kenapa gitu? Tidak ada hubungan antara interface Cdan class B, tetapi memberikan false sedangkan jika obj instanceof Amemberikan kesalahan compiler?

Ajay Sharma
sumber
12
Catatan: jika Anda mengubahnya menjadi Object obj = new B(), itu akan dikompilasi.
pengguna253751
1
Apa kesalahan kompiler yang memberitahu Anda?
karfau
Jika class Bada finalmaka obj instanceof Ctidak akan dikompilasi juga, karena jika tidak Bdapat memiliki subtipe, maka dijamin tidak terkait dengan C.
jaco0646

Jawaban:

127

Karena Java tidak memiliki pewarisan kelas jamak, selama kompilasi diketahui bahwa objobjek berjenis Btidak dapat dijadikan subjenis A. Di sisi lain, ini mungkin merupakan subtipe antarmuka C, misalnya dalam kasus ini:

interface C {}

class B {}

class D extends B implements C {}

public class A {
    public static void main(String args[]) {
        B obj = new D();
        System.out.println(obj instanceof C);      //compiles and gives true as output  
    }
}

Jadi melihat hanya pada obj instanceof Cpengompilasi ekspresi tidak dapat mengetahui sebelumnya apakah itu benar atau salah, tetapi melihatnya obj instanceof Atahu bahwa ini selalu salah, sehingga tidak berarti dan membantu Anda mencegah kesalahan. Jika Anda masih ingin mendapatkan tanda centang yang tidak berarti ini di program Anda, Anda dapat menambahkan transmisi eksplisit ke Object:

System.out.println(((Object)obj) instanceof A);      //compiles fine
Tagir Valeev
sumber
1
Rasa lain dari cek yang tidak berarti adalah dengan menggunakanA.class.isAssignableFrom(obj.getClass())
David Ehrmann
Saya agak bingung dengan penjelasan Anda, Anda mengatakan Java has no multiple class inheritanceya Saya setuju tetapi bagaimana penerapannya dalam kasus ini karena B atau A tidak memperluas anyting jadi mengapa ada banyak pewarisan di sini. Akan sangat membantu jika Anda dapat menjelaskan?
codegasmer
@codegasmer Jawaban terlambat: Jika Java mengizinkan sebuah kelas untuk mewarisi dari beberapa kelas lain, maka seseorang dapat melakukan "kelas D meluas A, B" atau semacamnya, dan kemudian "B obj = baru D ()", dan membuat "obj instance dari A "dalam kompilasi pertanyaan asli (sedangkan saat ini tidak) - sebenarnya ia memiliki kompilasi yang lebih baik, karena itu diharapkan untuk mengevaluasi ke benar. Tetapi jika tidak diperbolehkan untuk apapun menjadi B dan A, maka ekspresi "obj instanceof A" di mana obj didefinisikan sebagai tipe B dapat dianggap tidak masuk akal.
mjwach
"Jika Anda masih ingin memiliki tanda centang yang tidak berarti ini" - tidak perlu menjadi tidak berarti, karena jika kelas ini berasal dari pustaka / kerangka kerja lain maka ada kemungkinan bahwa Anda akan menggunakan versi yang berbeda pada waktu proses di mana B extends A. Dalam hidup saya, saya benar-benar perlu melakukan pemeriksaan dan pemeran aneh seperti (A)(Object)bdalam runtime itu sebenarnya mungkin untuk menjadi kenyataan.
GotoFinal
1

Dengan menggunakan finalpengubah dalam deklarasi kelas di bawah ini, dijamin bahwa tidak mungkin ada subkelas dari Test, yang mungkin mengimplementasikan antarmuka Foobar. Dalam hal ini, jelas bahwa Testdan Foobartidak kompatibel satu sama lain:

public final class Test {

    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test instanceof Foobar); // Compiler error: incompatible types
    }
}

interface Foobar {
}

Jika tidak, jika Testtidak dideklarasikan final, mungkin saja subclass dari Testmengimplementasikan antarmuka. Dan itulah mengapa kompilator akan mengizinkan pernyataan test instanceof Foobardalam kasus ini.

Nurettin Armutcu
sumber