Thinking in Annotation

Thinking in Java這本書好久前就購買了,打算有時間看一下,由於本身的時間被本身安排的緊張,也沒時間看書。黃師傅上次課程講到了註解的使用和反射的使用,今天打算學習一下註解。該文章參考Thinking in Java的第20章Annotation。java

簡單介紹

註解爲咱們代碼中添加信息提供了一種形式化的方法,使咱們能夠在稍後某個時刻很是方便的使用這些數據。程序員

內置註解:

JavaSE5內置了3個註解數據庫

  • @Override 覆蓋超類中的方法,若是不當心拼寫錯誤,或者方法簽名對不上覆蓋的方法,編譯器會發出錯誤提示
  • @Deprecated 若是程序員使用了註解爲它的元素,編譯器會發出警告信息
  • @Suppress Warnings 關閉不當的警告信息,在JavaSE5以前版本,也可使用該註解

除了這三個註解,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,註解元素可用類型以下所示:

  • 全部基本類型(int,float,boolean等)
  • String
  • Class
  • enum
  • Annotation
  • 以上類型的數組

若是你使用其餘類型,那麼編譯器就會報錯。也不容許使用任何包裝類型,不過因爲自動打包機制,這個算不上限制。註解也能夠做爲元素類型,稍後,咱們能夠看到,這是一個頗有用的技巧。

 

(淺識註解,博主學習速度太慢,須要慢慢消化 )

相關文章
相關標籤/搜索