Thinking in Java這本書好久前就購買了,打算有時間看一下,由於本身的時間被本身安排的緊張,也沒時間看書。黃師傅上次課程講到了註解的使用和反射的使用,今天打算學習一下註解。該文章參考Thinking in Java的第20章Annotation。java
註解爲咱們代碼中添加信息提供了一種形式化的方法,使咱們能夠在稍後某個時刻很是方便的使用這些數據。程序員
JavaSE5內置了3個註解數據庫
除了這三個註解,Java還提供了四種胡姐,負責新註解的建立,咱們將稍後學習。數組
當咱們建立描述符合性質的類和接口時,一旦其中包含了重複性的工做,那就能夠考慮使用註解來簡化與自動化該過程,例如ide
在EJB中存在不少的額外工做,EJB3.0就是使用註解消除了它們。工具
編譯器要確保其構造路徑上必須有@Test註解的定義,咱們能夠建立一個經過反射機制來運行testExecute()方法的工具。學習
package littlepage.annotation.test1; public class Testable { public void execute(){ System.out.println("Executing...."); } @Test void testExecute(){execute();} }
備註接的方法與其餘方法沒有區別,在這個例子中,註解@Test能夠與任何修飾符做用於方法,例如public、static或者void。從語法角度看,註解的使用方式幾乎與修飾符使用如出一轍。ui
package littlepage.annotation.test1; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Test { }
除了@符號之外,@Test的定義很像一個空的接口。定義註解,你須要一些元註解(meta-annotation),如@Target和@Retention。@Target用來定義你的註解將用於什麼地方(例如一個方法或者一個域),@Retention用來定義註解在哪個級別可用,在源碼中(Source),類文件中(Class)或者運行時(Runtime)spa
在註解中,通常會包含一些元素以某些值。當分析處理註解時,程序或者工具可利用這些值。註解的元素看起來很像接口方法,惟一區別是你能夠用爲其指定默認值。code
沒有元素的註解稱爲標記註解,例如上面的@Test。
下面死一個簡單的註解,咱們可使用它來跟蹤項目用例。
package littlepage.annotation.test1; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface UseCase { public int id(); public String description() default "no description"; }
注意,id和description相似方法的定義,因爲便要一塊兒會對id進行類型檢查,所以將用例文檔追蹤數據庫與源代碼的關聯是可靠的。description元素有一個默認值,若是註解某方法沒有給出description的值,那麼處理器會使用該元素默認值。
下面一個類中有三個方法被註解的用例
package littlepage.annotation.test1; import java.util.List; public class PasswordUtils { @UseCase(id=47,description = "Password must contain at least one numeric") public boolean validatePassword(String password){ return (password.matches("\\w*\\d\\w*")); } @UseCase(id=48) public String encryptPassword(String password){ return new StringBuilder(password).reverse().toString(); } @UseCase(id=49,description = "New passwords can't equal previously used ones") public boolean checkForNewPassword(List<String> prevPasswords,String password){ return !prevPasswords.contains(password); } }
Java目前只內置了3種標準註解,以及四種元註解。元註解負責註解其餘註解。
圖:詳見Thinking in Java p622
若是沒有用來讀取註解的工具,那註解也不劊比註釋更加有用。使用註解的過程當中,很重要的一個部分是建立和使用註解處理器。Java SE5擴展了反射機制的API,幫助程序員構造這類工具。同時,它還提供了一個外部工具apt幫助程序員解析帶有註解的Java代碼。
下面是一個很是簡單的註解處理器,咱們將用它來讀取PasswordUtils類,並使用反射機制查找@UseCase標記。咱們爲其提供了一組id值,而後它會列出在PasswordUtils中找到的用例,以及缺失的 用例。
package littlepage.annotation.test1; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class UseCaseTracker { public static void trackUseCases(List<Integer> useCases, Class<?> clazz){ for (Method m:clazz.getDeclaredMethods()) { UseCase uc = m.getAnnotation(UseCase.class); if (uc != null) { System.out.println("Found Use Case:" + uc.id() + " " + uc.description()); useCases.remove(new Integer(uc.id())); } } } public static void main(String[] args) { List<Integer> useCases=new ArrayList<>(); Collections.addAll(useCases,47,48,49,50); trackUseCases(useCases,PasswordUtils.class); } }
這個程序用到了兩個反射的方法:getDeclaredMethods()和getAnnotation(),它們都屬於AnnotatedElement接口(Class,Method和Field等類都實現了該接口)。getAnnoation()方法返回指定類型的註解對象。在這裏就是UseCase。若是被註解方法上沒沒有該類型的豬價,則返回null值。而後咱們經過調用id和description的方法從返回的對象中提取元素的值。
標籤@UeCase由UseCase.java定義,其中包含int元素id,以及一個String元素description,註解元素可用類型以下所示:
若是你使用其餘類型,那麼編譯器就會報錯。也不容許使用任何包裝類型,不過因爲自動打包機制,這個算不上限制。註解也能夠做爲元素類型,稍後,咱們能夠看到,這是一個頗有用的技巧。
(淺識註解,博主學習速度太慢,須要慢慢消化 )