java註解基礎與使用

whywhy發表於2018-02-11

什麼是註解

註解是一種在類、方法、屬性、引數、變數等程式碼中新增一些描述資訊,這些資料可以通過反射來獲取到,然後針對註解資訊做相應操作

為什麼要學習註解

  • 一些優秀的開源庫如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
    }
複製程式碼

相關文章