Toán tử 'instanceof' hoạt động khác nhau đối với các giao diện và lớp


88

Tôi muốn biết về hành vi sau của instanceoftoán tử trong Java.

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
    }
}

Tại sao nó như vậy? Không có mối quan hệ nào giữa interface Cclass B, nhưng nó cho sai trong khi trong trường hợp obj instanceof Anó cho lỗi trình biên dịch?


12
Lưu ý: nếu bạn thay đổi nó thành Object obj = new B(), nó sẽ biên dịch.
user253751

1
Lỗi trình biên dịch cho bạn biết điều gì?
karfau,

If class Bis finalthen obj instanceof Ccũng sẽ không biên dịch, bởi vì if Bcó thể không có kiểu con, thì nó được đảm bảo là không liên quan đến C.
jaco0646

Câu trả lời:


127

Bởi vì Java không có nhiều lớp kế thừa, nên trong quá trình biên dịch, objđối tượng của kiểu Bkhông thể là kiểu con của đối tượng này A. Mặt khác, nó có thể là kiểu con của giao diện C, ví dụ trong trường hợp này:

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  
    }
}

Vì vậy, chỉ nhìn vào obj instanceof Ctrình biên dịch biểu thức không thể biết trước nó sẽ đúng hay sai, nhưng nhìn vào obj instanceof Anó sẽ biết rằng điều này luôn luôn sai, do đó vô nghĩa và giúp bạn ngăn ngừa lỗi. Nếu bạn vẫn muốn kiểm tra vô nghĩa này trong chương trình của mình, bạn có thể thêm một phép truyền rõ ràng vào Object:

System.out.println(((Object)obj) instanceof A);      //compiles fine

1
Các hương vị khác séc nghĩa là để sử dụngA.class.isAssignableFrom(obj.getClass())
David Ehrmann

Tôi hơi bối rối với lời giải thích của bạn, bạn nói Java has no multiple class inheritancecó Tôi đồng ý nhưng nó được áp dụng như thế nào trong trường hợp này bởi vì cả B hoặc A đều không mở rộng bất kỳ ý nghĩa nào vậy tại sao lại có nhiều thừa kế ở đây. Sẽ hữu ích nếu bạn có thể giải thích?
codegasmer

@codegasmer Câu trả lời muộn: Nếu Java cho phép một lớp kế thừa từ nhiều lớp khác, thì người ta có thể thực hiện "lớp D mở rộng A, B" hoặc một số như vậy, sau đó "B obj = new D ()" và tạo "obj instanceof A "trong biên dịch câu hỏi ban đầu (trong khi hiện tại thì không) - thực tế là nó đã biên dịch tốt hơn, bởi vì nó sẽ được đánh giá là true. Nhưng nếu nó chỉ đơn giản là không được phép cho bất kỳ thứ gì là cả B và A, thì cụm từ "obj instanceof A" trong đó obj được định nghĩa là loại B có thể được coi là vô nghĩa một cách hợp lý.
mjwach

"Nếu bạn vẫn muốn kiểm tra vô nghĩa này" - nó không cần phải vô nghĩa, vì nếu các lớp này là từ thư viện / khung công tác khác thì có khả năng bạn sẽ sử dụng phiên bản khác trong thời gian chạy ở đâu B extends A. Trong cuộc sống của tôi, tôi thực sự cần phải thực hiện những kiểm tra và phôi kỳ lạ (A)(Object)bnhư trong thời gian chạy nó thực sự có thể thành sự thật.
GotoFinal

1

Bằng cách sử dụng công cụ finalsửa đổi trong khai báo lớp bên dưới, đảm bảo rằng không thể có lớp con của lớp này, lớp Testnày có thể triển khai giao diện Foobar. Trong trường hợp này, rõ ràng là TestFoobarkhông tương thích với nhau:

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 {
}

Ngược lại, nếu Testkhông được khai báo final, có thể một lớp con của Testthực thi giao diện. Và đó là lý do tại sao trình biên dịch sẽ cho phép câu lệnh test instanceof Foobartrong trường hợp này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.