Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android —— 注解(Annotation)也被稱為元數據(Metadata)

Android —— 注解(Annotation)也被稱為元數據(Metadata)

編輯:關於Android編程

之前博主講xUtils的時候,介紹過注解,不過是蜻蜓點水,有興趣的同學可以先移步到xUtils介紹2,今天我們就來詳細解剖一下Android中注解的使用。

Java注解是附加在代碼中的一些元信息,用於一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。

講起注解,我為它分了四大塊,元注解、內建注解、自定義注解,還有xUtils中為我們提供的注解方式,下面我們就一一剖析。

一、元注解

實例:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

//其中的@interface是一個關鍵字,在設計annotations的時候必須把一個類型定義為@interface,而不能用class或interface關鍵字,由以上的源碼可以知道,他的elementType 可以有多個,一個注解可以為類的,方法的,字段的等等。

元注解,分為四種:包括 @Retention @Target @Document @Inherited四種。

@Retention:定義注解的保留策略。
通俗的講,它表示一個注解類型會被保留到什麼時候。
@Retention(RetentionPolicy.SOURCE)//注解僅存在於源碼中,在class字節碼文件中不包含。
@Retention(RetentionPolicy.CLASS)// 默認的保留策略,注解會在class字節碼文件中存在,但運行時無法得。
@Retention(RetentionPolicy.RUNTIME)// 注解會在class字節碼文件中存在,在運行時可以通過反射獲取到。

@Target:定義注解的作用目標。
@Target(ElementType.TYPE) //接口、類、枚舉、注解
@Target(ElementType.FIELD) //字段、枚舉的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法參數
@Target(ElementType.CONSTRUCTOR) //構造函數
@Target(ElementType.LOCAL_VARIABLE)//局部變量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包

@Document:說明該注解將被包含在javadoc中。
會被Javadoc工具文檔化。

@Inherited:說明子類可以繼承父類中的該注解。
這個比較難理解,這裡詳細講一下,一般用在自定義注解上。
我們自定義注解(Annotation)時,把自定義的注解標注在父類上不會被子類所繼承,但是我們可以在定義注解時給我們自定義的注解標注一個@Inherited注解來實現注解繼承。
注意點:
這種標有@Inherited注解的自定義的注解運用到類級別上和方法級別上是不一樣的,如果把標有@Inherited注解的自寶義的注解標注在類級別上,子類則可以繼承父類類級別的注解,反之,則不行。
實例:(標注在類級別)
1.定義一個自定義注解,包含一個方法value

@Inherited
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)

public @interface InheritedAnnotation {

    String value();

}

2.定義一個帶注解的抽象父類

@InheritedAnnotation(value = "parent AnnotarionParent ")
public abstract class AnnotarionParent {

    @InheritedAnnotation(value = "parent abstractMethod ")
    public abstract void abstractMethod();

    @InheritedAnnotation(value = "Parent's doExtends")
    public void doExtends() {
        Log.d("dongmj"," AbstractParent doExtends ...");
    }
}

3.定義一個子類繼承上面父類

public class SubAnnotation extends AnnotarionParent{

    @Override
    public void abstractMethod() {
        Log.d("dongmj","子類實現抽象父類的抽象方法");

    }

}

4.測試:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Class clazz = SubAnnotation.class; //1.獲得子類class類型
        try {
            Method method = clazz.getMethod("abstractMethod", new Class[]{});//2獲得方法
            if(method.isAnnotationPresent(InheritedAnnotation.class)){//3.判斷方法的注解類型
                InheritedAnnotation ma = method.getAnnotation(InheritedAnnotation.class);//4.得到方法的注解
                Log.d("dongmj","子類實現的抽象方法繼承到父類抽象方法中的Annotation,其信息如下:");
                Log.d("dongmj",ma.value()); //5.打印注解中的value方法
            }else{
                Log.d("dongmj","子類實現的抽象方法沒有繼承到父類抽象方法中的Annotation");
            }


            Method methodDoExtends = clazz.getMethod("doExtends", new Class[]{});
            if(methodDoExtends.isAnnotationPresent(InheritedAnnotation.class)){
                InheritedAnnotation mado = methodDoExtends.getAnnotation(InheritedAnnotation.class);
                Log.d("dongmj","子類實現的抽象方法繼承到父類抽象方法中的doExtends,其信息如下:");
                Log.d("dongmj",mado.value());
            }else{
                Log.d("dongmj","子類實現的抽象方法沒有繼承到父類抽象方法中的doExtends");
            }


            if(clazz.isAnnotationPresent(InheritedAnnotation.class)){
                InheritedAnnotation cla = clazz.getAnnotation(InheritedAnnotation.class);
                Log.d("dongmj","子類繼承到父類類上Annotation,其信息如下:");
                Log.d("dongmj",cla.value());
            }else{
                Log.d("dongmj","子類沒有繼承到父類類上Annotation");
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

}

結果:

09-18 15:11:39.898 32178-32178/com.example.annotationtest D/dongmj: 子類實現的抽象方法沒有繼承到父類抽象方法中的Annotation
09-18 15:11:39.908 32178-32178/com.example.annotationtest D/dongmj: 子類實現的抽象方法繼承到父類抽象方法中的doExtends,其信息如下:
09-18 15:11:39.908 32178-32178/com.example.annotationtest D/dongmj: Parent's doExtends
09-18 15:11:39.908 32178-32178/com.example.annotationtest D/dongmj: 子類繼承到父類類上Annotation,其信息如下:
09-18 15:11:39.908 32178-32178/com.example.annotationtest D/dongmj: parent AnnotarionParent 

二、內建注解

Java本身內建了一些注解,下面我們來介紹一下我們在日常開發中比較常見的注解:
@Override、@Deprecated、@SuppressWarnings。

@Override注解
定義如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

這個注解可以被用來修飾方法,並且它只在編譯時有效,在編譯後的class文件中便不再存在。這個注解的作用我們大家都不陌生,那就是告訴編譯器被修飾的方法是重寫的父類的中的相同簽名的方法,編譯器會對此做出檢查,若發現父類中不存在這個方法或是存在的方法簽名不同,則會報錯。

@Deprecated
定義如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

從它的定義我們可以知道,它會被文檔化,能夠保留到運行時,能夠修飾構造方法、屬性、局部變量、方法、包、參數、類型。這個注解的作用是告訴編譯器被修飾的程序元素已被“廢棄”,不再建議用戶使用。
Override就是用在方法上的注解,Deprecated是既可以用在方法上面,也可以用在類上面。

@SuppressWarnings
定義:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

它能夠修飾的程序元素包括類型、屬性、方法、參數、構造器、局部變量,只能存活在源碼時,取值為String[]。它的作用是告訴編譯器忽略指定的警告信息,它可以取的值如下所示:
deprecation:忽略使用了廢棄的類或方法時的警告;
unchecked:執行了未檢查的轉換;
fallthrough:swich語句款中case忘加break從而直接“落入”下一個case;
path:類路徑或原文件路徑等不存在;
serial:可序列化的類缺少serialVersionUID;
finally:存在不能正常執行的finally子句;
all:以上所有情況產生的警告均忽略。

用法:

@SuppressWarning(value={"deprecation", "unchecked"})
public void myMethos() {...} 

三、自定義注解

在自定義注解時,有以下幾點需要我們了解:

1)注解類型是通過”@interface“關鍵字定義的;
2)在”注解體“中,所有的方法均沒有方法體且只允許public和abstract這兩種修飾符號(不加修飾符缺省為public),注解方法不允許有throws子句;
3)注解方法的返回值只能為以下幾種:原始數據類型), String, Class, 枚舉類型, 注解和它們的一維數組,可以為方法指定默認返回值。

上面的實例也是自定義注解的栗子。再舉個

/**
 * 水果名稱注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}

/**
 * 水果顏色注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * 顏色枚舉
     * @author peida
     *
     */
    public enum Color{ BULE,RED,GREEN};

    /**
     * 顏色屬性
     * @return
     */
    Color fruitColor() default Color.GREEN;

}

/**
 * 水果供應者注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
    /**
     * 供應商編號
     * @return
     */
    public int id() default -1;

    /**
     * 供應商名稱
     * @return
     */
    public String name() default "";

    /**
     * 供應商地址
     * @return
     */
    public String address() default "";
}

這裡寫圖片描述

解析注解:
栗子:
public class AnnotationParser {
    public static void main(String[] args) {
        try {
            Class cls = AnnotationTest.class;
            for (Method method : cls.getMethods()) {
                MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
                if (methodInfo != null) {
                    System.out.println("method name:" + method.getName());
                    System.out.println("method author:" + methodInfo.author());
                    System.out.println("method date:" + methodInfo.date());
                    System.out.println("method version:" + methodInfo.version());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

四、利用xUtils中注解

關於這部分,主要是可以對findViewByid和onclick的優化

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved