瘋狂Java學習筆記(53)------------Annotation(注釋)第二篇

      網友投稿 755 2025-03-31

      瘋狂Java學習筆記(53)------------Annotation(注釋)第二篇

      JDK的元Annotation

      JDK除了java.lang下提供了3個基本Annotation之外,還在java.lang.annotation包下提供了四個Meta Annotation(元Annotation),這四個都是用于修飾其它Annotation定義

      (1)使用@Retention

      @Retention只能用于修飾一個Annotation定義,用于該Annotation可以保留多長時間,@Retention包含一個RetentionPolicy類型的value成員變量,所以使用@Retention時必須為該value成員變量指定值.

      value成員變量的值只能是如下三個

      RetentionPolicy.CLASS:編譯器將把注釋記錄在class文件中。當運行Java程序時,JVM不再保留注釋。這是默認值

      RentionPolicy.RUNTIME:編譯器將把注釋記錄在class文件中。當運行java程序時,JVM也會保留注釋,程序也可以通過反射獲取該注釋。

      RentionPolicy.SOURCE:編譯器直接丟棄這種策略的注釋。

      在前面的程序中,因為我們要通過反射獲取注釋信息,所以我們指定value屬性值為RetentionPolicy.RUNTIME. 使用@Retention元數據Annotation可采用如下代碼為value指定值.

      //定義下面的Testable Annotation的保留到過行時

      @Retention(value=RetentionPolicy.RUNTIME)

      public @interface Testable{}

      也可以采用如下代碼來為value指定值

      @Retention(RetentionPolicy.SOURCE)

      public @interface Testable{}

      上面代碼使用@Retention元數據Annotation時,并未直接通過value=RetentionPolicy.SOURCE的方式來為成員變量指定值,這是因為如果Annotation的成員變量名為value時,程序中可以直接在Annotation后的括號里指定該成員變量的值,無須用name=value的形式.

      說明

      如果我們定義的Annotation類型里只有一個value成員變量,使用該Annotation時可以直接在Annotation后的括號里指定value成員變量的值,無須使用name=value的形式。

      (2)使用@Target

      @Target也是用于修飾一個Annotation定義,它用于指定被修飾的Annotation能用于修飾哪些程序元素。@Target Annotation也包含一個名為value的成員變量。該成員變量的值只能是如下幾個

      ElementType.ANNOTATION_TYPE: 指定該策略的Annotation只能修飾Annotation

      ElementType.CONSTRUCTOR:指定該策略的Annotation能修飾構造器

      ElementType.FIELD:?????????????????指定該策略的Annotation只能修飾成員變量

      ElementType.LOCAL_VARIABLE:指定該策略的Annotation只能修飾局部變量

      ElementType.METHOD?????????????指定該策略的Annotation只能修飾方法定義

      ElementType.PACKAGE?????????? 指定該策略的Annotaion只能修飾包定義

      ElementType.PARAMETER???? ?指定該策略的Annotation可以修飾參數

      ElementType.TYPE?????????????????? 指定該策略的Annotaion可以修飾類,接口(包括注釋類型)或枚舉定義

      與使用@Retention類似的是,使用@Target也可以直接在括號里指定value值,可以無須使用name=value的形式。如

      下代碼指定@ActionListenerFor Annotation只能修飾成員變量

      @Target(ElementType.FIELD)

      public @interface ActionListenerFor{}

      如下代碼指定@Testable Annotation只能修飾方法

      @Target(ElementType.METHOD)

      public @interface Testable{}

      (3)使用@Documented

      @Documented用于指定該元Annotation修飾的Annotation類將被javadoc工具提取成文檔,如果定義Annotatin類時使用了@Documented修飾,則所有使用該Annotation修飾的程序元素API文檔中將會包含該Annotation說明

      下面程序定義了一個Testable Annotation程序使用@Documented來修飾@Testable Annotation定義,所以該Annotation將被 javadoc工具提取

      @Retention(RetentionPolicy.RUNTIME)

      @Target(ElementType.METHOD)

      //定義Testable Annotation將被javadoc工具提取

      @Documented

      public @interface Testable

      {

      }

      上面程序中的@Documented代碼決定了所有使用@Testable Annotation的地方都會被javadoc工具提取到api文檔中

      下面程序中定義了一個 MyTest類,該類中的infor方法使用Testable Annotation修飾

      程序清單

      public class MyTest

      {

      //使用@Testable修飾info方法

      @Testable

      public void info()

      {

      System.out.println("info方法...");

      }

      }

      (4)使用@Inherited

      @Inherited元Annotation指定被它修飾的Annotation將具有繼承性。如果某個類使用了Annotaion(使用Annotation時使用了@Inherited修飾)修飾,則其子類將自動具有A注釋。

      下面使用@Inherited元數據注釋定義了一個Inherited Annotation,該Annotation將具有繼承性

      程序清單

      @Target(ElementType.TYPE)

      @Retention(RetentionPolicy.RUNTIME)

      // @Inherited

      public @interface Inheritable

      {

      }

      上面程序中表明了@Inheritable Annotation具有繼承性,如果某個類使用了該Annotation 修飾,則該類的子類將自動具有@Inheritable Annotation

      下面程序定義了一個Base基類,該基類使用了@Inherited修飾,則Base類的子類將自動具有@Inherited Annotation

      程序清單

      //使用@Inheritable修飾的Base類

      @Inheritable

      class Base

      {

      }

      //TestInheritable類只是繼承了Base類,

      //并未直接使用@Inheritable Annotiation修飾

      public class TestInheritable extends Base

      {

      public static void main(String[] args)

      {

      //打印TestInheritable類是否具有Inheritable Annotation

      System.out.println(TestInheritable.class.isAnnotationPresent(Inheritable.class));

      }

      }

      總結

      1.上面程序中的Base類使用了@Inheritable Annotation修飾,而該Annotaion具有可繼承性,所以其子類也將具有@Inheritable Annotation,運行上面程序看到輸出 true

      2.如果將上面的Inheritable.java程序中的@Inherited注釋或者刪除,將會導致Inheritable Annotation不具有繼承性,運行上面程序將會輸出 false

      使用APT處理Annotation

      APT(Annotation processing tool)是一種處理注釋的工具,它對源代碼文件進行檢測找出其中的Annotation,使用Annotation進行額外的處理。

      Annotation處理器在處理Annotation時可以根據源文件中的Annotation生成額外的源文件和其它的文件(文件具體內容由Annotation處理器的編寫者決定),APT還會編譯生成的源文件和原來的源文件,將它們一起生成class文件.

      使用APT主要的目的是簡化開發者的工作量,因為APT可以編譯程序源代碼的同時,生成一些附屬文件(比如源文件,類文件,程序發布描述文件等),這些附屬文件的內容也都是與源代碼相關的,換句話說,使用APT可以代替傳統的對代碼信息和附屬文件的維護工作。

      如果有過Hibernate開發經驗的朋友可能知道每寫一個Java文件,還必須額外地維護一個Hibernate映射文件(一個名為*.hbm.xml的文件,當然可以有一些工具可以自動生成),下面將使用Annotation來簡化這步操作。

      為了使用系統的apt工具來讀取源文件中的Annotation,程序員必須自定義一個Annotation處理器,編寫Annotation處理器需要使用JDK lib目錄中的tools.jar 里的如下4個包.

      com.sun.mirror.apt:和APT交互的接口

      com.sun.mirror.declaration:包含各種封裝類成員,類方法,類聲明的接口。

      com.sun.mirror.type:包含各種封裝源代碼中程序元素的接口。

      com.sun.mirror.util:提供了用于處理類型和聲明的一些工具。

      每個Annotation處理器需要實現com.sun.mirror.apt包下的AnnotationProcessor接口,這個接口中定義了一個"process"方法,該方法是由apt調用Annotation處理器時將被用到的。

      一個Annotation處理器可以處理一種或多種Annotation類型。

      1.通常情況下,Annotation處理器實例是由其相應的工廠返回,Annotation處理器工廠應該實現AnnotationProcessorFactory接口,APT將調用工廠類的getProcessorFor方法來獲得Annotation處理器。

      2.在調用過程中,APT將提供給工廠類一個AnnotationProcessorEnvironment對象.

      3.AnnotationProcessorEnvironment對象是APT工具與注釋環境通信的途徑。

      使用APT工具來處理源文件時,APT首先檢測在源代碼文件中包含哪些Annotation,然后APT將查找所需的處理器工廠,并由工廠來返回相應的Annotation處理器。如果該處理器工廠支持這些Annotaion,處理器工廠返回的Annotaion處理器將會處理這些Annotation,如果生成的源文件中再次包含Annotaion,APT將會重復上面過程,直至沒有新文件生成。

      為了說明使用APT來根據源文件中的注釋來生成額外的文件,下面將定義三個Annotation類型,分別用于修飾持久化類,標識屬性和普通屬性。

      程序清單

      修飾表屬性

      @Persistent(table="persons_table")

      public class Person

      {

      @IdProperty(column="person_id",type="integer",generator="identity")

      private int id;

      @Property(column="person_name",type="string")

      private String name;

      @Property(column="person_age",type="integer")

      private int age;

      public Person()

      {

      }

      public Person(int id , String name , int age)

      {

      this.id = id;

      this.name = name;

      this.age = age;

      }

      public void setId(int id)

      {

      this.id = id;

      }

      public int getId()

      {

      return this.id;

      }

      public void setName(String name)

      {

      this.name = name;

      }

      public String getName()

      {

      return this.name;

      }

      public void setAge(int age)

      {

      this.age = age;

      }

      public int getAge()

      {

      return this.age;

      }

      }

      定義了三個Annotation之后,下面我們提供一個簡單的Java類文件,這個Java類文件使用了上面三個Annotation來修飾

      @Persistent(table="persons_table")

      public class Person

      {

      @IdProperty(column="person_id",type="integer",generator="identity")

      private int id;

      @Property(column="person_name",type="string")

      private String name;

      @Property(column="person_age",type="integer")

      private int age;

      public Person()

      {

      }

      public Person(int id , String name , int age)

      {

      this.id = id;

      this.name = name;

      this.age = age;

      }

      public void setId(int id)

      {

      this.id = id;

      }

      public int getId()

      {

      return this.id;

      }

      public void setName(String name)

      {

      this.name = name;

      }

      public String getName()

      {

      return this.name;

      }

      public void setAge(int age)

      {

      this.age = age;

      }

      public int getAge()

      {

      return this.age;

      }

      }

      上面Person類是一個非常普通的Java類,但這個普通的Java類使用了@Persistent,@IdProperty,@IdPropery三個Annotation。下面我們為這三個Annotation提供了一個Annotation處理器,該處理器的功能是根據注釋來生成一個Hibernate的映射文件.

      程序清單

      import com.sun.mirror.apt.*;

      import com.sun.mirror.declaration.*;

      import com.sun.mirror.type.*;

      import com.sun.mirror.util.*;

      import java.beans.*;

      import java.io.*;

      import java.util.*;

      import java.lang.reflect.*;

      public class HibernateAnnotationProcessor implements AnnotationProcessor

      瘋狂Java學習筆記(53)------------Annotation(注釋)第二篇

      {

      //Annotation處理器環境,是該處理器與APT交互的重要途徑

      private AnnotationProcessorEnvironment env;

      //構造HibernateAnnotationProcessor對象時,獲得處理器環境

      public HibernateAnnotationProcessor(AnnotationProcessorEnvironment env)

      {

      this.env = env;

      }

      //循環處理每個對象

      public void process()

      {

      //遍歷每個class文件

      for (TypeDeclaration t : env.getSpecifiedTypeDeclarations())

      {

      //定義一個文件輸出流,用于生成額外的文件

      FileOutputStream fos = null;

      //獲取正在處理的類名

      String clazzName = t.getSimpleName();

      //獲取類定義前的Persistent Annotation

      Persistent per = t.getAnnotation(Persistent.class);

      //當per Annotation不為空時才繼續處理

      if(per != null)

      {

      try

      {

      //創建文件輸出流

      fos = new FileOutputStream(clazzName + ".hbm.xml");

      PrintStream ps = new PrintStream(fos);

      //執行輸出

      ps.println("");

      ps.println("

      ps.println(" PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"");

      ps.println(" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">");

      ps.println("");

      ps.print("

      //輸出per的table()的值

      ps.println("" table="" + per.table() + "">");

      for (FieldDeclaration f : t.getFields())

      {

      //獲取指定FieldDeclaration前面的IdProperty Annotation

      IdProperty id = f.getAnnotation(IdProperty.class);

      //如果id Annotation不為空

      if (id != null)

      {

      //執行輸出

      ps.println("

      + f.getSimpleName()

      + "" column="" + id.column()

      + "" type="" + id.type()

      + "">");

      ps.println("

      + id.generator() + ""/>");

      ps.println(" ");

      }

      //獲取指定FieldDeclaration前面的Property Annotation

      Property p = f.getAnnotation(Property.class);

      //如果p Annotation不為空

      if (p != null)

      {

      //執行輸出

      ps.println("

      + f.getSimpleName()

      + "" column="" + p.column()

      + "" type="" + p.type()

      + ""/>");

      }

      }

      ps.println(" ");

      ps.println("");

      }

      catch (Exception e)

      {

      e.printStackTrace();

      }

      finally

      {

      //關閉輸出流

      try

      {

      if (fos != null)

      {

      fos.close();

      }

      }

      catch (IOException ex)

      {

      ex.printStackTrace();

      }

      }

      }

      }

      }

      }

      上面的Annotation處理器比較簡單,與前面通過反射來獲取Annotation信息不同的是,這個Annotation處理器使用AnnotationProcessorEnvironment來獲取Annotation信息,AnnotationProcessorEnvironment包含了一個getSpecifiedTypeDeclarations方法,可獲取所有需要處理的類聲明,這個類聲明可包括類,接口,和枚舉等聲明,由TypeDeclaration對象表地示,與Classc對象的功能大致相似,區別只是TypeDeclaration是靜態,只要有類文件就可以獲得該對象,而Class是動態的,必須由虛擬機裝載了指定類文件后才會產生。

      TypeDeclaration又包含了如下三個常用方法來獲得對應的程序元素。

      getFields

      :獲取該類聲明里的所有成員變量聲明,返回值是集合元素FieldDeclaration的集合

      getMethods

      :獲取該類聲明里的所有成員聲明,返回值是集合元素MethodDeclaration的集合

      getPackage

      :獲取該類聲明里的包聲明,返回值是TypeDeclaration

      上面三個方法返回的TypeDeclaration,FieldDeclaration,MethodDeclaration都可調用getAnnotation方法來訪問修飾它們的Annotation,上面程序中就是獲取不同程序元素的Annotation的代碼。

      提供了上面的Annotation處理器類之后,還應該為該Annotation處理器提供一個處理工廠,處理工廠負責決定該處理器支持哪些Annotation,并通過getProcessorFor方法來生成一個Annotation處理哭對象。

      程序清單如下

      import com.sun.mirror.apt.*;

      import com.sun.mirror.declaration.*;

      import com.sun.mirror.type.*;

      import com.sun.mirror.util.*;

      import java.beans.*;

      import java.io.*;

      import java.util.*;

      public class HibernateAnnotationFactory implements AnnotationProcessorFactory

      {

      //所有支持的注釋類型

      public Collection supportedAnnotationTypes()

      {

      return Arrays.asList("Property" , "IdProperty" , "Persistent");

      }

      //返回所有支持的選項

      public Collection supportedOptions()

      {

      return Arrays.asList(new String[0]);

      }

      //返回Annotation處理器

      public AnnotationProcessor getProcessorFor(Set atds,AnnotationProcessorEnvironment env)

      {

      return new HibernateAnnotationProcessor(env);

      }

      }

      提供了上面的處理器工廠后,就可以使用API工具來處理上面的Person.java源文件,并根據該源文件來生成一個XML文件。 APT工具位于JDK的安裝路徑的bin路徑下。。

      java Annotation的講解就這些了,需要好好看一看呀!

      博客借鑒http://blog.sina.com.cn/s/blog_4c925dca0100hsyt.html

      http://blog.csdn.net/zhai56565/article/details/40503743

      Java JDK

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel底色怎么設置(excel底色怎么設置到無法更改)
      下一篇:wps表格如何做柱狀圖呢(wps怎么把表格做成柱狀圖)
      相關文章
      亚洲第一AAAAA片| 久久久久亚洲av毛片大| 亚洲AV综合永久无码精品天堂| 亚洲卡一卡2卡三卡4卡无卡三| 亚洲综合伊人久久综合| 国产成人亚洲精品无码AV大片| 亚洲无人区码一二三码区别图片 | 亚洲最大黄色网站| 久久亚洲国产精品五月天| 亚洲精品乱码久久久久久| 亚洲综合网站色欲色欲| 久久精品国产精品亚洲| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 精品亚洲成a人片在线观看| 久久精品国产亚洲AV麻豆王友容| 亚洲综合伊人久久综合| 亚洲精品~无码抽插| 亚洲国产精品VA在线看黑人| 亚洲爆乳无码专区| 亚洲AV无码成人精品区天堂 | 亚洲国产精品xo在线观看| 亚洲国产精品久久网午夜 | 国产亚洲视频在线观看| 亚洲国产成人久久综合碰| 亚洲av无码成人精品区在线播放| 国产精品亚洲а∨无码播放麻豆| 亚洲XX00视频| 国产亚洲精品免费视频播放 | 亚洲免费电影网站| 国产精品久久亚洲不卡动漫| 中文日韩亚洲欧美制服| 亚洲国产欧美一区二区三区| www亚洲精品久久久乳| 亚洲AV永久无码精品一区二区国产| 亚洲av无码成人精品区在线播放| 久久亚洲AV永久无码精品| 国产精品亚洲一区二区三区在线| 亚洲av日韩av不卡在线观看| 亚洲沟沟美女亚洲沟沟| 亚洲最大中文字幕无码网站| 亚洲av日韩综合一区二区三区|