2009-07-24 34 views

Trả lời

52

Tôi không biết tại sao, nhưng JLS là rất rõ ràng:

Discussion 

Note that null is not a legal element value for any element type. 

Và định nghĩa của một yếu tố mặc định là:

 DefaultValue: 
     default ElementValue 

Đáng tiếc là tôi tiếp tục tìm kiếm rằng các tính năng ngôn ngữ mới (Enums và bây giờ chú thích) có thông báo lỗi trình biên dịch rất không hữu ích khi bạn không đáp ứng các spec ngôn ngữ.

EDIT: Một googleing ít thấy following trong JSR-308, nơi họ tranh luận đã cho phép null trong tình huống này:

Chúng tôi lưu ý một số phản đối có thể đề xuất.

Đề xuất không thực hiện bất kỳ điều gì có thể trước đây.

Giá trị đặc biệt lập trình viên xác định cung cấp tài liệu tốt hơn so với null, mà có thể có nghĩa là “none”, “chưa được khởi tạo”, null chính nó, vv

Đề xuất này là hơn dễ bị lỗi. Nó dễ dàng hơn nhiều để quên kiểm tra chống lại null hơn là quên kiểm tra cho một giá trị rõ ràng.

Đề xuất có thể làm cho thành ngữ chuẩn tiết hơn. Hiện tại chỉ người dùng chú thích mới cần kiểm tra các giá trị đặc biệt của nó. Với đề xuất này, nhiều công cụ xử lý các chú thích sẽ phải kiểm tra xem giá trị của trường có phải là giá trị rỗng không khi chúng ném một ngoại lệ con trỏ null.

Tôi nghĩ chỉ có hai điểm cuối có liên quan đến "tại sao không làm điều đó ngay từ đầu". Điểm cuối cùng chắc chắn sẽ đưa ra một điểm tốt - một trình xử lý chú thích không bao giờ phải lo ngại rằng chúng sẽ nhận được một giá trị chú thích trên một giá trị chú thích. Tôi có xu hướng thấy rằng càng nhiều công việc của bộ xử lý chú thích và mã khuôn khổ như vậy phải làm loại kiểm tra đó để làm cho các nhà phát triển mã rõ ràng hơn là theo cách khác, nhưng nó sẽ làm cho việc sửa đổi nó trở nên khó khăn.

41

Dường như điều này là bất hợp pháp, mặc dù JLS rất mờ về điều này.

tôi tàn phá trí nhớ của tôi để cố gắng và suy nghĩ của một chú thích hiện ra có mà đã có một thuộc tính Class để chú thích, và nhớ cái này từ API JAXB:

@Retention(RUNTIME) @Target({PACKAGE,FIELD,METHOD,TYPE,PARAMETER})   
public @interface XmlJavaTypeAdapter { 
    Class type() default DEFAULT.class; 

    static final class DEFAULT {}  
} 

Bạn có thể xem cách họ đã phải định nghĩa một lớp tĩnh giả để giữ tương đương với một giá trị rỗng.

Khó chịu.

+2

Có, chúng tôi làm điều gì đó tương tự (chúng tôi chỉ sử dụng Foo.class làm mặc định). Sucks. – ripper234

+5

Và trong trường hợp của các trường String, bạn phải sử dụng [chuỗi ma thuật] (http://en.wikipedia.org/wiki/Magic_string). Rõ ràng các mẫu antipatterns nổi tiếng là tốt hơn so với các tính năng ngôn ngữ được hiểu rõ hiện nay. –

+2

@TimYates Nó giết chết tôi để thấy mọi người định nghĩa giá trị sentinel "không có giá trị" của riêng mình khi có sẵn và hiểu được toàn bộ. Và bây giờ nó được yêu cầu bởi chính ngôn ngữ đó ?! May mắn thay, bạn có thể xác định "chuỗi ma thuật" của bạn là hằng số công khai. Nó vẫn không lý tưởng nhưng ít nhất mã tìm kiếm chú thích của bạn có thể tham chiếu hằng số thay vì sử dụng các chữ trong mọi nơi. – spaaarky21

46

Hãy thử điều này

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface SomeInterface { 
    Class bar() default void.class; 
} 

Nó không đòi hỏi một lớp mới và nó đã là một từ khóa trong Java có nghĩa là gì.

+6

Tôi thích nó. Vấn đề duy nhất - trong ngữ cảnh của câu hỏi ban đầu - là câu trả lời này không hỗ trợ các thông số kiểu: 'Lớp bar() mặc định void.null' không biên dịch. – Kariem

+1

Lớp void.class không thể được áp dụng chung: public @interface NoNullDefault {String value() default void.class; } – wjohnson

+0

Đối với Groovy nó hoạt động tốt, ngay cả trong các trường hợp được đề cập trong các ý kiến ​​ – Vampire

9

Dường như có một cách khác để thực hiện điều đó.

Tôi không thích điều này, nhưng nó có thể hoạt động.

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface SomeInterface { 
    Class<? extends Foo>[] bar() default {}; 
} 

Vì vậy, về cơ bản bạn tạo một mảng trống để thay thế. Điều này dường như cho phép một giá trị mặc định.

1

Thông báo lỗi đó gây hiểu lầm, nhưng, không, null chữ không phải là một biểu thức liên tục, như được định nghĩa trong Đặc tả Ngôn ngữ Java, here.

Hơn nữa, Java Language Specification nói

Đó là một lỗi thời gian biên dịch nếu kiểu của phần tử là không tương xứng (§9.7) với giá trị mặc định theo quy định.

Và để explain what that means

Đó là một lỗi thời gian biên dịch nếu các loại nguyên tố là không tương xứng với giá trị phần tử. Một loại nguyên tố T là tương xứng với giá trị yếu tố V khi và chỉ khi một trong những điều sau đây là đúng:

  • [...]
  • V không phải là null.

Vì vậy, ở đây, loại nguyên tố của bạn, Class<? extends Foo>, là không tương xứng với giá trị mặc định, bởi vì giá trị đó là null.

+0

Tôi đã nhận được một cái gì đó sai? –

+0

Giải pháp của bạn không phù hợp để sao chép và dán ;-) Một số không thích suy nghĩ, khi đọc –

0
Class<? extends Foo> bar() default null;// this doesn't compile 

Như đã đề cập, đặc tả ngôn ngữ Java không cho phép giá trị null trong giá trị mặc định chú thích.

Điều tôi có xu hướng làm là xác định các hằng số DEFAULT_VALUE ở đầu định nghĩa chú thích. Một cái gì đó như:

public static final String DEFAULT_VALUE = "__class-name-here__ default"; 

public String prefix() default DEFAULT_VALUE; 

Sau đó trong mã của tôi, tôi làm điều gì đó như:

if (myAnnotation.prefix().equals(MyAnnotation.DEFAULT_VALUE)) { ... } 

Trong trường hợp bạn có một lớp học, tôi sẽ chỉ định nghĩa một lớp marker. Đáng tiếc là bạn không thể có một hằng số cho điều này để thay vào đó bạn cần phải làm điều gì đó như:

Class<? extends Foo> bar() default DefaultFoo.class; 

lớp DefaultFoo của bạn sẽ chỉ là một thực phẩm nào để mã có thể làm:

if (myAnnotation.bar() == DefaultFoo.class) { ... } 

Hy vọng điều này giúp người khác.

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