最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Java自定義注解和運行時靠反射獲取注解

 更新時間:2016年11月26日 09:52:57   投稿:jingxian  
下面小編就為大家?guī)硪黄獪\談Java自定義注解和運行時靠反射獲取注解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

java自定義注解

Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。

注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。

1、元注解

元注解是指注解的注解。包括  @Retention @Target @Document @Inherited四種。

1.1、@Retention: 定義注解的保留策略

@Retention(RetentionPolicy.SOURCE)  //注解僅存在于源碼中,在class字節(jié)碼文件中不包含
@Retention(RetentionPolicy.CLASS)   // 默認的保留策略,注解會在class字節(jié)碼文件中存在,但運行時無法獲得,
@Retention(RetentionPolicy.RUNTIME) // 注解會在class字節(jié)碼文件中存在,在運行時可以通過反射獲取到

注解類:

@Retention(RetentionPolicy.RUNTIME) // 注解會在class字節(jié)碼文件中存在,在運行時可以通過反射獲取到
@Target({ElementType.FIELD,ElementType.METHOD})//定義注解的作用目標**作用范圍字段、枚舉的常量/方法
@Documented//說明該注解將被包含在javadoc中
public @interface FieldMeta {

	/**
	 * 是否為序列號
	 * @return
	 */
	boolean id() default false;
	/**
	 * 字段名稱
	 * @return
	 */
	String name() default "";
	/**
	 * 是否可編輯
	 * @return
	 */
	boolean editable() default true;
	/**
	 * 是否在列表中顯示
	 * @return
	 */
	boolean summary() default true;
	/**
	 * 字段描述
	 * @return
	 */
	String description() default "";
	/**
	 * 排序字段
	 * @return
	 */
	int order() default 0;
}

實體類:

public class Anno {

	@FieldMeta(id=true,name="序列號",order=1)
	private int id;
	@FieldMeta(name="姓名",order=3)
	private String name;
	@FieldMeta(name="年齡",order=2)
	private int age;
	
	@FieldMeta(description="描述",order=4)
	public String desc(){
		return "java反射獲取annotation的測試";
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

獲取到注解的幫助類:

public class SortableField {

	public SortableField(){}
	
	public SortableField(FieldMeta meta, Field field) {
		super();
		this.meta = meta;
		this.field = field;
		this.name=field.getName();
		this.type=field.getType();
	}
	
	
	public SortableField(FieldMeta meta, String name, Class<?> type) {
		super();
		this.meta = meta;
		this.name = name;
		this.type = type;
	}


	private FieldMeta meta;
	private Field field;
	private String name;
	private Class<?> type;
	
	public FieldMeta getMeta() {
		return meta;
	}
	public void setMeta(FieldMeta meta) {
		this.meta = meta;
	}
	public Field getField() {
		return field;
	}
	public void setField(Field field) {
		this.field = field;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public Class<?> getType() {
		return type;
	}

	public void setType(Class<?> type) {
		this.type = type;
	}
	
	
}

運行時獲取注解,首先創(chuàng)建一個基類:

public class Parent<T> {

	private Class<T> entity;

	public Parent() {
		init();
	}

	@SuppressWarnings("unchecked")
	public List<SortableField> init(){
		List<SortableField> list = new ArrayList<SortableField>();
		/**getClass().getGenericSuperclass()返回表示此 Class 所表示的實體(類、接口、基本類型或 void)
		 * 的直接超類的 Type(Class<T>泛型中的類型),然后將其轉換ParameterizedType。。
		 * 	getActualTypeArguments()返回表示此類型實際類型參數(shù)的 Type 對象的數(shù)組。
		 * 	[0]就是這個數(shù)組中第一個了。。
		 * 	簡而言之就是獲得超類的泛型參數(shù)的實際類型。。*/
		entity = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass())
				.getActualTypeArguments()[0];
//		FieldMeta filed = entity.getAnnotation(FieldMeta.class);
		
		if(this.entity!=null){
			
			/**返回類中所有字段,包括公共、保護、默認(包)訪問和私有字段,但不包括繼承的字段
			 * entity.getFields();只返回對象所表示的類或接口的所有可訪問公共字段
			 * 在class中getDeclared**()方法返回的都是所有訪問權限的字段、方法等;
			 * 可看API
			 * */
			Field[] fields = entity.getDeclaredFields();
//			
			for(Field f : fields){
				//獲取字段中包含fieldMeta的注解
				FieldMeta meta = f.getAnnotation(FieldMeta.class);
				if(meta!=null){
					SortableField sf = new SortableField(meta, f);
					list.add(sf);
				}
			}
			
			//返回對象所表示的類或接口的所有可訪問公共方法
			Method[] methods = entity.getMethods();
			
			for(Method m:methods){
				FieldMeta meta = m.getAnnotation(FieldMeta.class);
				if(meta!=null){
					SortableField sf = new SortableField(meta,m.getName(),m.getReturnType());
					list.add(sf);
				}
			}
			//這種方法是新建FieldSortCom類實現(xiàn)Comparator接口,來重寫compare方法實現(xiàn)排序
//			Collections.sort(list, new FieldSortCom());
			Collections.sort(list, new Comparator<SortableField>() {
				@Override
				public int compare(SortableField s1,SortableField s2) {
					return s1.getMeta().order()-s2.getMeta().order();
//					return s1.getName().compareTo(s2.getName());//也可以用compare來比較
				}
				
			});
		}
		return list;
		
	}
}

創(chuàng)建子類繼承基類:

public class Child extends Parent<Anno>{

}

測試類:

public class TestAnnotation {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) {
		Parent c = new Child();
		List<SortableField> list = c.init();//獲取泛型中類里面的注解
		//輸出結果
		for(SortableField l : list){
			System.out.println("字段名稱:"+l.getName()+"\t字段類型:"+l.getType()+
					"\t注解名稱:"+l.getMeta().name()+"\t注解描述:"+l.getMeta().description());
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

1、Annotation的工作原理:

JDK5.0中提供了注解的功能,允許開發(fā)者定義和使用自己的注解類型。該功能由一個定義注解類型的語法和描述一個注解聲明的語法,讀取注解的API,一個使用注解修飾的class文件和一個注解處理工具組成。

Annotation并不直接影響代碼的語義,但是他可以被看做是程序的工具或者類庫。它會反過來對正在運行的程序語義有所影響。

Annotation可以沖源文件、class文件或者在運行時通過反射機制多種方式被讀取。

2、@Override注解:

java.lang

注釋類型 Override
@Target(value=METHOD)
@Retention(value=SOURCE)
public @interface Override表示一個方法聲明打算重寫超類中的另一個方法聲明。如果方法利用此注釋類型進行注解但沒有重寫超類方法,則編譯器會生成一條錯誤消息。

@Override注解表示子類要重寫父類的對應方法。

Override是一個Marker annotation,用于標識的Annotation,Annotation名稱本身表示了要給工具程序的信息。

下面是一個使用@Override注解的例子:

class A {
  private String id;
  A(String id){
    this.id = id;
  }
  @Override
  public String toString() {
    return id;
  }
}

3、@Deprecated注解:

java.lang
注釋類型 Deprecated
@Documented
@Retention(value=RUNTIME)

public @interface Deprecated用 @Deprecated 注釋的程序元素,不鼓勵程序員使用這樣的元素,通常是因為它很危險或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執(zhí)行重寫時,編譯器會發(fā)出警告。

@Deprecated注解表示方法是不被建議使用的。

Deprecated是一個Marker annotation。

下面是一個使用@Deprecated注解的例子:

class A {
  private String id;
  A(String id){
    this.id = id;
  }
  @Deprecated
  public void execute(){
    System.out.println(id);
  }
  public static void main(String[] args) {
    A a = new A("a123");
    a.execute();
  }
}

4、@SuppressWarnings注解:

java.lang
注釋類型 SuppressWarnings
@Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(value=SOURCE)

public @interface SuppressWarnings指示應該在注釋元素(以及包含在該注釋元素中的所有程序元素)中取消顯示指定的編譯器警告。注意,在給定元素中取消顯示的警告集是所有包含元素中取消顯示的警告的超集。例如,如果注釋一個類來取消顯示某個警告,同時注釋一個方法來取消顯示另一個警告,那么將在此方法中同時取消顯示這兩個警告。

根據(jù)風格不同,程序員應該始終在最里層的嵌套元素上使用此注釋,在那里使用才有效。如果要在特定的方法中取消顯示某個警告,則應該注釋該方法而不是注釋它的類。

@SuppressWarnings注解表示抑制警告。

下面是一個使用@SuppressWarnings注解的例子:

@SuppressWarnings("unchecked")
public static void main(String[] args) {
  List list = new ArrayList();
  list.add("abc");
}

5、自定義注解:

使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節(jié)。在定義注解時,不能繼承其他的注解或接口。

自定義最簡單的注解:

public @interface MyAnnotation {

}

使用自定義注解:

public class AnnotationTest2 {

  @MyAnnotation
  public void execute(){
    System.out.println("method");
  }
}

5.1、添加變量:

public @interface MyAnnotation {

  String value1();
}

使用自定義注解:

public class AnnotationTest2 {

  @MyAnnotation(value1="abc")
  public void execute(){
    System.out.println("method");
  }
}

當注解中使用的屬性名為value時,對其賦值時可以不指定屬性的名稱而直接寫上屬性值接口;除了value意外的變量名都需要使用name=value的方式賦值。

5.2、添加默認值:

public @interface MyAnnotation {

  String value1() default "abc";
}

5.3、多變量使用枚舉:

public @interface MyAnnotation {

  String value1() default "abc";
  MyEnum value2() default MyEnum.Sunny;
}
enum MyEnum{
  Sunny,Rainy
}

使用自定義注解:

public class AnnotationTest2 {

  @MyAnnotation(value1="a", value2=MyEnum.Sunny)
  public void execute(){
    System.out.println("method");
  }
}

5.4、數(shù)組變量:

public @interface MyAnnotation {

  String[] value1() default "abc";
}

使用自定義注解:

public class AnnotationTest2 {

  @MyAnnotation(value1={"a","b"})
  public void execute(){
    System.out.println("method");
  }
}

6、設置注解的作用范圍:

@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)

public @interface Retention指示注釋類型的注釋要保留多久。如果注釋類型聲明中不存在 Retention 注釋,則保留策略默認為 RetentionPolicy.CLASS。

只有元注釋類型直接用于注釋時,Target 元注釋才有效。如果元注釋類型用作另一種注釋類型的成員,則無效。

public enum RetentionPolicy
extends Enum<RetentionPolicy>注釋保留策略。此枚舉類型的常量描述保留注釋的不同策略。它們與 Retention 元注釋類型一起使用,以指定保留多長的注釋。

CLASS
編譯器將把注釋記錄在類文件中,但在運行時 VM 不需要保留注釋。

RUNTIME
編譯器將把注釋記錄在類文件中,在運行時 VM 將保留注釋,因此可以反射性地讀取。

SOURCE
編譯器要丟棄的注釋。@Retention注解可以在定義注解時為編譯程序提供注解的保留策略。

屬于CLASS保留策略的注解有@SuppressWarnings,該注解信息不會存儲于.class文件。

6.1、在自定義注解中的使用例子:

@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation {

  String[] value1() default "abc";
}

7、使用反射讀取RUNTIME保留策略的Annotation信息的例子:

java.lang.reflect

接口 AnnotatedElement

所有已知實現(xiàn)類:

AccessibleObject, Class, Constructor, Field, Method, Package表示目前正在此 VM 中運行的程序的一個已注釋元素。該接口允許反射性地讀取注釋。由此接口中的方法返回的所有注釋都是不可變并且可序列化的。調(diào)用者可以修改已賦值數(shù)組枚舉成員的訪問器返回的數(shù)組;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。

如果此接口中的方法返回的注釋(直接或間接地)包含一個已賦值的 Class 成員,該成員引用了一個在此 VM 中不可訪問的類,則試圖通過在返回的注釋上調(diào)用相關的類返回的方法來讀取該類,將導致一個 TypeNotPresentException。

isAnnotationPresent
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)如果指定類型的注釋存在于此元素上,則返回 true,否則返回 false。此方法主要是為了便于訪問標記注釋而設計的。

參數(shù):

annotationClass - 對應于注釋類型的 Class 對象

返回:

如果指定注釋類型的注釋存在于此對象上,則返回 true,否則返回 false

拋出:

NullPointerException - 如果給定的注釋類為 null

從以下版本開始:

1.5

getAnnotation
<T extends Annotation> T getAnnotation(Class<T> annotationClass)如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。

參數(shù):

annotationClass - 對應于注釋類型的 Class 對象

返回:

如果該元素的指定注釋類型的注釋存在于此對象上,則返回這些注釋,否則返回 null

拋出:

NullPointerException - 如果給定的注釋類為 null

從以下版本開始:

1.5

getAnnotations
Annotation[] getAnnotations()返回此元素上存在的所有注釋。(如果此元素沒有注釋,則返回長度為零的數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。

返回:

此元素上存在的所有注釋

從以下版本開始:

1.5

getDeclaredAnnotations
Annotation[] getDeclaredAnnotations()返回直接存在于此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在于此元素上,則返回長度為零的一個數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。

返回:

直接存在于此元素上的所有注釋

從以下版本開始:

1.5

下面是使用反射讀取RUNTIME保留策略的Annotation信息的例子:

自定義注解:

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

  String[] value1() default "abc";
}

使用自定義注解:

public class AnnotationTest2 {

  @MyAnnotation(value1={"a","b"})
  @Deprecated
  public void execute(){
    System.out.println("method");
  }
}

讀取注解中的信息:

public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  AnnotationTest2 annotationTest2 = new AnnotationTest2();
  //獲取AnnotationTest2的Class實例
  Class<AnnotationTest2> c = AnnotationTest2.class;
  //獲取需要處理的方法Method實例
  Method method = c.getMethod("execute", new Class[]{});
  //判斷該方法是否包含MyAnnotation注解
  if(method.isAnnotationPresent(MyAnnotation.class)){
    //獲取該方法的MyAnnotation注解實例
    MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
    //執(zhí)行該方法
    method.invoke(annotationTest2, new Object[]{});
    //獲取myAnnotation
    String[] value1 = myAnnotation.value1();
    System.out.println(value1[0]);
  }
  //獲取方法上的所有注解
  Annotation[] annotations = method.getAnnotations();
  for(Annotation annotation : annotations){
    System.out.println(annotation);
  }
}

8、限定注解的使用:

限定注解使用@Target。

@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)

public @interface Target指示注釋類型所適用的程序元素的種類。如果注釋類型聲明中不存在 Target 元注釋,則聲明的類型可以用在任一程序元素上。如果存在這樣的元注釋,則編譯器強制實施指定的使用限制。 例如,此元注釋指示該聲明類型是其自身,即元注釋類型。它只能用在注釋類型聲明上:

@Target(ElementType.ANNOTATION_TYPE)
  public @interface MetaAnnotationType {
    ...
  }

此元注釋指示該聲明類型只可作為復雜注釋類型聲明中的成員類型使用。它不能直接用于注釋:

@Target({}) 
  public @interface MemberType {
    ...
  }

這是一個編譯時錯誤,它表明一個 ElementType 常量在 Target 注釋中出現(xiàn)了不只一次。例如,以下元注釋是非法的:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
  public @interface Bogus {
    ...
  }public enum ElementType

extends Enum<ElementType>程序元素類型。此枚舉類型的常量提供了 Java 程序中聲明的元素的簡單分類。

這些常量與 Target 元注釋類型一起使用,以指定在什么情況下使用注釋類型是合法的。

ANNOTATION_TYPE
注釋類型聲明
CONSTRUCTOR
構造方法聲明
FIELD
字段聲明(包括枚舉常量)
LOCAL_VARIABLE
局部變量聲明
METHOD
方法聲明
PACKAGE
包聲明
PARAMETER
參數(shù)聲明
TYPE
類、接口(包括注釋類型)或枚舉聲明

注解的使用限定的例子:

@Target(ElementType.METHOD)
public @interface MyAnnotation {

  String[] value1() default "abc";
}

9、在幫助文檔中加入注解:

要想在制作JavaDoc文件的同時將注解信息加入到API文件中,可以使用java.lang.annotation.Documented。

在自定義注解中聲明構建注解文檔:

@Documented
public @interface MyAnnotation {

  String[] value1() default "abc";
}

使用自定義注解:

public class AnnotationTest2 {

  @MyAnnotation(value1={"a","b"})
  public void execute(){
    System.out.println("method");
  }
}

10、在注解中使用繼承:

默認情況下注解并不會被繼承到子類中,可以在自定義注解時加上java.lang.annotation.Inherited注解聲明使用繼承。

@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Inherited指示注釋類型被自動繼承。如果在注釋類型聲明中存在 Inherited 元注釋,并且用戶在某一類聲明中查詢該注釋類型,同時該類聲明中沒有此類型的注釋,則將在該類的超類中自動查詢該注釋類型。此過程會重復進行,直到找到此類型的注釋或到達了該類層次結構的頂層 (Object) 為止。如果沒有超類具有該類型的注釋,則查詢將指示當前類沒有這樣的注釋。

注意,如果使用注釋類型注釋類以外的任何事物,此元注釋類型都是無效的。還要注意,此元注釋僅促成從超類繼承注釋;對已實現(xiàn)接口的注釋無效。

以上這篇淺談Java自定義注解和運行時靠反射獲取注解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Springboot集成Kafka進行批量消費及踩坑點

    Springboot集成Kafka進行批量消費及踩坑點

    本文主要介紹了Springboot集成Kafka進行批量消費及踩坑點,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Java原子類中的AtomicInteger類詳解

    Java原子類中的AtomicInteger類詳解

    這篇文章主要介紹了Java原子類中的AtomicInteger類詳解,原子類可以保證對"變量"操作的,原子性、有序性、可見性,我們可以通過AtomicInteger類,來看看它們是怎樣工作的,需要的朋友可以參考下
    2023-10-10
  • java泛型基本知識和通用方法

    java泛型基本知識和通用方法

    這篇文章主要介紹了java泛型基礎知識及通用方法,從以下幾個方面介紹一下java的泛型: 基礎, 泛型關鍵字, 泛型方法, 泛型類和接口,感興趣的可以了解一下
    2021-06-06
  • spring中ApplicationListener的使用小結

    spring中ApplicationListener的使用小結

    ApplicationListener是spring提供的一個監(jiān)聽器,本文主要介紹了spring中ApplicationListener的使用小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-07-07
  • SpringMVC中參數(shù)綁定問題實例詳解

    SpringMVC中參數(shù)綁定問題實例詳解

    springmvc是用來處理頁面的一些請求,然后將數(shù)據(jù)再通過視圖返回給用戶的,下面這篇文章主要給大家介紹了關于SpringMVC中參數(shù)綁定問題的相關資料,需要的朋友可以參考下
    2022-04-04
  • Spring集成MyBatis?及Aop分頁的實現(xiàn)代碼

    Spring集成MyBatis?及Aop分頁的實現(xiàn)代碼

    這篇文章主要介紹了Spring集成MyBatis?及Aop分頁的實現(xiàn),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • Spring Boot中Reactor模型的基本概念和最佳實踐

    Spring Boot中Reactor模型的基本概念和最佳實踐

    Reactor模型是一種基于事件驅動和非阻塞IO的編程模型,用于處理并發(fā)和異步操作,本文將介紹Spring Boot中使用Reactor模型的基本概念和最佳實踐,幫助讀者更好地理解如何利用這一強大的工具來構建現(xiàn)代化的Java應用程序,感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • Mybatis velocity腳本的使用教程詳解(推薦)

    Mybatis velocity腳本的使用教程詳解(推薦)

    很多朋友不清楚在mybatis可以使用各種腳本語言來定義Mapper文件里面的動態(tài)SQL;目前mybatis支持的腳本語言有XML(默認的);Velocity和Freemarker三種。下面通過本文給大家介紹Mybatis velocity腳本的使用,一起看看吧
    2016-11-11
  • Java實現(xiàn)從jar包中讀取指定文件的方法

    Java實現(xiàn)從jar包中讀取指定文件的方法

    這篇文章主要介紹了Java實現(xiàn)從jar包中讀取指定文件的方法,涉及java針對jar文件的讀取及查找相關操作技巧,需要的朋友可以參考下
    2017-08-08
  • Java通過HttpClient進行HTTP請求的代碼詳解

    Java通過HttpClient進行HTTP請求的代碼詳解

    Apache?HttpClient是一個功能強大且廣泛使用的Java庫,它提供了方便的方法來執(zhí)行HTTP請求并處理響應。本文將介紹如何使用HttpClient庫進行HTTP請求,包括GET請求、POST請求、添加參數(shù)和請求體、設置請求頭等操作,需要的朋友可以參考下
    2023-05-05

最新評論

淅川县| 郴州市| 鹤壁市| 萍乡市| 积石山| 连云港市| 鞍山市| 兴文县| 墨江| 民县| 宜良县| 会理县| 仁化县| 正宁县| 马龙县| 邵东县| 宝兴县| 佛冈县| 凯里市| 安庆市| 子洲县| 梁河县| 张家港市| 彰化市| 濮阳县| 泗洪县| 汉川市| 辽宁省| 福建省| 澳门| 宁南县| 仲巴县| 凌源市| 察哈| 安国市| 台东市| 安化县| 安义县| 黑河市| 铁力市| 武邑县|