反射的原理及應用
阿新 • • 發佈:2018-12-31
原理:反射首先是能夠獲取到Java中的反射類的位元組碼,然後將位元組碼中的方法,變數,建構函式等對映成 相應的 Method、Filed、Constructor 等類
應用:取出類的modifiers,資料成員,方法,構造器,和超類
找出某個接口裡定義的常量和方法說明.
取得和設定物件資料成員的值,如果資料成員名是執行時刻確定的也能做到.
在執行時刻呼叫動態物件的方法.
1,類的載入
當程式要使用某個類時,如果該類還未被載入到記憶體中,則系統會通過載入,連線,初始化三步來實
現對這個類進行初始化。
- 載入 就是指將 class 檔案讀入記憶體,併為之建立一個 Class 物件。 任何類被使用時系統都會建立一個 Class 物件
- 連線 驗證 是否有正確的內部結構,並和其他類協調一致 準備 負責為類的靜態成員分配記憶體,並設定預設初始化值 解析 將類的二進位制資料中的符號引用替換為直接引用
- 初始化
1.2類的初始化
- 建立類的例項
- 類的靜態變數,或者為靜態變數賦值
- 類的靜態方法
- 使用反射方式來強制建立某個類或介面對應的 java.lang.Class 物件
- 初始化某個類的子類
1.3反射概述
Java 反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱 為 java 語言的反射機制。
要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖這個類,使用的就是 Class 類中的方法,所以先要獲取到每一個位元組碼檔案所對應的 Class 型別物件。
1.4準備資料,我就用我現在的寫的專案的資料,大家隨意
1.5 知識儲備
需要掌握 6 個單詞
- Class 類
- Constructor 構造
- Method 方法
- Filed 欄位
- instance 例項
- invoke 執行
1.6 Class 獲得方式
public class A {
/**
* class獲得方式
*
* @param args
*/
public static void main(String[] args) {
//1 通過型別獲得
// 語法:類名.class
// 應用場景:確定型別 等
Class clazz1 = BrandController.class;
System.out.println("語法:類名.class|" + clazz1);
//2 通過例項物件獲得
// 語法:變數.getClass()
// 應用場景:在方法內部通過引數獲得型別 等
BrandController brandController = new BrandController();
Class<? extends BrandController> aClass = brandController.getClass();
System.out.println("語法:變數.getClass()|" + aClass);
//3 通過字串獲得
// 語法:Class.forName("全限定類名")
// 應用場景:通過配置獲得字串 等
try {
Class<?> aClass1 = Class.forName("com.controller.BrandController");
System.out.println("Class.forName(\"全限定類名\")|"+aClass1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
1.6.1 得到這個類的名字
//1 獲得 Class
Class clazz = User.class;
// 得到這個類的名字:全限定類名
String name = clazz.getName();
// 這個只是類的名字
String simpleName = clazz.getSimpleName();
System.out.println(" 這個只是類的名字simpleName:"+simpleName);
System.out.println("得到這個類的名字:全限定類名name:"+name);
1.7構造方法與例項
public class A {
/**
* 構造方法與例項
*
* @param args
*/
public static void main(String[] args) {
//無參構造 , 並例項化
//1 獲得 Class
Class<SpecificationOption> specificationOptionClass = SpecificationOption.class;
System.out.println("獲得 Class"+specificationOptionClass);
//2 獲得構造 -- 沒有形參
Constructor<SpecificationOption> constructor = null;
try {
constructor = specificationOptionClass.getConstructor();
System.out.println("獲得構造 -- 沒有形參"+constructor);
SpecificationOption specificationOption = constructor.newInstance();
System.out.println("例項物件,沒有實參"+specificationOption);
} catch (Exception e) {
e.printStackTrace();
}
}
}
獲取無參的簡化版
public class A {
/**
* 構造方法與例項
*
* @param args
*/
public static void main(String[] args) {
//無參構造 , 並例項化
//1 獲得 Class
try {
// 獲得無參的簡化版
SpecificationOption specificationOption = SpecificationOption.class.newInstance();
System.out.println(specificationOption);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
獲取有參構造
public static void main(String[] args) {
//有參構造 , 並例項化
//1 獲得 Class
Class beanClass = SpecificationOption.class;
//2 獲得構造 -- 三個字串形參 -- (Integer.class,String.class,Integer.class)
Constructor constructor = null;
try {
constructor = beanClass.getConstructor(Integer.class, String.class, Integer.class);
System.out.println("獲得構造 -- 三個字串形參" + constructor);
//3 例項物件,三個字串實參
Object o = constructor.newInstance(2323,"白色", 1);
System.out.println(o);
} catch (Exception e) {
e.printStackTrace();
}
}
1.7.5 擴充套件:私有構造(暴力反射)
- 修改 Bean 新增私有構造
private Bean(String id) {
this.id = id;
System.out.println("有參構造:" + id);
}
- getConstructor() 使用該方法將無法獲得私有方法,程式執行拋異常
- 沒有使用 setAccessible(true),將拋異常
@Test
public void testPrivateCons() throws Exception{
//私有構造
//1 獲得 Class
Class beanClass = Bean.class;
//2 獲得構造 -- 兩個字串形參 -- Bean(String id, String className)
// * getConstructor() 將拋異常 java.lang.NoSuchMethodException
// * getDeclaredConstructor 可以獲得私有構造
Constructor constructor = beanClass.getDeclaredConstructor(String.class)
//暴力訪問
constructor.setAccessible(true);
//3 例項物件,兩個字串實參
Object bean = constructor.newInstance("userId");
System.out.println(bean);
1.8方法與執行
1.8.1public 方法
- 獲得方法並設定
//1 獲得 Class
Class clazz = User.class;
//2 獲得例項 ,相當於 Object obj = new Bean();
Object obj = clazz.newInstance();
//3 操作 setAge 方法
// * 格式:getMethod(方法名,形成列表)
Method setMethod = clazz.getMethod("setAge", Integer.class);
System.out.println("getMethod(方法名,形成列表)"+setMethod);
//3.2 執行方法,一個實參
Object setReturnObj = setMethod.invoke(obj, 12);
System.out.println("set 方法返回值:" + setReturnObj);
1.8.2私有方法(暴力反射)private
新增私有方法
//4 操作 getId 方法
// 4.1 獲得方法,沒有形參
Method getMethod = clazz.getMethod("getAge");
// 4.2 執行方法,沒有實參
Object getReturnObj = getMethod.invoke(obj);
System.out.println("get 方法返回值:" + getReturnObj);
//5 暴力反射私有的構造方法
Method showMethod = clazz.getDeclaredMethod("show");
System.out.println("暴力反射私有的構造方法show "+showMethod);
//暴力訪問
showMethod.setAccessible(true);
// 4 執行方法,沒有實參
// obj.setMethod(args) user.setAge(20)
Object invoke = setMethod.invoke(obj, 20);
Object result = showMethod.invoke(obj);
System.out.println("show私有"+result);
1.8.3 main 方法與執行
新增main方法
//有參構造 , 並例項化
Class<User> clazz = User.class;
//2 獲得方法 -- main 靜態方法 -- public static void main(String[] args)
Method mainMethod = clazz.getMethod("main", String[].class);
Object getReturnObj = mainMethod.invoke(null, (Object)new String[]{"aaa","bbb"});
System.out.println("main 方法返回值:|||||||||" + getReturnObj);
1.8.4 public 欄位的操作
//5 操作欄位,進行賦值,public String name;
//5.1 獲得的欄位,一個形參
// * 格式:getField(欄位名)
Field descriptionField = clazz.getField("name");
System.out.println("getField(欄位名) "+descriptionField);
//5.2 為物件的欄位賦值
descriptionField.set(obj, "喜歡在文字中傾訴");
//5.3 獲取物件的欄位值
Object fieldReturnObj = descriptionField.get(obj);
System.out.println("description 欄位返回值: "+fieldReturnObj);
1.8.5 private 欄位的操作
//5 操作欄位,進行賦值,private String name;
//5.1 獲得的欄位,一個形參
// * 格式:getDeclaredField(欄位名)
Field descriptionField = clazz.getDeclaredField("name");
System.out.println("getDeclaredField(欄位名) "+descriptionField);
//暴力訪問
descriptionField.setAccessible(true);
//5.2 為物件的欄位賦值
descriptionField.set(obj, "喜歡在文字中傾訴");
//5.3 獲取物件的欄位值
Object fieldReturnObj = descriptionField.get(obj);
System.out.println("description 欄位返回值: "+fieldReturnObj);