1、反射java
1.動態語言:是指程序在運行是能夠改變其結構:新的函數能夠引進,已有的函數能夠被刪除等結構上的變化。好比常見的JavaScript就是動態語言,除此之外Python等也屬於動態語言,而C、C++則不屬於動態語言。從反射角度說Java屬於半動態語言。程序員
2.反射機制:指在運行狀態中,對於任意一個類都可以知道這個類全部的屬性和方法;而且對於任意一個對象,都可以調用它的任意一個方法;這種動態獲取信息以及動態調用對象方法的功能稱爲Java語言的反射機制。安全
3.反射的應用場合
app
編譯時類型和運行時類型ide
在Java程序中許多對象在運行時都會出現兩種類型:編譯時類型和運行時類型。編譯時的類型由聲明對象時使用的類型來決定;運行時的類型由實際賦值給對象的類型決定。如:函數
Person p = new Student(); 其中編譯時類型爲Person,運行時類型爲Student。工具
編譯時類型沒法獲取具體方法性能
程序在運行時還可能接收到外部傳入的對象,該對象的編譯時類型爲Object,可是程序有須要調用該對象的運行時類型的方法。爲了解決這些問題,程序須要在運行時發現對象和類的真實信息。然而,若是編譯時根本沒法預知該對象和類屬於哪些類,程序只能依靠運行時信息來發現該對象和類的真實信息,此時就必須使用到反射了。ui
4.Java反射APIthis
反射API 用來生成JVM中的類、接口或對象的信息。
1)Class類:反射的核心類,能夠獲取類的屬性、方法等信息。
2)Field類:Java.lang.reflect 包中的類,表示類的成員變量,能夠用來獲取和設置類中的屬性值。
3)Method類:Java.lang.refect 包中的類,表示類的方法,能夠用來獲取類中的方法信息或執行方法。
4)Constructor類:Java.lang.reflect 包中的類,表示類的構造方法。
5.反射使用步驟(獲取class對象、調用對象的方法)
1)獲取想要操做的類的Class對象,它是反射的核心,經過Class對象咱們能夠任意調用類的方法。
2)調用Class類中的方法,即就是反射的使用階段。
3)使用反射API來操做這些信息。
6.獲取Class對象的3種方法
調用某個對象的getClass()方法
Person p = new Person();
Class clazz = p.getClass();
調用某個類的class屬性來獲取該類對應的Class對象
Class clazz = Person.class;
使用Class 類中的forName()靜態方法(最安全/性能最好)
Class clazz = Class.forName("類的全路徑");
1 當咱們得到了想要操做的類的 Class 對象後,能夠經過 Class 類中的方法獲取並查看該類中的方法和屬性。 2 //獲取 Person 類的 Class 對象
3 Class clazz=Class.forName("reflection.Person"); 4 //獲取 Person 類的全部方法信息
5 Method[] method=clazz.getDeclaredMethods(); 6 for(Method m:method){ 7 System.out.println(m.toString()); 8 } 9 //獲取 Person 類的全部成員屬性信息
10 Field[] field=clazz.getDeclaredFields(); 11 for(Field f:field){ 12 System.out.println(f.toString()); 13 } 14 //獲取 Person 類的全部構造方法信息
15 Constructor[] constructor=clazz.getDeclaredConstructors(); 16 for(Constructor c:constructor){ 17 System.out.println(c.toString()); 18 }
7.建立對象的兩種方法
Class 對象的newInstance()
1)使用Class對象的newInstance()方法來建立該Class對象對應類的實例,可是這種方法要求該Class對象對應的類有默認的空構造器。
調用Constructor對象的newInstance()
2)先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來建立Class對象對應類的實例,經過這種方法能夠選定構造方法建立實例。
1 //獲取 Person 類的 Class 對象
2 Class clazz=Class.forName("reflection.Person"); 3 //使用.newInstane 方法建立對象
4 Person p=(Person) clazz.newInstance(); 5 //獲取構造方法並建立對象
6 Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class); 7 //建立對象並設置屬性
8 Person p1=(Person) c.newInstance("李四","男",20);
8.JDK動態加載
Java反射機制容許程序在運行時加載、探知、使用編譯期間徹底未知的classes。經過Java的反射機制,能夠得到程序內部或第三方JAR包的Class、Method、屬性、參數等信息。
動態加載:程序在運行時調用相應方法,即便其餘方法是錯誤的,程序依舊會執行。
靜態加載:程序在編譯時執行,在執行過程當中加載全部可能執行到的程序。在這種加載方式下,只要加載中一個方法出錯,程序就不能運行。
2、Java註解
1.概念
Annotation(註解)是Java提供的一種對源程序中元素關聯信息和元數據(metadata)的途徑和方法。Annotation(註解)是一個接口,程序能夠經過反射來獲取制定程序中元素的Annotation對象,而後經過該Annotation對象來獲取註解中的元數據信息。
2. 四種標準元註解
元註解做用是負責註解其餘註解。Java5.0定義了4個標準的meta-annotation類型,它們被用來提供對其餘annotation類型做說明。
@Target 修飾的對象範圍
@Target說明了annotation所修飾的對象範圍:annotation可被用於packages、types(類、接口、枚舉、annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在annotation類型的聲明中使用了target可更加明晰其修飾的目標。
@Retention 定義被保留的時間長短
Retention定義了該annotation被保留的時間長短:表示須要在什麼級別保存註解信息,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效),取值(RetentionPoicy)有:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在運行時有效(即運行時保留)
@Documented 描述-javadoc
@Documented用於描述其餘類型的annotation應該被做爲被標註的程序成員的公共API,所以能夠被例如javadoc此類的工具文檔化。
@Inherited 闡述了某個被標註的類型是被繼承的
@Inherited元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。
3.註解處理器
若是沒有用來讀取註解的方法和工做,那麼註解也就不會比註釋更有用處了。使用註解的過程當中,很重要的一部分就是建立與使用註解處理器。Java SE5擴展了反射機制的API,以幫助程序員快速的構造自定義註解處理器。下面實現一個註解處理器。
1 /1:*** 定義註解*/
2 @Target(ElementType.FIELD) 3 @Retention(RetentionPolicy.RUNTIME) 4 @Documented 5 public @interface FruitProvider { 6 /**供應商編號*/
7 public int id() default -1; 8 /*** 供應商名稱*/
9 public String name() default ""; 10 /** * 供應商地址*/
11 public String address() default ""; 12 } 13 //2:註解使用
14 public class Apple { 15 @FruitProvider(id = 1, name = "陝西紅富士集團", address = "陝西省西安市延安路") 16 private String appleProvider; 17 public void setAppleProvider(String appleProvider) { 18 this.appleProvider = appleProvider; 19 } 20 public String getAppleProvider() { 21 return appleProvider; 22
23 } 24 /3:*********** 註解處理器 ***************/
25 public class FruitInfoUtil { 26 public static void getFruitInfo(Class<?> clazz) { 27 String strFruitProvicer = "供應商信息:"; 28 Field[] fields = clazz.getDeclaredFields();//經過反射獲取處理註解
29 for (Field field : fields) { 30 if (field.isAnnotationPresent(FruitProvider.class)) { 31 FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);//註解信息的處理地方
32 strFruitProvicer = " 供應商編號:" + fruitProvider.id() + " 供應商名稱:"
33 + fruitProvider.name() + " 供應商地址:"+ fruitProvider.address(); 34 System.out.println(strFruitProvicer); 35 } 36 } 37 } 38 } 39 public class FruitRun { 40 public static void main(String[] args) { 41 FruitInfoUtil.getFruitInfo(Apple.class); 42 /***********輸出結果***************/
43 // 供應商編號:1 供應商名稱:陝西紅富士集團 供應商地址:陝西省西安市延
44 } 45 }