首發於我的公眾號
註解基礎
0x00 概述
註解系列
本文主要是介紹註解的基礎知識,為後面的APT和JavaPoet打下基礎
0x01 什麼是註解
註解(Annotation)是Java5的一個新特性,是插入在程式碼中的一種註釋或者說是一種後設資料(meta data),這些註釋資訊可以在編譯期使用預編譯工具進行獲取處理,也可以在執行期使用Java反射機制來獲取,這取決於你的註解型別。
0x02 註解的語法及其定義
在Android中註解經常存在我們程式碼中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
getIntentData();
}
複製程式碼
上面的@Override
就是系統的註解,表明這是個重寫方法,點選原始碼可以看到長成下面的樣子
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
複製程式碼
實際中會帶有一些引數
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface run_methodInfo {
String name() default "long";
String data();
int id() default 365;
}
複製程式碼
@Retention @Target @Document @Inherited四種 是元註解即 “註解的註解”
@Target 表示該註解目標,可能的 ElemenetType 引數包括:
- ElemenetType.CONSTRUCTOR 構造器宣告
- ElemenetType.FIELD 域宣告(包括 enum 例項)
- ElemenetType.LOCAL_VARIABLE 區域性變數宣告
- ElemenetType.METHOD 方法宣告
- ElemenetType.PACKAGE 包宣告
- ElemenetType.PARAMETER 引數宣告
- ElemenetType.TYPE 類,介面(包括註解型別)或enum宣告
@Retention 表示該註解的生命週期,可選的 RetentionPolicy 引數包括
- RetentionPolicy.SOURCE 註解只保留在原始檔,當Java檔案編譯成class檔案的時候,註解被遺棄註解將被編譯器丟棄
- RetentionPolicy.CLASS 註解被保留到class檔案,但jvm載入class檔案時候被遺棄
- RetentionPolicy.RUNTIME 註解不僅被儲存到class檔案中,jvm載入class檔案之後,仍然存在;,因此可以通過反射機制讀取註解的資訊
@Documented 指示將此註解包含在 javadoc 中 @Inherited 指示允許子類繼承父類中的註解
使用註解需要遵守它的規則:
- Annotation型定義為@interface, 所有的Annotation會自動繼承java.lang.Annotation這一介面,並且不能再去繼承別的類或是介面.
- 引數成員只能用public或預設(default)這兩個訪問權修飾
- 引數成員只能用基本型別byte,short,char,int,long,float,double,boolean八種基本資料型別和String、Enum、Class、annotations等資料型別,以及這一些型別的陣列.
- 要獲取類方法和欄位的註解資訊,必須通過Java的反射技術來獲取 Annotation物件,因為你除此之外沒有別的獲取註解物件的方法(分為編譯期還是執行期)
0x03 使用
(這裡僅介紹最常見的執行期的註解,編譯期註解涉及到apt、javapoet會單獨再開一篇介紹)
Step One 定義註解
先看三個Runtime註解,包括類、方法、欄位,
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface run_classInfo {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface run_methodInfo {
String name() default "long";
String data();
int id() default 365;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface run_fieldInfo {
int[] value();
}
複製程式碼
Step two 使用這些註解,
@run_classInfo("類註解RunTime Class")
public class RunTimeTest {
@run_fieldInfo(value = {77, 88})
public String fieldInfo = "filedInfo";
@run_fieldInfo(value = {163})
public int id = 55;
@run_methodInfo(name = "彩筆學長", data = "finance")
public static String getMethod() {
return RunTimeTest.class.getSimpleName();
}
}
複製程式碼
使用反射解析註解
/**
* 解析執行時註解
*/
private void showRunTimeInfo() {
StringBuffer sb = new StringBuffer();
//獲取Class 註解
Class<?> clazz = RunTimeTest.class;
Constructor<?>[] constructors = clazz.getConstructors();
//獲取包含的註解類資訊
run_classInfo runClassInfo = clazz.getAnnotation(run_classInfo.class);
if (runClassInfo != null) {
//獲取class註解
sb.append("Class註解: ").append("\n");
sb.append(Modifier.toString(clazz.getModifiers())).append(" ")
.append(clazz.getSimpleName()).append("\n");
sb.append("註解值:").append("\n")
.append(runClassInfo.value()).append("\n\n");
}
//獲取Field註解
sb.append("Field註解:").append("\n");
Field[] fields = clazz.getDeclaredFields(); //獲取自身的不包括繼承類
for (Field field : fields) {
//獲取field註解類資訊
run_fieldInfo fieldInfo = field.getAnnotation(run_fieldInfo.class);
if (fieldInfo != null) {
sb.append(Modifier.toString(field.getModifiers())).append(" ")
.append(field.getType().getSimpleName()).append(" ")
.append(field.getName()).append("\n");
sb.append("註解值: ").append("\n")
.append(Arrays.toString(fieldInfo.value())).append("\n\n");
}
}
//獲取Method 註解
sb.append("Method註解: ").append("\n");
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
run_methodInfo methodInfo = method.getAnnotation(run_methodInfo.class);
if (methodInfo != null) {
sb.append(Modifier.toString(method.getModifiers())).append(" ")
.append(method.getReturnType().getSimpleName()).append(" ")
.append(method.getName()).append("\n");
sb.append("註解值:").append("\n");
sb.append("name: ").append(methodInfo.name()).append("\n");
sb.append("data: ").append(methodInfo.data()).append("\n");
sb.append("id: ").append(methodInfo.id()).append("\n");
}
}
tvDes.setText(sb.toString());
}
複製程式碼
0x04 參考文獻
-
歡迎關注我的公眾號,一起學習,共同提高~ 複製程式碼