4.3 註解(Annotation)

1.註解

註解(Annotation)也被稱爲元數據(Metadata),是在Java SE 5中提供的一個新特性。Annotation可以用來修飾類,屬性,方法。在Java中,除了使用系統內置的Annotation以外,用戶還能夠通過自定義Annotation來實現所需要的功能。下面就來看一下如何使用自定義的Annotation。
又分爲標準註解和元註解。

1.1 標準註解

  • @Override:對覆蓋超類中的方法進行標記,如果被標記的方法並沒有實際覆蓋超類中的方法,則編 譯器會發出錯誤警告。
  • @Deprecated:對不鼓勵使用或者已過時的方法添加註解,當編程人員使用這些方法時,將會在編譯 時顯示提示信息。
  • @SuppressWarnings:選擇性地取消特定代碼段中的警告。
  • @SafeVarargs:JDK 7新增,用來聲明使用了可變長度參數的方法,其在與泛型類一起使用時不會出現 類型安全問題

1.2 元註解

在Java中目前包含及四種元註解。元註解是專門用來負責註解其他的註解。所以自定義註解也是通過元註解來完成的。首先在這裏來看一下Java中的四種元註解。

@Target

註解所修飾的對象範圍。

其中的ElementType取值如下:

TYPE:類,接口或者是enum聲明
FIELD:域聲明(包括enum實例)
METHOD:方法聲明
PARAMETER:參數聲明
CONSTRUCTOR:構造器聲明
LOCAL_VARIABLE:局部變量聲明
ANNOTATION_TYPE:註解類型聲明
PACKAGE:包聲明

@Retention

用來聲明註解的保留策略

其中RetentionPolicy取值如下:

SOURCE:只在源碼中保留,該註解將會被編譯器丟掉
CLASS:註解在class文件中可用,但是會被VM丟棄
RUNTIME:VM會在運行時保留註解,這時可以通過反射讀取註解信息。

@Documented

表示在Javadocs中包含這個註解。

@Inherited

表示允許子類繼承父類中的註解

2.定義註解

2.1 基礎定義

定義新的註解類型使用@interface關鍵字,

public @interface Swordman{
	String name() default "李丹";
	int age() default 22;
	...
}

簡單使用

@Swordman(name ="張三",age=11)
public class AnnotationTest{
	
	...
}

2.2 定義運行時註解

可以用@Retention來設定註解的保留策略,這 3 個策略的生命週期長度爲 SOURCE <CLASS< RUNTIME

@Retention(RetentaionPolicy.RUNTIME)
public @interface Swordman{
	String name() default "李丹";
	int age() default 22;
	...
}

2.3 定義編譯時註解

@Retention(RetentaionPolicy.CLASS)
public @interface Swordman{
	String name() default "李丹";
	int age() default 22;
	...
}

3.註解處理器

不同的註解有不同的註解處理器。 雖然註解處理器的編寫會千變萬化,但是其也有處理標準,比如:針對運行時註解會採用反射機制處理, 針對編譯時註解會採用 AbstractProcessor 來處理

3.1 編譯時註解

3.1.1 定義註解

使用Android studio 新建一個java Library ,這個Library名爲annotations 存放註解。

@Retention(RetentaionPolicy.CLASS)
@Target(FIELD) // 修飾變量
public @interface BindView{
	 
	int age() default 1;
	...
}

3.1.2 編寫註解處理器

再新建一個Java Library來存放註解處理器,這個Library名爲processor。我們來配置 processor庫的build.gradle

dependencied{
	compile fileTree(include:['*.jar'],dir:'libs')
	compile project(':annotaions')
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"
public class ClassProcessor extends AbstractProcessor {

    /**
     * 初始化
     * @param processingEnv
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        Filer filer = processingEnv.getFiler();
        Messager messager = processingEnv.getMessager();
        Elements elementUtils = processingEnv.getElementUtils();
    }
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();

    }
}

  • init:被註解處理工具調用,並輸入 ProcessingEnviroment 參數。ProcessingEnviroment提供很多有用的 工具類,比如Elements、Types、Filer和Messager等。
  • process:相當於每個處理器的主函數main(),在這裏寫你的掃描、評估和處理註解的代碼,以及生 成Java文件。輸入參數RoundEnviroment,可以讓你查詢出包含特定註解的被註解元素。
  • getSupportedAnnotationTypes:這是必須指定的方法,指定這個註解處理器是註冊給哪個註解的。注 意,它的返回值是一個字符串的集合,包含本處理器想要處理的註解類型的合法全稱。
  • getSupportedSourceVersion:用來指定你使用的 Java 版本,通常這裏返回 SourceVersion.latestSupported()。

參考:Android 進階之光

3.1.3 註冊–註解解析器

使用谷歌開源的AutoService,它用來幫助開 發者生成META-INF/services/javax.annotation.processing.Processor文件。首先我們添加該開源庫,可以在 File→Project Structure 搜索“auto-service”查找該庫並添加

最後在註解處理器ClassProcessor中添加@AutoService 就可以了。

@AutoService(Processor.class)
public class ClassProcessor extends AbstractProcessor {

3.2 運行時註解

運行時解析需要用到反射機制。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Get {
    String url() default "";

}

//使用
public class ApiSevice {
    @Get(url = "baidu.com")
   public String getNetData(){

        return null;
    }
}

代碼動態獲取


        Method[] declaredMethods = ApiSevice.class.getDeclaredMethods();

        for (int i = 0; i < declaredMethods.length; i++) {
            Method method = declaredMethods[i];
            Get annotation = method.getAnnotation(Get.class);
            String url = annotation.url();

            Log.d(TAG, "onCreate: "+url);
        }

3.4 應用註解

在主項目build.gradle文件裏添加依賴

   implementation project(path: ':annotation')
    implementation project(path: ':processor')

然後重新編譯整個工程。

主項目引用的processor只在編譯的時候起到實際作用,比如打包,運行的時候沒有必要引用,怎麼解決呢?
接下來我們引入android-apt插件就能解決這個問題。

1.在工程的build.gradle裏添加

   classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

2.更改依賴

apply plugin:'com.neenbedankt.android-apt'

...
deoebdebcies{
	...
	apt project(path: ':processor')
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章