java 學習自定義註解Annotation

Annotation 註解相信大家平時經常用到,比如常見的有@Override  @Deprecated  @SuppressWarnings

還有很多第三方框架也用到了自定義註解,以前一直覺得很神奇,其實學習自定義才發現還是很簡單的嘛


什麼是註解?

由於不擅言辭,我就直接引用大神的博客介紹了,以下是大神博客地址

http://blog.csdn.net/hai_qing_xu_kong/article/details/51779695    點擊打開鏈接

註解是一種元數據, 可以添加到java代碼中. 類、方法、變量、參數、包都可以被註解,註解對註解的代碼沒有直接影響


首先了解下元註解,


元註解就是用來定義註解的註解.其作用就是定義註解的作用範圍, 使用在什麼元素上等等, 

元註解共有四種@Retention, @Target, @Inherited, @Documented


@Target:


   @Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。 
  作用:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方) 
  取值(ElementType)有: 
    1.CONSTRUCTOR:用於描述構造器 
    2.FIELD:用於描述域 
    3.LOCAL_VARIABLE:用於描述局部變量 
    4.METHOD:用於描述方法 
    5.PACKAGE:用於描述包 
    6.PARAMETER:用於描述參數 
    7.TYPE:用於描述類、接口(包括註解類型) 或enum聲明


@Retention:


  @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因爲Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命週期”限制。 
  作用:表示需要在什麼級別保存該註釋信息,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效) 
  取值(RetentionPoicy)有: 
    1.SOURCE:在源文件中有效(即源文件保留) 
    2.CLASS:在class文件中有效(即class保留) 
    3.RUNTIME:在運行時有效(即運行時保留)


@Documented:


  @Documented用於描述其它類型的annotation應該被作爲被標註的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個標記註解,沒有成員。


@Inherited:


  @Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。如果一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。 
  注意:@Inherited annotation類型是被標註過的class的子類所繼承。類並不從它所實現的接口繼承annotation,方法並不從它所重載的方法繼承annotation。 
  當@Inherited annotation類型標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。


其中, @Retention是定義保留策略, 直接決定了我們用何種方式解析. SOUCE級別的註解是用來標記的, 比如Override, SuppressWarnings. 我們真正使用的類型是CLASS(編譯時)和RUNTIME(運行時)


自定義註解:


  使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節。在定義註解時,不能繼承其他的註解或接口。@interface用來聲明一個註解,其中的每一個方法實際上是聲明瞭一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過default來聲明參數的默認值。 


以上很大一篇都是詳細介紹註解的,現在直接來自定義吧


我總共創建了4個類,Person 和 PersonAttr 就是定義的註解,LaoFuzi是使用註解的類,MainActivity是運行效果的類


先看下Person

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定義用於方法描述的註解
 * Created by Alex on 2017/11/23.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Person {

    boolean beautiful() default false;

    int age() default 0;

    String name() default "Alex";
}

這個註解用於方法的描述,所以用@Target({ElementType.METHOD}),保存時機一般都是用@Target({ElementType.METHOD}),因爲我們絕大部分都是需要運行時用

內部定義了幾個方法,後面的返回的默認值,返回值必須是可以定義常量的類型


再看下PersonAttr

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定義用於成員變量描述的註解
 * Created by Alex on 2017/11/23.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface PersonAttr {

    String value();

}

這個註解用於描述成員變量,比如很多請求框架都用到,便於解析字段,跟Person差不多,只是@Target({ElementType.FIELD})這裏改變了下,當然還可以定義其他類型


LaoFuzi,使用剛纔定義的註解,方法和成員變量都用到了

public class LaoFuzi {

    @PersonAttr("name")
    public String name;

    @Person(beautiful = false, age = 28, name = "老夫子")
    public void printPersonInfo() {

    }
}


最後看下效果

private static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Method[] methods = LaoFuzi.class.getDeclaredMethods();
    for (Method method: methods) {
        Person person = method.getAnnotation(Person.class);
        if (person != null) {
            Log.d(TAG, person.name() + " "  + person.age() + " " + person.beautiful());
        }
    }

    Field[] fields = LaoFuzi.class.getDeclaredFields();
    for (Field field : fields) {
        PersonAttr personAttr = field.getAnnotation(PersonAttr.class);
        if (personAttr != null) {
            Log.d(TAG, personAttr.value());
        }
    }

}

打印結果:

11-23 15:41:31.617 9793-9793/android.example.com.customannotationdemo D/MainActivity: 老夫子 28 false
11-23 15:41:31.617 9793-9793/android.example.com.customannotationdemo D/MainActivity: name


demo 地址

http://download.csdn.net/download/msn465780/10130482  點擊打開鏈接

到這裏已經完成了自定義註解,是不是很簡單啊,又可以愉快的玩耍了大笑


發佈了140 篇原創文章 · 獲贊 137 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章