關(guān)于Java注解學(xué)習(xí)總結(jié)

什么是注解

注解是 Java 5 的一個新特性。注解是插入你代碼中的一種注釋或者說是一種元數(shù)據(jù)(meta data)。這些注解信息可以在編譯期使用預(yù)編譯工具進行處理(pre-compiler tools),也可以在運行期使用 Java 反射機制進行處理。

那么通俗來說,注解就是我們所說的標(biāo)簽,我們可以把一些類,方法,變量,參數(shù)添加注解,即加上標(biāo)簽來表明這些是干啥的,以便有需要的時候查看。

注解的聲明

使用@interface聲明:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)     

public @interface Test {
}
  • 使用@Target注解傳入ElementType.METHOD參數(shù)來標(biāo)明@Test只能用于方法上。

  • 使用@Retention(RetentionPolicy.TRUNTIME)來表示該注解生存期是運行時。

  • @Target@Retention是由Java提供的元注解,即可以標(biāo)記自定義注解的注解。

元注解

@Target

@Target用來約束注解可以應(yīng)用的地方(如類、方法、方法參數(shù)、字段),ElementType是枚舉類型,其定義如下:

public enum ElementType {
/**標(biāo)明該注解可以用于類、接口(包括注解類型)或enum聲明*/
TYPE,

/** 標(biāo)明該注解可以用于字段(域)聲明,包括enum實例 */
FIELD,

/** 標(biāo)明該注解可以用于方法聲明 */
METHOD,

/** 標(biāo)明該注解可以用于參數(shù)聲明 */
PARAMETER,

/** 標(biāo)明注解可以用于構(gòu)造函數(shù)聲明 */
CONSTRUCTOR,

/** 標(biāo)明注解可以用于局部變量聲明 */
LOCAL_VARIABLE,

/** 標(biāo)明注解可以用于注解聲明(應(yīng)用于另一個注解上)*/
ANNOTATION_TYPE,

/** 標(biāo)明注解可以用于包聲明 */
PACKAGE,

/**
 * 標(biāo)明注解可以用于類型參數(shù)聲明(1.8新加入)
 * @since 1.8
 */
TYPE_PARAMETER,

/**
 * 類型使用聲明(1.8新加入)
 * @since 1.8
 */
TYPE_USE
}

當(dāng)注解未指定Target值時,則此注解可以用于任何元素上,多個值使用{}包含并用逗號隔開,如下:

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

@Retention

@Retention用來約束注解的生命周期,有三個級別:源碼級別(SOURCE)、類文件級別(CLASS)、運行時級別(RUNTIME),

  • SOURCE: 注解將被編譯器丟棄(該類型的注解信息只會保留在源碼里,源碼經(jīng)過編譯后,注解信息會被丟棄,不會保留在編譯好的class文件里)

  • CLASS:注解在class文件中可用,但會被VM丟棄(該類型的注解信息會保留在源碼里和class文件里,在執(zhí)行的時候,不會加載到虛擬機中),請注意,當(dāng)注解未定義Retention時,默認(rèn)值是CLASS,如Java內(nèi)置注解,@Override、@Deprecated、@SuppressWarnning等

  • RUNTIME:注解信息將在運行期(JVM)也保留,因此可以通過反射機制讀取注解的信息(源碼、class文件和執(zhí)行的時候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。

@Inherited

@Inherited 可以讓注解被繼承,但這并不是真的繼承,只是通過使用@Inherited,可以讓子類Class對象使用getAnnotations()獲取父類被@Inherited修飾的注解。

/** 使用@Inherited注解會被子類所繼承 */
@Retention(Retention.RUNTIME)
@Inherited
public @interface InheritedTest {
    String value();
}

/** 未聲明@Inherited, 不會被子類繼承*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NoInheritedTest {
    String value();
}

/**父類*/

@InheritedTest("InheritedTest:使用@Inherited的class")
@NoInheritedTest("NoInheritedTest:未使用@Inherited的class")
public class Parent {

@InheritedTest("InheritedTest:使用@Inherited method")
@NoInheritedTest("NoInheritedTest:未使用@Inherited method")
public void method(){
    
}
@InheritedTest("InheritedTest:使用@Inherited method2")
@NoInheritedTest("NoInheritedTest:未使用@Inherited method2")
public void method2(){
    
}

@InheritedTest("InheritedTest:使用@Inherited field")
@NoInheritedTest("NoInheritedTest:未使用@Inherited field")
public String a;
}   

/**子類  只繼承了一個method方法 */
public class Child extends Parent {

@Override
public void method() {
    }
}


/**使用反射進行測試 */
public class Test {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
    Class<Child> childClass = Child.class;
    //對類測試
    System.out.println("-------------------------------------");
    System.out.println("對類測試");
    if (childClass.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(childClass.getAnnotation(InheritedTest.class).value());
    }

    if (childClass.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(childClass.getAnnotation(NoInheritedTest.class).value());
    }

    //對方法1測試
    System.out.println("-------------------------------------");
    System.out.println("對方法1測試");
    Method method = childClass.getMethod("method", null);
    if (method.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(method.getAnnotation(InheritedTest.class).value());
    }

    if (method.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(method.getAnnotation(NoInheritedTest.class).value());
    }

    //對方法2測試
    System.out.println("-------------------------------------");
    System.out.println("對方法2測試");
    Method method2 = childClass.getMethod("method2");
    if (method2.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(method2.getAnnotation(InheritedTest.class).value());
    }

    if (method2.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(method2.getAnnotation(NoInheritedTest.class).value());
    }

    //對變量測試
    System.out.println("-------------------------------------");
    System.out.println("對變量測試");
    Field field = childClass.getField("a");
    if (field.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(field.getAnnotation(InheritedTest.class).value());
    }

    if (field.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(field.getAnnotation(NoInheritedTest.class).value());
    }
}
}

/**輸出結(jié)果*/
-------------------------------------
對類測試
InheritedTest:使用@Inherited的class
-------------------------------------
對方法1測試
-------------------------------------
對方法2測試
InheritedTest:使用@Inherited method2
NoInheritedTest:未使用@Inherited method2
-------------------------------------
對變量測試
InheritedTest:使用@Inherited field
NoInheritedTest:未使用@Inherited field


我們可以得出結(jié)論,使用`@Inherited`注解類的時候,子類繼承了父類的注解,但是第一個方法沒有繼承到注解,說明`@Inherited`對方法無效,但方法2和域拿到的是父類的注解,所以有輸出。

@Repeatable

在Java SE 8中引入的 @Repeatable 注解表明標(biāo)記的注解可以多次應(yīng)用于相同的聲明或類型使用。
可以這么理解:有個人可以音樂家,畫家,程序員,那我們就用@Repeatable給這個人貼上這三個標(biāo)簽。

@Retention(RetentionPolicy.RUNTIME)
public @interface Persons {
    Person[] value();   
}

@Repeatable(Persons.class)
public @interface Person {
    String role default "";
}

@Person(role="Painter")
@Person(role="Musician")
@Person(role="Lion")
public class KUN {}

注解的成員變量及其數(shù)據(jù)類型

我們定義注解,也可以定義一些成員變量,而且還可以用default指定默認(rèn)值。

@Retention(RetentionPolicy.RUNTIME)
public @interface FavouriteAnnotation {

int num() default 0;

String name() default "X JAPAN";

}

/** 默認(rèn)第0位最喜愛的是X JAPAN*/
@FavouriteAnnotation()
public class KUN {}

/** 指定第1位最喜愛的是Queen*/
@FavouriteAnnotation(num=1, name="Queen")
public class KUN {}

注解支持的數(shù)據(jù)類型有:

  • 所有基本類型(int,float,boolean,byte,double,char,long,short)

  • String

  • Class

  • enum

  • Annotation

  • 上述類型的數(shù)組

注解與反射

注解通過反射獲取,使用Class對象的isAnnotationPresent()方法判斷是否應(yīng)用了某個注解,如果指定類型的注解存在于此元素上,則返回 true,否則返回 false。
public boolean isAnnotationPresent(Class<? extend Annotation> annotationClass)

使用getAnnotation()方法獲取Annotation對象。
public <A extebds Annotation> A getAnnotation(Class<A> annotationClass) {}

使用getAnnotations() 獲取此元素上存在的所有注解,包括從父類繼承的。
public Annotation[] getAnnotations() {}

使用getDeclaredAnnotations(),返回直接存在于此元素上的所有注解,注意,不包括父類的注解,調(diào)用者可以隨意修改返回的數(shù)組;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響,沒有則返回長度為0的數(shù)組

public native Annotation[] getDeclaredAnnotations()

注解的應(yīng)用場景

注解是一系列元數(shù)據(jù),它提供數(shù)據(jù)用來解釋程序代碼,但是注解并非是所解釋的代碼本身的一部分。注解對于代碼的運行效果沒有直接影響。
注解有許多用處,主要如下:

  • 提供信息給編譯器: 編譯器可以利用注解來探測錯誤和警告信息
  • 編譯階段時的處理: 軟件工具可以用來利用注解信息來生成代碼、Html文檔
    或者做其它相應(yīng)處理。
  • 運行時的處理: 某些注解可以在程序運行的時候接受代碼的提取
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容