Tại sao một chú thích bị thiếu không gây ra ClassNotFoundException trong thời gian chạy?


91

Hãy xem xét đoạn mã sau:

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 hoạt động như mong đợi:

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

Nhưng sau đó hãy xem xét điều này:

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

Tôi đã mong đợi nó ném một ClassNotFoundException, vì đã @Amất tích. Nhưng thay vào đó, nó âm thầm bỏ chú thích.

Hành vi này có được ghi lại trong JLS ở đâu đó không, hay nó chỉ là một trò lố của JVM của Sun? Cơ sở lý luận của nó là gì?

Nó có vẻ thuận tiện cho những thứ như javax.annotation.Nonnull(có vẻ như @Retention(CLASS)dù sao thì nó cũng nên như vậy ), 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 tồi tệ khác nhau xảy ra trong thời gian chạy.

Câu trả lời:


90

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

Ngay cả khi cách diễn đạt hơi mơ hồ, tôi giả sử rằng hành vi bạn đang thấy đượ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 các biểu diễn nhị phân của các 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ể các chú thích bị xóa (không có sẵn trong thời gian chạy), chương trình sẽ vẫ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ỉ bị bỏ qua khi được truy cập thông qua phản chiếu.

Bản phát hành đầ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 đầu mối thông số JSR-175, các chú thích không xác định phải bị getAnnotations bỏ qua".


35

Trích dẫn JLS:

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

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

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

Nếu T không có chú thích (meta-) m tương ứng với annotation.Retention, thì trình biên dịch Java phải coi T như thể nó có một meta-annotation 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 chú thích được biên dịch thành tệp nhị phân nhưng chú thích có trong tệp nhị phân không nhất thiết phải có sẵn trong thời gian chạy


9

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

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

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.