java註解詳解

1、前言

  註解(Annotation),實際上和屬性、方法同樣,都是一個類的組成部分,不過對於初學者來講仍是有點陌生的,由於註解是給別人用的,而屬性和方法都是本身用的,這就致使沒有對註解進行深刻的學習,而在使用別人框架的時候,才被迫去了解框架提供的註解的使用方法。java

  註解的形式都是以@開頭,在微博微信中@Somebody是通知某人,而註解的@Info,則表示通知一件事(代表一種狀態),具體通知誰不去管,具體誰去用也無論,誰對這個註解感興趣誰來用。api

1.1 示例

  咱們從最簡單的例子提及,最經常使用的就是@Override,@Deprecated,@SuppressWarnings。若是按照上面的說法來講明,這三個註解都是給編譯器使用的。數組

  @Override:代表這個方法是重寫的父類的方法,當你把@Override放到一個方法上時,編譯器會自動去父類中查找是否有相應的方法,若是沒有,說明註解使用錯誤,或者重寫的方法名、參數等寫錯了,那麼編譯器就會給出編譯錯誤,讓你去修改。微信

  @Deprecated:代表這個屬性被棄用,當你使用它的時候,編譯器就會給出提醒。框架

  @SuppressWarnings:代表這不是一個警告,那麼編譯器就不會把它當作警告給提示出來。ide

1.2 再議註解

  也就是說,註解的使用方便了別人去作某些事情,若是不用註解的話用配置文件也能夠,可是針對上面三個註解,若是寫在配置文件中,那麼編譯器要怎麼知道去哪一個配置文件中去讀,又要以怎樣的格式去讀,這都是一個問題,而使用註解聽從了一種約定大於配置的理念。學習

  因此使用註解的時候就要明白這個註解是給誰用的,用做什麼。spa

  而當你打算寫一個框架時,也能夠提供註解的方式給別人使用,這樣來講更方便,而對於你來講就要以解析註解的方式來代替讀取並解析配置文件的方式。設計

2、註解的屬性

  註解也是有相應的屬性的,也就是說當定義一個註解的時候指定註解的屬性。code

2.1 註解位置

  首先了解一下能夠被註解的位置有哪些,這些都在一個枚舉類:ElementType當中:

  • TYPE:類、接口、註解、枚舉
  • FIELD:字段
  • METHOD:方法
  • PARAMETER:參數
  • CONSTRUCTOR:構造方法
  • LOCAL_VARIABLE:本地變量
  • ANNOTATION_TYPE:註解
  • PACKAGE:包
  • TYPE_PARAMETER:類型參數
  • TYPE_USE:類型使用

  註解位置配合@Target使用,當只有一個位置時能夠這麼使用:

@Target(ElementType.ANNOTATION_TYPE)

  當指定多個位置時,使用方法以下:

@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})

  若是一個註解沒有指定註解位置,那麼它能夠應用於全部位置。

2.2 註解生命週期

  註解也是有相應的聲明週期的,也是封裝在一個枚舉類:RetentionPolicy中:

  • SOURCE:源代碼期間,在編譯時會去除,因此這都是給編譯器使用的
  • CLASS:會保留在類文件中,可是運行時JVM不須要保存,默認的生命週期
  • RUNTIME:會持續保存到JVM運行時,能夠經過反射來獲取

  聲明週期配合@Retention來使用,使用方法以下:

@Retention(RetentionPolicy.RUNTIME)

  通常來講對於編寫框架用的註解的生命週期都是RUNTIME。

3、自定義註解

3.1 註解定義

  註解和接口其實很類似,接口裏面的方法定義了行爲,註解的方法定義了屬性,下面先給一個例子:

public @interface MyAnnotation {
    //聲明屬性,可使用以下類型
    String name();
    String password() default "123";
    int age() default 12;
    TimeUnit gender() default TimeUnit.SECONDS;
    Class<?> clazz();
    int[] arr() default {1,2,3};
    //爲了嵌套配置
    Override my2();
}

  簡單總結下:

  • 屬性是以方法的形式定義的,屬性名即爲方法名。
  • 能夠設置默認值,那麼當使用該註解的時候,若是不指定該屬性則使用默認這
  • 沒有默認值的,使用時必須賦值
  • 屬性類型能夠爲:String、基本類型、Class類型、枚舉、註解、以上的一維數組
  • 若只有一種屬性,且名爲value,則賦值時能夠不指定屬性名
  • 一樣的只有一個一維數組value[],則賦值時能夠不指定屬性名

3.2 註解使用

  當你提供一個註解供別人使用時,那麼對方可能將註解應用於容許的位置,並有可能賦值,而咱們沒法知道註解具體的位置,這時候只能經過反射加遍歷的方式來得到註解的位置。下面給出一個例子:

package yiwangzhibujian.annotation;

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

public class UseAnnatation {

    public static void main(String[] args) throws Exception {
        Dog dog=new Dog();
        Field[] fields = Dog.class.getFields();
        for(Field field:fields){
            DefaultValue annotation = field.getAnnotation(DefaultValue.class);
            if(annotation!=null){
                String value = annotation.value();
                field.set(dog, value);
            }
        }
        System.out.println(dog);
    }

}

class Dog{
    @DefaultValue("little white")
    public String name;
    public int age;
    
    public String toString() {
        return "Dog [name=" + name + ", age=" + age + "]";
    }
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface DefaultValue{
    String value();
}

  這個例子作了以下事:

  1. 定義一個默認值的註解
  2. 定義了一個類,指定了一個屬性的默認值
  3. 構造一個對象的時候,獲取註解並賦默認值

  固然這個例子只是舉例說明註解的用法,默認值根本就不用這麼複雜的方式,若是用過Spring的話,應該知道自動注入的註解,實現原理就是經過這種方式。

4、jdk已有註解

  除了一開始說的@Override,@Deprecated,@SuppressWarnings三個註解之外,jdk還有其餘註解,簡單來講,如今介紹的時候就會貼出源碼。

  @Documented:

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

  這個註解用來代表,在生成api文檔的時候將註解的對象生成文檔。

  @Inherited:

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

  被註解的註解,將會有被子類繼承。

  @Repeatable:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    Class<? extends Annotation> value();
}

  被註解的註解,能夠在一個屬性上重複使用。

  @Native:

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Native {
}

  代表一個字段引用的值可能來自於本地代碼,暫未找到具體示例,後續補上。

5、總結

  說到底,註解的使用方仍是很簡單的,難點在於提供給你註解的人是怎麼經過註解去達到他的目的的。若是你設計一個框架並提供註解給人使用,那麼你就要精通反射。不過通常狀況下是不多遇到須要自定義反射的場景,除非你設計一箇中間框架,別人經過你的框架來調用本身實現的類,就像Spring同樣。

相關文章
相關標籤/搜索