1、Annotation(註解)
java
一、Annotation介紹數組
Annotation,是Java語言中的一種特殊的元數據語法,能夠被添加到Java代碼中。類,方法,變量,參數,包均可以被標註。與Javadoc的標籤不一樣,註解是能夠被反射的,由於他們被編譯器生成嵌入在 編譯後文件,並保留在虛擬機中以便在運行時被索引。Annotation類型是一種接口,不會直接影響到程序的語義,只是做爲註解(標識)存在,可以經過java反射API的方式提供對其信息的訪問。ide
二、Annotation工做原理測試
在java5.0 中Java.lang.reflect 提供的反射API被擴充了讀取運行時annotation的能力。一個annotation類型被定義爲runtime retention後,它纔是在運行時可見,當class文件被裝載時被保存在class文件中的annotation纔會被虛擬機讀取。 其中java.lang.reflect.AnnotatedElement是重要的接口,它表明了提供查詢annotation能力的程序成員。這個接口被java.lang.Package、java.lang.Class實現,並間接地被Method類、Constructor類、 java.lang.reflect的Field類實現。而annotation中的方法參數能夠經過Method類、Constructor類的 getParameterAnnotations()方法得到。this
三、系統內置標準註解spa
@Override:用於修飾此方法覆蓋了父類的方法,也就是子類要重寫(override)父類的對應方法;
@Deprecated:用於修飾已通過時的方法,不建議被使用;
@SuppressWarnnings:用於通知java編譯器禁止特定的編譯警告。code
四、元註解對象
元註解也就是註解的註解,java提供了四種元註解,其中兩種是經常使用的,分別是Retention和Target。繼承
@Retention元註解,表示須要在什麼級別保存該註釋信息(生命週期)。可選的RetentionPoicy參數包括:RetentionPolicy.SOURCE: 停留在java源文件,編譯器被丟掉
RetentionPolicy.CLASS:停留在class文件中,但會被VM丟棄(默認)
RetentionPolicy.RUNTIME:內存中的字節碼,VM將在運行時也保留註解,所以能夠經過反射機制讀取註解的信息索引
@Retention(RetentionPolicy.RUNTIME) // 編譯程序將Annotation存儲於class文件中,能夠由虛擬機讀入 public @interface MyAnnotation { String hello() default "hello"; String world(); }
@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
ElementType.CONSTRUCTOR: 構造器聲明
ElementType.FIELD: 成員變量、對象、屬性(包括enum實例)
ElementType.LOCAL_VARIABLE: 局部變量聲明
ElementType.METHOD: 方法聲明
ElementType.PACKAGE: 包聲明
ElementType.PARAMETER: 參數聲明
ElementType.TYPE: 類、接口(包括註解類型)或enum聲明
demo以下:
自定義一個用於方法的註解
@Target(ElementType.METHOD) public @interface MyTarget { String hello() default "hello"; }
package annotationVSreflect; @MyTarget //註解到這編譯器會報錯 public class MyTargetTest { @MyTarget //該註解(@MyTarget)已指明只能註解方法 public void fun() { } }
@Documented將註解包含在JavaDoc中
@Inheried容許子類繼承父類中的註解
五、自定義註解
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Target(ElementType.METHOD)//若是Target元註解不存在,那麼該註解就能夠使用在任何程序元素之上。 @Inherited @Retention(RetentionPolicy.RUNTIME) //使用@interface來聲明一個註解(其實是自動繼承了java.lang.annotation.Annotation接口) public @interface AnnotationTest { String value1() default "hello";//爲註解設置String類型的屬性Value1,並使用defalut關鍵字設置默認值 String[] value3(); //設置數組類型的value3 }
自定義註解須要注意的細節:
1. Annotation型定義爲@interface, 全部的Annotation會自動繼承java.lang.Annotation這一接口,而且不能再去繼承別的類或是接口。
2. 參數成員只能用public或默認(default)這兩個訪問權修飾。
3. 參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和String、Enum、Class、annotations等數據類型,以及這一些類型的數組。
4. 要獲取類方法和字段的註解信息,必須經過Java的反射技術來獲取 Annotation對象,由於你除此以外沒有別的獲取註解對象的方法。
5. 註解也能夠沒有定義成員, 只是這樣註解就沒有做用。
2、反射
JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
通俗說:能夠經過一個類名來獲取關於這個類的信息,好比:屬性名、屬性名的修飾符、方法名、方法的返回值、方法的修飾符等。反射還能夠生成類的實例,經過這個實例定義屬性、調用方法。
import java.lang.reflect.Method; public class Reflect { public static void main(String[] args) { try { Class c=Class.forName("java.util.HashSet"); System.out.println("Test======"+c); Object o=c.newInstance(); Method[] methods=c.getDeclaredMethods(); for(Method method:methods){ System.out.println("------------------------------------"); System.out.println(method); } Method m1=c.getMethod("add", Object.class); m1.invoke(o, "cyq"); m1.invoke(o, "hello"); m1.invoke(o, "java"); System.out.println(o); } catch (Exception e) { e.printStackTrace(); } } }
控制檯打印信息:
Test======class java.util.HashSet
------------------------------------
public boolean java.util.HashSet.add(java.lang.Object)
------------------------------------
public boolean java.util.HashSet.remove(java.lang.Object)
------------------------------------
public java.lang.Object java.util.HashSet.clone()
------------------------------------
public void java.util.HashSet.clear()
------------------------------------
public boolean java.util.HashSet.contains(java.lang.Object)
------------------------------------
public boolean java.util.HashSet.isEmpty()
------------------------------------
public int java.util.HashSet.size()
------------------------------------
public java.util.Iterator java.util.HashSet.iterator()
------------------------------------
private void java.util.HashSet.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
------------------------------------
private void java.util.HashSet.writeObject(java.io.ObjectOutputStream) throws java.io.IOException
[hello, java, cyq]
3、綜合實例:
首先自定義兩個註解:
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String hello() default "hello"; String world(); }
@Retention(RetentionPolicy.CLASS) public @interface MyAnnotation2 { String hello() default "hello"; }
而後作一個測試類MyTest
import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class MyTest { @SuppressWarnings("unchecked")//java自帶的註解Retention的policy爲SOURCE @Deprecated //java自帶的註解Retention的policy爲RUNTIME @MyAnnotation(world = "jia") //自定義的註解Retention的policy爲RUNTIME @MyAnnotation2 //自定義的註解Retention的policy爲CLASS public void TestMethod() { System.out.println("this is a method"); } public static void main(String[] args) throws Exception { MyTest myTest=new MyTest(); Class<MyTest> clazz=MyTest.class; Method method =clazz.getMethod("TestMethod",new Class[]{});//返回一個 Method 對象, //它反映此 Class 對象所表示的類或接口的指定公共成員方法。 System.out.println("test==========="+clazz); System.out.println("test==========="+method); //AnnotatedElement接口中的方法isAnnotationPresent(),判斷傳入的註解類型是否存在 if (method.isAnnotationPresent(MyAnnotation.class)) { method.invoke(myTest,new Object[]{}); //AnnotatedElement接口中的方法getAnnotation(),獲取傳入註解類型的註解 MyAnnotation myAnnotation=method.getAnnotation(MyAnnotation.class); String hello=myAnnotation.hello(); String world=myAnnotation.world(); System.out.println("hello:"+hello+"world:"+world); } System.out.println("-----------------------------------"); //AnnotatedElement接口中的方法getAnnotations(),獲取全部註解 Annotation[] annotations = method.getAnnotations(); //循環註解數組打印出註解類型的名字 for (Annotation annotation : annotations) { System.out.println(annotation.annotationType().getName()); } } }
控制檯打印信息:
test===========class annotationVSreflect.MyTest
test===========public void annotationVSreflect.MyTest.TestMethod()
this is a method
hello:helloworld:jia
-----------------------------------
java.lang.Deprecated
annotationVSreflect.MyAnnotation
分割線上:介紹瞭如何使用AnnotatedElement接口中的方法和反射去調用註解
分割線下:證實了只有定義了Retention的Policy爲Runtime的註解才能夠被反射讀取出來