2016-01-03 11 views
5

Các mã sau biên dịch tốt:biên dịch lỗi thể hiện của lớp thức

interface Flyer{ } 
class Bat { } 

public class App { 

    public static void main(String[] args) { 
     Bat b = new Bat(); 
     if(b instanceof Flyer) System.out.println("b is a Bird"); 
    } 

} 

Nếu chúng ta làm cho Bat lớp final, mã không biên dịch:

final class Bat { } 

Nếu lớp thức thực hiện Flyer , nó biên dịch tốt:

final class Bat implements Flyer { } 

Bất kỳ một sự quan tâm để giải thích logic đằng sau điều này?

Trả lời

6

Khi bạn tạo lớp Batfinal, bạn đang nói rằng lớp này không thể được phân loại phụ. Vì Bat không triển khai giao diện Flyer, trình biên dịch có thể xác định rằng b instanceof Flyer không bao giờ có thể là true và gây ra lỗi.

này được quy định tại JLS section 15.20.2:

Nếu một dàn diễn viên (§15.16) của RelationalExpression đến ReferenceType sẽ bị từ chối là một lỗi thời gian biên dịch, thì biểu thức quan hệ tương tự như vậy instanceof tạo ra lỗi biên dịch. Trong tình huống như vậy, kết quả của biểu thức instanceof không bao giờ có thể đúng.

Bên cạnh đó, từ section 15.16 về biểu diễn:

Đó là một lỗi thời gian biên dịch nếu loại thời gian biên dịch của các toán hạng có thể không bao giờ được biến đổi thành kiểu xác định bởi các nhà điều hành đúc theo các quy tắc đúc chuyển đổi (§5.5).

Trong trường hợp này, Bat không bao giờ có thể được đúc để Flyer: nó không thực hiện nó và final đảm bảo rằng không thể có tiểu lớp đó sẽ thực hiện nó.


Như bạn phát hiện ra, các bản sửa lỗi là:

  • Hãy Bat thực hiện Flyer: trong trường hợp này, các nhà điều hành instanceof sẽ luôn luôn trả true.
  • Xóa số nhận dạng final, ngụ ý rằng có thể có các lớp con của Bat triển khai Flyer.
+0

Sẽ không 'null instanceof X' trả về true bất kể" kiểu "của cá thể null? Tuy nhiên tôi có thể thấy rằng điều này sẽ rất dodgy để cho trình biên dịch chấp nhận rằng – Dici

+0

@Dici Trên thực tế, ['null instanceof X' luôn luôn là' false'] (http://stackoverflow.com/questions/2950319/is-null- check-needed-before-calling-instanceof). – Tunaki

+0

Ups ... xin lỗi, bạn nói đúng, tôi thậm chí còn sử dụng nó để viết tất cả các phương thức 'equals' của tôi. Tôi cần một giấc ngủ: D – Dici

4

Vâng, nếu Bat là một lớp cuối cùng và nó không thực hiện Flyer, nó có thể không có bất kỳ sub-class đó sẽ thực hiện một trong hai Flyer, vì vậy instanceof không bao giờ có thể trở lại thành sự thật. Trong trường hợp này trình biên dịch không cho phép biểu thức này (tức là (x instanceof Y) chỉ được cho phép nếu có khả năng x sẽ chứa tham chiếu đến một cá thể triển khai hoặc mở rộng Y).

Trong đoạn thứ hai của bạn Bat đã thực hiện Flyer, vì vậy b instanceof Flyer sẽ luôn luôn trả true, bất kể Bat là cuối cùng hay không.

+0

Tôi thấy nó lạ (có thể là thiết kế xấu) nếu luôn luôn là 'sai' thì lỗi biên dịch sẽ xảy ra, nhưng nếu nó là * luôn luôn *' true' thì sẽ ổn. – Maroun

+0

Dường như logic bây giờ ... kiểm tra sớm luôn là một ý tưởng hay. – Trace

+0

@MarounMaroun Có một số mâu thuẫn ở đây, tôi đồng ý. – Eran

4

Ngoài @ Tunaki của tài liệu tham khảo từ các JLS, điều này cũng được giải thích một cách rõ ràng trong https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5.1, trích dẫn quy định có liên quan:

Nếu S là một final lớp (§8.1.1), sau đó S phải thực hiện T, hoặc một lỗi biên dịch thời gian xảy ra.

An instanceof kiểm tra tuân theo các quy tắc này cho phôi loại tham chiếu.

Các vấn đề liên quan