Tại sao không thể mở rộng các chú thích trong Java?


227

Tôi không hiểu tại sao không có sự kế thừa trong các chú thích Java, giống như các lớp Java. Tôi nghĩ rằng nó sẽ rất hữu ích.

Ví dụ: Tôi muốn biết nếu một chú thích nhất định là một trình xác nhận hợp lệ. Với tính kế thừa, tôi có thể điều hướng theo phản xạ thông qua các siêu lớp để biết chú thích này có mở rộng không ValidatorAnnotation. Nếu không, làm thế nào tôi có thể đạt được điều này?

Vì vậy, bất cứ ai có thể cho tôi một lý do cho quyết định thiết kế này?


2
Lưu ý, BTW, rằng tất cả các chú thích đều mở rộng java.lang.annotation.Annotation, tức là bất kỳ chú thích nào cũng instanceofvậy mặc dù thực tế này không được tuyên bố rõ ràng.
Tomáš Záluský

Câu trả lời:


166

Về lý do tại sao nó không được thiết kế theo cách bạn có thể tìm thấy câu trả lời trong Câu hỏi thường gặp về thiết kế của JSR 175 , nơi nó nói:

Tại sao bạn không hỗ trợ phân nhóm chú thích (trong đó một loại chú thích mở rộng loại chú thích khác)?

Nó làm phức tạp hệ thống loại chú thích và làm cho việc viết công cụ cụ thể khó khăn hơn nhiều.

Giáo dục

Các công cụ cụ thể của cung cấp - Các chương trình truy vấn các loại chú thích đã biết của các chương trình bên ngoài tùy ý. Máy phát điện còn sơ khai, ví dụ, thuộc loại này. Các chương trình này sẽ đọc các lớp chú thích mà không tải chúng vào máy ảo, nhưng sẽ tải các giao diện chú thích.

Vì vậy, vâng tôi đoán, lý do là nó chỉ HÔN. Dù sao, có vẻ như vấn đề này (cùng với nhiều người khác) đang được xem xét như là một phần của JSR 308 và thậm chí bạn có thể tìm thấy một trình biên dịch thay thế với chức năng này đã được Mathias Ricken phát triển .


67
Chà, có lẽ tôi ngu ngốc, nhưng tôi nghĩ thật đáng tiếc không thể mở rộng các chú thích chỉ vì "giữ cho nó đơn giản". Ít nhất, các nhà thiết kế Java đã không nghĩ giống nhau về kế thừa lớp: P
sinuhepop

2
Java 8 M7, dường như không hỗ trợ các chú thích phân lớp. Thật đáng tiếc.
Ceki

2
@assylias JEP 104 không phải là để làm cho nó có thể chú thích lớp con. JEP 104 đã được triển khai trong Java 8, nhưng vẫn không thể chú thích lớp con (tạo một chú thích mở rộng một chú thích khác).
Jesper

71

Các chú thích mở rộng sẽ có hiệu quả thêm gánh nặng của việc chỉ định và duy trì một hệ thống loại khác. Và đây sẽ là một hệ thống loại khá độc đáo, vì vậy bạn không thể đơn giản áp dụng mô hình loại OO.

Hãy suy nghĩ về tất cả các vấn đề khi bạn giới thiệu tính đa hình và kế thừa cho một chú thích (ví dụ: điều gì xảy ra khi chú thích phụ thay đổi các thông số chú thích meta như lưu giữ?)

Và tất cả điều này thêm phức tạp cho trường hợp sử dụng?

Bạn muốn biết nếu một chú thích nhất định thuộc về một thể loại?

Thử cái này:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

Như bạn có thể thấy, bạn có thể dễ dàng nhóm và phân loại các chú thích mà không bị đau quá mức khi sử dụng các phương tiện được cung cấp.

Vì vậy, hôn là lý do không giới thiệu một hệ thống loại meta cho ngôn ngữ Java.

[chỉnh sửa]

Tôi đã sử dụng Chuỗi đơn giản để trình diễn và theo quan điểm của một chú thích meta kết thúc mở. Đối với dự án cụ thể của riêng bạn, rõ ràng bạn có thể sử dụng một danh mục các loại danh mục và chỉ định nhiều danh mục ("nhiều kế thừa") cho một chú thích nhất định. Xin lưu ý rằng các giá trị hoàn toàn không có thật và chỉ nhằm mục đích trình diễn:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    AnnotationCategory[] category();
}
public enum AnnotationCategory {
    GENERAL,
    SEMANTICS,
    VALIDATION,
    ETC
}

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {

}


Không hoạt động sẽ in sai:@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) @interface C {}; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @C public @interface F {} class a{ @F public void S() {} } @Test public void blahTest() throws NoSuchMethodException { Method m = a.class.getMethod("S"); System.out.println(m.isAnnotationPresent(C.class)); }
user1615664

Chúng tôi đang chú thích một chú thích. a # S có chú thích F. Bản thân F được chú thích bởi C. Hãy thử điều đó.
alphazero

Vâng, đó là chính xác. Nhưng có cách nào để làm điều đó sạch sẽ hơn thay vì đọc qua proxy Annotation?
dùng1615664

12

Theo một nghĩa nào đó, bạn đã có nó với Chú thích - Chú thích meta. Nếu bạn chú thích một chú thích với thông tin meta, thì theo nhiều cách tương đương với việc mở rộng một giao diện bổ sung. Chú thích là các giao diện, vì vậy tính đa hình không thực sự phát huy tác dụng, và vì chúng có bản chất tĩnh, nên không thể gửi động động thời gian chạy.

Trong ví dụ về trình xác nhận của bạn, bạn có thể chỉ vào chú thích lấy loại chú thích và xem nó có chú thích meta của trình xác nhận hay không.

Trường hợp sử dụng duy nhất tôi có thể thấy rằng sự kế thừa sẽ giúp ích nếu bạn muốn có thể nhận được chú thích theo loại siêu, nhưng điều đó sẽ thêm một loạt các phức tạp, bởi vì một phương thức hoặc loại đã cho có thể có hai chú thích như vậy trên đó, có nghĩa là một mảng sẽ phải được trả về thay vì chỉ một đối tượng.

Vì vậy, tôi nghĩ rằng câu trả lời cuối cùng là các trường hợp sử dụng là bí truyền và làm phức tạp thêm các trường hợp sử dụng tiêu chuẩn làm cho nó không có giá trị.


5

Các nhà thiết kế hỗ trợ chú thích Java đã thực hiện một số "đơn giản hóa" để gây bất lợi cho cộng đồng Java.

  1. Không có các kiểu con chú thích làm cho nhiều chú thích phức tạp xấu xí không cần thiết. Một người không thể chỉ đơn giản là có một thuộc tính trong một chú thích có thể chứa một trong ba điều. Một cần phải có ba thuộc tính riêng biệt, gây nhầm lẫn cho các nhà phát triển và yêu cầu xác thực thời gian chạy để đảm bảo rằng chỉ một trong ba thuộc tính được sử dụng.

  2. Chỉ có một chú thích của một loại nhất định trên mỗi trang web. Điều này đã dẫn đến mẫu chú thích bộ sưu tập hoàn toàn không cần thiết. @Validation và @Validations, @Image và @Images, v.v.

Cái thứ hai đang được khắc phục trong Java 8, nhưng đã quá muộn. Nhiều khung công tác đã được viết dựa trên những gì có thể có trong Java 5 và bây giờ các mụn cóc API này đã tồn tại trong một thời gian dài.


1
Không chỉ vậy, nó cũng làm cho không thể xác định các thuộc tính có các thuộc tính lồng nhau đệ quy - được lược đồ XML hỗ trợ. Điều này làm cho các chú thích hoàn toàn không mạnh hơn XML
user2833557

3

Tôi có thể trễ ba năm khi trả lời câu hỏi này, nhưng tôi thấy nó thú vị bởi vì tôi thấy mình ở cùng một chỗ. Đây là của tôi về nó. Bạn có thể xem các chú thích dưới dạng Enums. Họ cung cấp một loại thông tin một chiều - sử dụng hoặc mất nó.

Tôi đã có một tình huống mà tôi muốn mô phỏng GET, POST, PUT và DELETE trong một ứng dụng web. Tôi rất muốn có một chú thích "siêu" được gọi là "HTTP_METHOD". Nó sau đó nhận ra rằng tôi không thành vấn đề. Chà, tôi đã phải giải quyết bằng cách sử dụng một trường ẩn trong biểu mẫu HTML để xác định XÓA và PUT (vì dù sao thì POST và GET cũng có sẵn).

Về phía máy chủ, tôi tìm kiếm một tham số yêu cầu ẩn với tên, "_method". Nếu giá trị là PUT hoặc DELETE, thì nó sẽ vượt qua phương thức yêu cầu HTTP được liên kết. Có nói rằng, không quan trọng tôi có cần gia hạn chú thích để hoàn thành công việc hay không. Tất cả các chú thích trông giống nhau, nhưng chúng được xử lý khác nhau ở phía máy chủ.

Vì vậy, trong trường hợp của bạn, giảm ngứa để mở rộng chú thích. Hãy coi họ là "điểm đánh dấu". Họ "đại diện" cho một số thông tin và không nhất thiết phải "thao túng" một số thông tin.


2

Một điều tôi có thể nghĩ là khả năng có nhiều chú thích. Vì vậy, bạn có thể thêm trình xác nhận và chú thích cụ thể hơn ở cùng một nơi. Nhưng tôi có thể nhầm :)


2

Không bao giờ nghĩ về điều đó nhưng ... có vẻ như bạn đúng, không có vấn đề gì với cơ sở thừa kế chú thích (ít nhất là tôi không thấy vấn đề với nó).

Giới thiệu về ví dụ của bạn với chú thích 'trình xác thực' - sau đó bạn có thể khai thác phương pháp 'chú thích meta' . Tức là bạn áp dụng chú thích meta cụ thể cho toàn bộ giao diện chú thích.


Tôi có thể trễ ba năm khi trả lời câu hỏi này, nhưng tôi thấy nó thú vị bởi vì tôi thấy mình ở cùng một chỗ.
mainas

1

vấn đề tương tự tôi có. Không, bạn không thể. Tôi đã 'kỷ luật' bản thân mình để viết các thuộc tính trong các chú thích để tôn trọng một số tiêu chuẩn, vì vậy bên ngoài khi bạn nhận được chú thích, bạn có thể 'đánh hơi' nó là loại chú thích nào bởi các thuộc tính mà nó có.

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.