簡單介紹下反射機制[中高]?
反射是框架設計的靈魂.
(使用的前提條件:必須先得到代表的位元組碼的Class,Class類用於表示.class檔案(位元組碼))
什麼是反射?
Java反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為Java語言的反射機制。
要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼檔案對應的Class型別的物件.
Class是反射的基石。
1、Class是一個類,一個描述類的類(也就是描述類本身),封裝了描述方法的Method,描述欄位的Filed,描述構造器的Constructor等屬性,通過反射可以得到類的各種成分。
2、對於每個類而言,JRE 都為其保留一個不變的 Class 型別的物件。一個 Class 物件包含了特定某個類的有關資訊。
3、Class 物件只能由jvm建立
4、一個類在 JVM 中只會有一個Class例項
5、反射相關的類這個包下:java.lang.reflect
獲取Class物件的三種方式要知道。
- Object ——> getClass();
- 任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性
- 通過Class類的靜態方法:Class.forName(String className)(常用,一般都是使用這個)
參考程式碼: GetClassTest
// 獲取Class物件的三種方式測試 public class GetClassTest { public static void main(String[] args) { // 第一種方式獲取Class物件 Student stu1 = new Student(); // 獲取Class物件 Class stuClass = stu1.getClass(); System.out.println(stuClass.getName()); // 第二種方式獲取Class物件 Class stuClass2 = Student.class; // 判斷第一種方式獲取的Class物件和第二種方式獲取的是否是同一個 System.out.println("第一種和第二種方式的class是否相等:" + (stuClass == stuClass2)); // 第三種方式獲取Class物件,一般都是用這種方式,強烈推薦這種方式 try { // 注意此字串必須是真實路徑,就是帶包名的類路徑,包名.類名 Class stuClass3 = Class.forName("com.cto.edu.basic.Student"); // 判斷三種方式是否獲取的是同一個Class物件 System.out.println("第二種和第三種方式的class是否相等:" + (stuClass3 == stuClass2)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
專案中使用的很多的例子:
使用jdbc連結資料庫的時,都用的反射,一般都是通過配置檔案書寫連結哪個資料庫,比如mysql、orcle等,以及對應的關鍵資訊。
簡單總結說:
反射就是把java類中的各種成分對映成一個個的Java物件。
例如:一個類有:成員變數、方法、構造方法、包等等資訊,利用反射技術可以對一個類進行解剖,把個個組成部分對映成一個個物件。
核心的幾個類:
Class類:代表一個類
Constructor類:代表類的構造方法
Filed類:代表類的成員變數
Method類:代表類的方法
參考程式碼: ConstructorsTest FieldsTest
/* * 利用反射獲取構造方法測試 * 通過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員; * * 1.獲取構造方法: * 1).批量的方法: * public Constructor[] getConstructors():所有"公有的"構造方法 public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有) * 2).獲取單個的方法,並呼叫: * public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法: * public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有; * * 呼叫構造方法: * Constructor-->newInstance(Object... initargs) */ public class ConstructorsTest { public static void main(String[] args) throws Exception { //載入Class物件 Class cla = Class.forName("com.cto.edu.basic.Student"); System.out.println("**********************所有公有構造方法*********************************"); Constructor[] conArray = cla.getConstructors(); for(Constructor c : conArray){ System.out.println(c); } System.out.println(); System.out.println("************所有的構造方法(包括:私有、受保護、預設、公有)***************"); conArray = cla.getDeclaredConstructors(); for(Constructor c : conArray){ System.out.println(c); } System.out.println(); System.out.println("*****************獲取公有、無參的構造方法*******************************"); // Constructor con = cla.getConstructor(); Constructor con = cla.getConstructor(null); //1>、因為是無參的構造方法所以型別是一個null,不寫也可以:這裡需要的是一個引數的型別,切記是型別 //2>、返回的是描述這個無參建構函式的類物件。 System.out.println("con = " + con); //呼叫構造方法 Object obj = con.newInstance(); System.out.println(); System.out.println("******************獲取私有構造方法,並呼叫*******************************"); con = cla.getDeclaredConstructor(int.class); System.out.println(con); //呼叫構造方法 con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符) obj = con.newInstance(20); } }
/*
* 利用反射獲取成員變數並呼叫測試:
*
* 1.批量的
* 1).Field[] getFields():獲取所有的"公有欄位"
* 2).Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有;
* 2.獲取單個的:
* 1).public Field getField(String fieldName):獲取某個"公有的"欄位;
* 2).public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
*
* 設定欄位的值:
* Field --> public void set(Object obj,Object value):
* 引數說明:
* 1.obj:要設定的欄位所在的物件;
* 2.value:要為欄位設定的值;
*
*/
public class FieldsTest {
public static void main(String[] args) throws Exception {
//獲取Class物件
Class stuClass = Class.forName("com.cto.edu.basic.Student");
System.out.println("************獲取所有公有的欄位********************");
Field[] fieldArray = stuClass.getFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println();
System.out.println("************獲取所有的欄位(包括私有、受保護、預設的)********************");
fieldArray = stuClass.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println();
System.out.println("*************獲取公有欄位**並呼叫***********************************");
Field f = stuClass.getField("name");
System.out.println(f);
//獲取一個物件 --》相當於Student stu = new Student();
Object obj = stuClass.getConstructor().newInstance();
//為欄位賦值
f.set(obj, "張三");//為Student物件中的name屬性賦值--》stu.name = "張三"
//驗證
Student stu = (Student)obj;
System.out.println("驗證姓名:" + stu.name);
System.out.println();
System.out.println("**************獲取私有欄位****並呼叫********************************");
f = stuClass.getDeclaredField("tellphone");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "13512345678");
System.out.println("驗證電話:" + stu.getTellphone());
}
}