什麼是註解
註解是一種在類、方法、屬性、引數、變數等程式碼中新增一些描述資訊,這些資料可以通過反射來獲取到,然後針對註解資訊做相應操作
為什麼要學習註解
- 一些優秀的開源庫如Dragger、Retrofit、Butter Knife等都大量使用了註解,理解註解有助於我們學習這些第三方開源庫
- android support-annotations庫提供了大量註解如@NonNull、@IntgerRes、@Keep等,使用這些註解有助於我們優化程式碼,增加程式碼可讀性的同性,也能減少錯誤
Java 元註解的簡單說明
- @Target 描述註解的作用區域,常見取值有(TYPE FIELD METHOD PARAMETER)等
- @Retention 描述註解的生命週期
SOURCE 只保留在原始碼中,如@SuppressWarning作用是在編譯時抑制警告,不必寫入到class中
CLASS 編譯後保留在class檔案中,如butterknife框架@Bind 編譯時會將註解寫入class檔案中
RUNTIME 註解會在class位元組檔案中存在,在執行時可以通過反射獲取到相應資料 - @Document 說明該註解將被包含在javadoc中
- @Inherited:說明子類可以繼承父類中的該註解
自定義註解
借用別人的一個例項,根據類中註解建立資料庫表結構:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
複製程式碼
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;
}
複製程式碼
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
複製程式碼
@DBTable(name = "MEMBER")
public class Member {
@SQLString(30) String firstName;
@SQLString(value = 30,constraints = @Constraints(primaryKey = true))
String handle;
static int memberCount;
public String getHandle() { return handle; }
public String getFirstName() { return firstName; }
}
複製程式碼
import java.util.List;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
public class TableCreator {
public static void main(String[] args) throws Exception {
createTab(Member.class);
}
private static void createTab(Class<?> tabClass) {
DBTable dbTable = tabClass.getAnnotation(DBTable.class);
String tableName = dbTable.name(); //讀取註解中表名
if (tableName.length() < 1)
tableName = tabClass.getName().toUpperCase();
List<String> columnDefs = new ArrayList<>();
for (Field field : tabClass.getDeclaredFields()) {
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations(); //讀取變數註解建立資料表欄位
if(anns.length > 0) {
if (anns[0] instanceof SQLString) {
SQLString sString = (SQLString) anns[0];
if (sString.name().length() < 1)
columnName = field.getName().toUpperCase();
else
columnName = sString.name();
columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraints()));
}
}
}
StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
for (String columnDef : columnDefs)
createCommand.append("\n " + columnDef + ",");
String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";
System.out.println("Table Creation SQL for " + tabClass.getName() + " is :\n" + tableCreate);
}
private static String getConstraints(Constraints con) {
String constraints = "";
if (!con.allowNull())
constraints += " NOT NULL";
if (con.primaryKey())
constraints += " PRIMARY KEY";
if (con.unique())
constraints += " UNIQUE";
return constraints;
}
}
複製程式碼
使用android support-annotations中註解優化程式碼
- Nullness註解: @Nullable @NonNull
- 資源類註解:@StringRes @IdRes @ColorRes等
- @Keep 保持某個類或者函式不被混淆
- IntDef和StringDef註解
我們出於效能考慮經常用整形代替列舉,假設建立核心時有以下三程型別,我們可以定義一個@CoreType的註解,這樣初始化的時候傳的不是這三個值,編譯器就會報錯
public static final int ANDROID_WEBVIEW = 0;
public static final int XWALK_WEBVIEW = 1;
public static final int TENCENT_WEBVIEW = 2;
@IntDef({ANDROID_WEBVIEW, XWALK_WEBVIEW, TENCENT_WEBVIEW})
private @interface CoreType{}
public void init(Context context, @CoreType int coreType) {
mCoreType = coreType
}
複製程式碼