2010-08-25 21 views
76

Xét đoạn mã sau:Tại sao chú thích thiếu mất gây ra một ClassNotFoundException khi chạy?

A.java:

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

@Retention(RetentionPolicy.RUNTIME) 
@interface A{} 

C.java:

import java.util.*; 

@A public class C { 
     public static void main(String[] args){ 
       System.out.println(Arrays.toString(C.class.getAnnotations())); 
     } 
} 

Biên dịch và chạy các tác phẩm như mong đợi:

$ javac *.java 
$ java -cp . C 
[@A()] 

Nhưng sau đó xem xét này:

$ rm A.class 
$ java -cp . C 
[] 

Tôi đã dự kiến ​​sẽ ném một số ClassNotFoundException vì thiếu @A. Nhưng thay vào đó, nó âm thầm giảm chú thích.

Hành vi này có được ghi lại trong JLS ở đâu đó không, hoặc đó có phải là một hoạt động không bình thường của JVM của Sun không? Lý do cho nó là gì?

Có vẻ như thuận tiện cho những thứ như javax.annotation.Nonnull (có vẻ như nó đã là @Retention(CLASS)), nhưng đối với nhiều chú thích khác, có vẻ như nó có thể gây ra nhiều điều xấu xảy ra khi chạy.

Trả lời

81

Trong bản nháp công khai trước đó cho JSR-175 (chú thích), nó được thảo luận nếu trình biên dịch và thời gian chạy phải bỏ qua chú thích không xác định, để cung cấp một khớp nối lỏng hơn giữa việc sử dụng và khai báo chú thích. Một ví dụ cụ thể là việc sử dụng các chú thích của máy chủ ứng dụng cụ thể trên một EJB để kiểm soát cấu hình triển khai. Nếu cùng một bean sẽ được triển khai trên một máy chủ ứng dụng khác nhau, nó sẽ thuận tiện nếu thời gian chạy chỉ đơn giản là bỏ qua các chú thích không xác định thay vì tăng NoClassDefFoundError.

Ngay cả khi từ ngữ có chút mơ hồ, tôi cho rằng hành vi bạn đang xem được chỉ định trong JLS 13.5.7: "... xóa chú thích không ảnh hưởng đến liên kết chính xác của biểu diễn nhị phân của chương trình trong ngôn ngữ lập trình Java. " Tôi giải thích điều này như thể chú thích bị xóa (không có sẵn khi chạy), chương trình vẫn nên liên kết và chạy và điều này ngụ ý rằng các chú thích không xác định chỉ đơn giản bị bỏ qua khi được truy cập thông qua sự phản chiếu.

Phiên bản đầu tiên của JDK 5 của Sun không thực hiện điều này một cách chính xác, nhưng nó đã được sửa trong 1.5.0_06. Bạn có thể tìm thấy lỗi liên quan 6322301 trong cơ sở dữ liệu lỗi, nhưng nó không trỏ đến bất kỳ thông số kỹ thuật nào ngoại trừ tuyên bố rằng "theo tiêu chuẩn JSR-175 spec, chú thích không rõ phải được bỏ qua bởi getAnnotations".

32

Trích dẫn JLS:

9.6.1.2 Retention Chú thích có thể có mặt chỉ trong mã nguồn, hoặc họ có thể hiện diện dưới dạng nhị phân của một lớp hoặc giao diện. Chú thích có trong nhị phân có thể hoặc có thể không có sẵn tại thời gian chạy qua thư viện phản chiếu của nền tảng Java .

Chú thích loại chú thích.Chú ý được sử dụng để chọn trong số các khả năng trên. Nếu một chú thích một tương ứng với một loại T, và T có một (meta) chú thích m mà tương ứng với annotation.Retention, thì:

  • nếu m có một yếu tố có giá trị là annotation.RetentionPolicy .SOURCE, thì trình biên dịch Java phải đảm bảo rằng a không có mặt trong biểu thức nhị phân của lớp hoặc giao diện trong đó xuất hiện.
  • Nếu m có một yếu tố có giá trị là annotation.RetentionPolicy.CLASS, hoặc annotation.RetentionPolicy.RUNTIME một trình biên dịch Java phải đảm bảo rằng một là đại diện trong nhị phân đại diện của lớp hoặc giao diện trong đó một xuất hiện , trừ khi m chú thích biến địa phương khai báo. Chú thích trên tuyên bố biến địa phương không bao giờ được giữ lại trong biểu diễn nhị phân.

Nếu T không có (meta) chú thích m tương ứng với annotation.Retention, sau đó một trình biên dịch Java phải đối xử với T như nếu nó có một meta-chú thích m với một phần tử có giá trị là chú thích.RetentionPolicy.CLASS.

Vì vậy RetentionPolicy.RUNTIME đảm bảo rằng các chú thích được biên soạn vào nhị phân nhưng chú thích hiện diện trong nhị phân không nhất thiết phải có sẵn trong thời gian chạy

-1

Chú thích không có ảnh hưởng trực tiếp đến hoạt động của mã họ chú thích.
Tuy nhiên, bằng cách sử dụng @Retention(RetentionPolicy.RUNTIME) các chú thích có sẵn khi chạy.

Bây giờ, tôi đoán là @Retention không khả dụng và do đó bị bỏ qua. Điều này ngụ ý rằng các chú thích khác không có sẵn khi chạy.
Không có ngoại lệ vì chú thích được bỏ qua theo mặc định. Chỉ khi có sự hiện diện của @Retention thì chúng mới được xem xét.

Có thể nếu bạn tạo shure @Retention khả dụng, sẽ có khiếu nại. (không chắc chắn về điều này)

+5

@Retention nằm trong java.lang.annotation - làm thế nào nó không có sẵn? –

7

nếu bạn thực sự có mã đọc @A và làm điều gì đó với nó, mã có sự phụ thuộc vào lớp A và nó sẽ ném ClassNotFoundException.

nếu không, nghĩa là không có mã nào quan tâm cụ thể về @A, thì có thể cho rằng @A không thực sự quan trọng.

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