2017-03-03 65 views
1

是否可以將註釋附加到新對象?附加到新對象的Java註釋?

比方說,我們有一個簡單的房屋對象,House house = new House() 和註釋@Large@Spooky

我的想法是有一個switch語句,所以一個標記爲@Spooky的房子做的東西與標記爲@Large的房子不同。

@Spooky 
House house = new House(); 

System.out.println(house.getClass().getAnnotations().length); 

顯然我的新房子對象上沒有註釋length == 0

這是爲什麼?

+3

這不是'House.class',你附加'@ Spooky'。這只是源代碼中的一個註釋變量。 –

+1

我不相信有什麼辦法從局部變量中獲得註釋。 (註釋當然不會附加到實際對象上,只是變量本身,無論如何你都不能傳遞它)。沒有辦法將任意元數據附加到任意Java對象上,就像你似乎試圖做的那樣。要麼它被構建到對象的類中,要麼不能這樣做。 –

+0

@Abrogatum有一個'House'可能有一些屬性,你應該有一個像'interface HouseProperty'這樣的類,你的House類應該有'private List ',方法'houseHas(HouseProperty property)'和' addProperty(HouseProperty p)'。在那之後,你可以讓'class Large實現HouseProperty {}'和'Spooky類實現HouseProperty'。 –

回答

2

一般

您不能註釋一個對象(僅在運行時存在)。您可以註釋一個聲明或自Java 8以來的類型用法(在編譯時已經存在)。

The Java™ Tutorials, Annotations, Annotations Basics

凡標註可用於

註釋可以應用於聲明:類聲明,字段,方法,和其他程序元素。 [...] 從Java SE 8發行版開始,註釋也可應用於類型的使用。

The Java™ Tutorials, Annotations, Type Annotations [...]

在Java SE 8發佈之前,註釋只能應用於聲明。從Java SE 8發行版開始,註釋也可以應用於任何類型的使用。這意味着註釋可用於任何使用類型的地方。使用類型的幾個示例是類實例創建表達式(新建),強制轉換,實現子句和引發子句。這種形式的註釋稱爲類型註釋[...]。

和可靠地最終來源The Java® Language Specification, 9.6.4. Predefined Annotation Types

9.6.4.1。在聲明上下文其中註釋適用於聲明@target

註釋類型可以適用,類型上下文其中註釋適用於聲明和表達式使用的類型。

[重點由我。]

ANWER你的問題

正如@ M.Prokhorov提到了他對你的問題,你不標註您的House類,但的house的局部變量聲明的評論,這是House類型。

也是這個Java Annotations Tutorial請參見:

註記配置

你可以把Java的[聲明]以上註解類,接口,方法,方法參數,字段和局部變量。 [...]

創建自己的註釋

[...]

@Retention

[...]

@Retention(RetentionPolicy.RUNTIME) 

這是什麼信號Java編譯器和JVM的註釋應該是可通過運行時反射

[...]

RetentionPolicy.CLASS意味着註釋存儲在.class文件,但不是在運行時可用。如果您沒有指定任何保留策略,則這是默認保留策略。

[由我重點。]

這意味着你有申報您的Spooky註釋:

@Retention(RetentionPolicy.RUNTIME) 
public @interface Spooky {} 

然而,隨着@LouisWasserman在他對你的問題的評論提到:

我不認爲有任何方法可以從局部變量中獲取註釋。

又見SO質疑ElementType.LOCAL_VARIABLE annotation type和上述JLS:

9.6.4.1。 @target

[...]

上的局部變量聲明的註釋是從來沒有保留在二進制表示。

所以,如果你會做一個house(亦稱成員變量):

@Spooky 
private House house = new House(); 

你可以使用:

Stream.of(this.getClass().getDeclaredFields()) 
    .forEach(field -> Stream.of(field.getAnnotations()) 
     .forEach(annotation -> System.out.printf("@%s%n%s %s %s;%n", 
      annotation.annotationType().getSimpleName(), 
      Modifier.toString(field.getModifiers()), 
      field.getType().getSimpleName(), 
      field.getName()))); 

,或者如果你想獲得house領域具體是:在這兩種情況下

try { 
    final Field field = this.getClass().getDeclaredField("house"); 
    final Spooky spooky = field.getAnnotation(Spooky.class); 
    if (spooky != null) { 
     System.out.printf("@%s%n%s %s %s;%n", 
      spooky.annotationType().getSimpleName(), 
      Modifier.toString(field.getModifiers()), 
      field.getType().getSimpleName(), 
      field.getName()); 
    } 
} 
catch (NoSuchFieldException | SecurityException e) { 
    e.printStackTrace(); 
} 

輸出:

@Spooky 
private House house; 

但是,正如你所看到的,即使是流的簡潔,你的代碼也不會變得更清晰。我會考慮評論中提出的建議以解決您的問題。