目錄
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')
}