Java中的註解以及自定義註解

1、Annotation(註解) 概述

(1)、註解起到標識做用,比如Junit的@Test註解。

Junit會在運行時檢查方法上是否存在此註解,如果存在,就通過 反射 來運行你的方法。注意標紅的反射兩個字,反射在註解裏相當重要,寫完你的自定義註解類後沒啥用,必須要用反射才能讓它動起來!所以需要對反射有了解,感興趣的小可愛可以看下這篇:Java中的反射機制介紹

(2)、從 JDK 5.0 開始,Java 增加了對 Annotation(註解)的支持。

(3)、 註解其實就是代碼裏的特殊標記,它可以用於替代配置文件,也就是說,傳統方式通過配置文件告訴類如何運行,有了註解技術後,開發人員可以通過註解告訴類如何運行。用了註解以後,可以減少項目的配置文件,使代碼看起來更優雅。在Java技術裏註解的典型應用是:可以通過反射技術去得到類裏面的註解,以決定怎麼去運行類。

(4)、註解可以代替配置文件會被大量的應用到實際項目中去,又由於註解看起很簡潔,因此如果對註解的知識瞭解的不夠的話,到項目應用中,有時候你會一頭霧水,不知道咋回事,會比較懵。所以,學好註解非常重要

(5)、掌握註解技術的要點: 如何定義註解、如何反射註解,並根據反射的註解信息,決定如何去運行類

2、自定義 Annotation

2.1、定義註解本身

使用關鍵字@interface定義一個類而已。這個類就是註解。

如:public @interface MyAnnotation{ }

2.2、定義註解中的屬性

基本形式:類型 屬性名稱();    
                  比如:String name();
註解屬性定義完以後,使用:@MyAnnotationDemo1(name="hello")

特別注意:註解的屬性的類型只能是:基本類型、String、Class、枚舉、註解類型及以上類型的一維數組。

2.3、定義註解屬性的默認值

類型 屬性名稱() default 默認值;

2.4、註解中的特殊屬性

(1)、特殊屬性value:如果註解中只有一個屬性,而且這個屬性的名稱是value的話,那麼使用註解時可以省略value=部分,可以直接寫成這樣@MyAnnotation(“xxx");

(2)、特殊類型[] value():如果註解中只有一個屬性,而且這個屬性名稱是value且數據類型是數組,那麼
使用方式:四種都ok,根據情況而定
@MyAnnotationDemo1(value={"a","b"})
@MyAnnotationDemo1({"a","b"})
@MyAnnotationDemo1({"a"})
@MyAnnotationDemo1("a")

以上就是註解的基本語法了,下面通過代碼寫一個真實的小案例,來感受一下註解

3、寫一個自定義註解的真實案例

按照上邊介紹的語法,開始自定義一個註解來模擬實現 @Test單元測試的功能

package com.cj.study.annotation.app1;

public @interface MyTest {
	
}
package com.cj.study.annotation.app1;

public class DemoTest1 {
	
	@MyTest
	public void test1(){
		System.out.println("test1執行了");
	}
	
	public void test2(){
		System.out.println("test2執行了");
	}
}
package com.cj.study.annotation.app1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//反射註解:
	//取得類的字節碼
	//反射其中的成員,此處就是方法成員
	//看誰的上面有MyTest註解
	//誰有,就執行誰
public class MyJunitRunner {

	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
		//取得類的字節碼
		Class clazz = DemoTest1.class;
		//反射其中的成員,此處就是方法成員
		Method methods[] = clazz.getMethods();//得到DemoTest1中的所有公有的方法
		//看誰的上面有MyTest註解
		for(Method m:methods){
			//誰有,就執行誰
			boolean b = m.isAnnotationPresent(MyTest.class);
			System.out.println(b+"==="+m.getName());
			if(b){
				m.invoke(clazz.newInstance(), null);
			}
		}
	}

}

如果運行結果出現test1方法執行了,test2方法沒執行的話,就對了。

運行看下運行結果:

但是從結果可以看出和咱們預期的並不一樣,那到底怎麼回事呢?

原因是:定義註解的時候除了上邊說的語法,還需要一個東西,那就是“元註解”

那什麼是元註解呢?

簡單的來說服務於註解的註解就是元註解,它主要用來標識你寫的註解保留範圍(作用範圍)以及出現的位置

JDK中定義了四種元註解:

@Retention:註解的保留範圍,是個枚舉,有如下可選值
        RetentionPolicy.SOURCE:註解存在於源文件中
        RetentionPolicy.CLASS:註解存在於源字節碼文件中
        RetentionPolicy.RUNTIME:註解存在於運行時

@Target:註解出現的位置(比如字段上、方法上等),也是個枚舉,有如下可選值

        ElementType.TYPE

        ElementType.FIELD:字段

        ElementType.METHOD:方法

        ElementType.PARAMETER

        ElementType.CONSTRUCTOR

        ElementType.LOCAL_VARIABLE

        ElementType.ANNOTATION_TYPE

        ElementType.PACKAGE

        ElementType.TYPE_PARAMETER

        ElementType.TYPE_USE

@Documented: 用於指定被該元 Annotation 修飾的 Annotation 類將被 javadoc 工具提取成文檔.

@Inherited: 被它修飾的 Annotation 將具有繼承性.如果某個類使用了被 @Inherited 修飾的 Annotation, 則其子類將自動具有該註解

常用的是前兩種,瞭解了元註解後,下面把咱們的代碼加上元註解再試一下

package com.cj.study.annotation.app1;

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

@Retention(RetentionPolicy.RUNTIME)//註解存在於運行時
@Target(ElementType.METHOD)//說明MyTest註解只能用在方法上
public @interface MyTest {
	
}
package com.cj.study.annotation.app1;

public class DemoTest1 {
	
	@MyTest
	public void test1(){
		System.out.println("test1執行了");
	}
	
	public void test2(){
		System.out.println("test2執行了");
	}
}
package com.cj.study.annotation.app1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//反射註解:
	//取得類的字節碼
	//反射其中的成員,此處就是方法成員
	//看誰的上面有MyTest註解
	//誰有,就執行誰
public class MyJunitRunner {

	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
		//取得類的字節碼
		Class clazz = DemoTest1.class;
		//反射其中的成員,此處就是方法成員
		Method methods[] = clazz.getMethods();//得到DemoTest1中的所有公有的方法
		//看誰的上面有MyTest註解
		for(Method m:methods){
			//誰有,就執行誰
			boolean b = m.isAnnotationPresent(MyTest.class);
			System.out.println(b+"==="+m.getName());
			if(b){
				m.invoke(clazz.newInstance(), null);
			}
		}
	}

}

運行結果

發現test1方法執行了, test2方法沒執行,和預期的一樣。

OK,以上就是本人對註解的一些簡單的理解和總結,歡迎大家一起留言一起學習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章