Java注解全面解析

khje5930 8年前發布 | 29K 次閱讀 Java Java開發

注解解析,包含基本語法,注解元素,快捷方式和JDK1.8注解增強的說明

基本語法

  • 注解定義看起來很像接口的定義。事實上,與其他任何接口一樣,注解也將會編譯成class文件。
  • </ul>

    @Target(ElementType.Method)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Test {}

    除了@符合以外,@Test的定義很像一個空的接口。定義注解時,需要一些 元注解 (meta-annotation),如 @Target@Retention

    • @Target用來定義注解將應用于什么地方(如一個方法或者一個域)

      </li>

    • @Retention用來定義注解在哪一個級別可用,在源代碼中(source),類文件中(class)或者運行時(runtime)

      </li>

    • 在注解中,一般都會包含一些元素以表示某些值。當分析處理注解時,程序可以利用這些值。沒有元素的注解稱為標記注解(marker annotation)

      </li>

    • 四種元注解,元注解專職負責注解其他的注解,所以這四種注解的Target值都是ElementType.ANNOTATION_TYPE

      </li> </ul>

      </tr> </thead>

      <td>@Target</td>

      </tr>

      <td>@Retention</td>

      </tr>

      <td>@Documented</td>

      </tr>

      <td>@Inherited</td>

      </tr> </tbody> </table>

      注解元素

      • 注解元素可用的類型如下:

        • 所有基本類型(int,float,boolean,byte,double,char,long,short)
        • String
        • Class
        • enum
        • Annotation
        • 以上類型的數組 如果使用了其他類型,那編譯器就會報錯。也不允許使用任何包裝類型。注解也可以作為元素的類型,也就是注解可以嵌套。 元素的修飾符,只能用 publicdefault
        • </ul> </li>

        • 默認值限制

          編譯器對元素的默認值有些過分挑剔。首先,元素不能有不確定的值。也就是說,元素必須要么具有默認值,要么在使用注解時提供元素的值。

          其次, 對于非基本類型的元素 ,無論是在源代碼中聲明,還是在注解接口中定義默認值, 都不能以null作為值 。這就是限制,這就造成處理器很難表現一個元素的存在或缺失狀態,因為每個注解的聲明中,所有的元素都存在,并且都具有相應的值。 為了繞開這個限制,只能定義一些特殊的值,例如空字符串或負數,表示某個元素不存在 。

          </li> </ul>

          @Target(ElementType.Method)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface MockNull {

          public int id() default -1;
          
          public String description() default "";
          
          

          }</pre>

          快捷方式

          何為快捷方式呢?先來看下springMVC中的Controller注解

          @Target({ElementType.TYPE})
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          @Component
          public @interface Controller {

          String value() default "";
          
          

          }</pre>

          可以看見Target應用于類、接口、注解和枚舉上,Retention策略為RUNTIME運行時期,有一個String類型的value元素。平常使用的時候基本都是這樣的:

          @Controller("/your/path")
          public class MockController { }

          這就是快捷方式,省略了名-值對的這種語法。下面給出詳細解釋:

          注解中定義了名為 value 的元素,并且在應用該注解的時候,如果該元素是唯一需要賦值的一個元素,那么此時無需使用名-值對的這種語法,而只需在括號內給出value元素所需的值即可。這可以應用于任何合法類型的元素,當然了,這限制了元素名必須為value。

          JDK1.8注解增強

          TYPE_PARAMETER和TYPE_USE

          在JDK1.8中 ElementType 多了兩個枚舉成員, TYPE_PARAMETERTYPE_USE ,他們都是用來限定哪個類型可以進行注解。舉例來說,如果想要對泛型的類型參數進行注解:

          public class AnnotationTypeParameter<@TestTypeParam T> {}

          那么,在定義@TestTypeParam時,必須在@Target設置 ElementType.TYPE_PARAMETER ,表示這個注解可以用來標注類型參數。例如:

          @Target(ElementType.TYPE_PARAMETER)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface TestTypeParam {}

          ElementType.TYPE_USE用于標注各種類型,因此上面的例子也可以將 TYPE_PARAMETER 改為 TYPE_USE ,一個注解被設置為 TYPE_USE ,只要是類型名稱,都可以進行注解。例如有如下注解定義:

          @Target(ElementType.TYPE_USE)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface Test {}

          那么以下的使用注解都是可以的:

          List<@Test Comparable> list1 = new ArrayList<>();
          List<? extends Comparable> list2 = new ArrayList<@Test Comparable>();
          @Test String text;
          text = (@Test String)new Object();
          java.util. @Test Scanner console;
          console = new java.util.@Test Scanner(System.in);

          PS:以上@Test注解都是在類型的右邊,要注意區分1.8之前的枚舉成員,例如:

          @Test java.lang.String text;

          在上面這個例子中,顯然是在進行text變量標注,所以還使用當前的@Target會編譯錯誤,應該加上 ElementType.LOCAL_VARIABLE

          <h4>@Repeatable注解</h4> <p>@Repeatable注解是JDK1.8新加入的,從名字意思就可以大概猜出他的意思(可重復的)。可以在同一個位置重復相同的注解。舉例: </p>

          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface Filter {

          String [] value();
          
          

          }</pre>

          如下進行注解使用:

          @Filter({"/admin","/main"})
          public class MainFilter { }

          換一種風格:

          @Filter("/admin")
          @Filter("/main")
          public class MainFilter {}

          在JDK1.8還沒出現之前,沒有辦法到達這種“風格”,使用1.8,可以如下定義@Filter:

          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          @Repeatable(Filters.class)
          public @interface Filter {

          String  value();
          
          

          }

          @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Filters {

          Filter [] value();
          
          

          }</pre>

          實際上這是編譯器的優化,使用@Repeatable時告訴編譯器,使用@Filters來作為收集重復注解的容器,而每個@Filter存儲各自指定的字符串值。

          JDK1.8在 AnnotatedElement 接口新增了 getDeclaredAnnotationsByTypegetAnnotationsByType ,在指定@Repeatable的注解時,會尋找重復注解的容器中。相對于,

          getDeclaredAnnotation和 getAnnotation 就不會處理@Repeatable注解。舉例如下:

          @Filter("/admin")
          @Filter("/filter")
          public class FilterClass {

          public static void main(String[] args) {
          
              Class<FilterClass> filterClassClass = FilterClass.class;
              Filter[] annotationsByType = filterClassClass.getAnnotationsByType(Filter.class);
              if (annotationsByType != null) {
                  for (Filter filter : annotationsByType) {
                      System.out.println(filter.value());
                  }
              }
              System.out.println(filterClassClass.getAnnotation(Filter.class));
          }
          

          }</pre>

          日志如下:

          /admin
          /filter
          null

          參考:

          Think in Java

          http://www.codedata.com.tw/java/jdk8-annotation-enhancement/ </div> </div>

          來自: http://9leg.com/java/2016/01/21/java-annotation.html

          </code></code></code></code></code></code></code></code></code></code></code></code></code></code></code>

           本文由用戶 khje5930 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
           轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
           本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
      注解 說明
      表示該注解可以用在什么地方,由ElementType枚舉定義
      CONSTRUCTOR :構造器的聲明
      FIELD :域聲明(包括enum實例)
      LOCAL_VARIABLE :局部變量聲明
      METHOD :方法聲明
      PACKAGE :包聲明
      PARAMETER :參數聲明
      TYPE :類、接口(包括注解類型)或enum聲明
      ANNOTATION_TYPE :注解聲明(應用于另一個注解上)
      TYPE_PARAMETER :類型參數聲明(1.8新加入)
      TYPE_USE :類型使用聲明(1.8新加入)
      PS:當注解未指定Target值時,此注解可以使用任何元素之上,就是上面的類型
      表示需要在什么級別保存該注解信息,由RetentionPolicy枚舉定義
      SOURCE :注解將被編譯器丟棄(該類型的注解信息只會保留在源碼里,源碼經過編譯后,注解信息會被丟棄,不會保留在編譯好的class文件里)
      CLASS :注解在class文件中可用,但會被VM丟棄(該類型的注解信息會保留在源碼里和class文件里,在執行的時候,不會加載到虛擬機(JVM)中)
      RUNTIME :VM將在運行期也保留注解信息,因此可以通過反射機制讀取注解的信息(源碼、class文件和執行的時候都有注解的信息)
      PS:當注解未定義Retention值時,默認值是CLASS
      表示注解會被包含在javaapi文檔中
      允許子類繼承父類的注解
sesese色