註解基礎

首發於個人公衆號
註解基礎html

0x00 概述

註解系列java

本文主要是介紹註解的基礎知識,爲後面的APT和JavaPoet打下基礎git

0x01 什麼是註解

註解(Annotation)是Java5的一個新特性,是插入在代碼中的一種註釋或者說是一種元數據(meta data),這些註釋信息能夠在編譯期使用預編譯工具進行獲取處理,也能夠在運行期使用Java反射機制來獲取,這取決於你的註解類型。github

0x02 註解的語法及其定義

在Android中註解常常存在咱們代碼中:數組

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main4);
        getIntentData();
    }
複製代碼

上面的@Override就是系統的註解,代表這是個重寫方法,點擊源碼能夠看到長成下面的樣子bash

@Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
複製代碼

實際中會帶有一些參數app

@Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface run_methodInfo {
        String name() default "long";
        String data();
        int id() default 365;
    }
複製代碼

@Retention @Target @Document @Inherited四種 是元註解即 「註解的註解」jvm

@Target 表示該註解目標,可能的 ElemenetType 參數包括:ide

  • 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 參考文獻

公衆號小.jpg
相關文章
相關標籤/搜索