帶你走進java.第二十四章.類的載入,反射
阿新 • • 發佈:2018-12-11
類的載入
1.類是如何載入的? 一. 載入 (將類的.class檔案 載入到方法區中) 建立一個class物件(代表.class檔案,相當於檔案物件) 二.連線 1.驗證:驗證一下類的內部結構(成員變數 和方法[成員方法,構造方法] ) 2.準備: 為靜態變數開闢一塊空間 , 賦初值 3.解析: 將區域性變數進行替換, 替換成對應的值 如 int a = 10; 下面會將所有的a 替換成 10 三.初始化 建立物件 (new一個物件,在堆記憶體開闢空間) 2.類是什麼時候被載入的? (載入時機) 當你使用類的時候 該類一定會被載入 載入該類時 會先載入該類的父類(保證繼承完整性) 3.類是用什麼載入的? (使用 類載入器 載入類) 1.根載入器[載入jdk的lib資料夾 jar檔案] 2.拓展載入器[載入jdk的ext資料夾下 的檔案] 3.系統載入器[自己自定義的類或者匯入的jar]
反射
1.什麼是反射?
反射可以將一個正在執行的類(載入完成的類)
通過這個.class檔案的class物件
可以直接獲取類內部的 所有成員變數和方法(包括私有的)
獲取構造方法
// 第一步. 獲取.class檔案的class物件 /* * 獲取class檔案物件 * 1.通過物件獲取 * 2.通過類獲取 * 3.通過class中的靜態方法獲取(Class.ForName() 常用) */ // 1.通過物件獲取 Person p = new Person(); Class<? extends Person> c1 = p.getClass();// 獲取Person類的 class檔案物件 System.out.println(c1); // 2.通過類獲取 Class<Person> c2 = Person.class; System.out.println(c2); // 3.常用(只需要一個字串,就能獲取該類的class物件) // 注意:引數 要填全類名(包名+類名) Class<?> c3 = Class.forName("com.reflect.Person"); System.out.println(c3);
// 獲取公開的構造方法 getConstructors() // 通過class檔案物件 獲取類中構造方法 Class<?> c = Class.forName("com.reflect.Person"); // 獲取所有public公開的構造方法 Constructor<?>[] constructors = c.getConstructors(); // 遍歷 for (Constructor<?> constructor : constructors) { System.out.println(constructor); } // 獲取單個構造方法 Constructor<?> constructor = c.getConstructor(); // 利用該構造方法建立物件 Object object = constructor.newInstance(); System.out.println(object); // 呼叫 有參的構造方法,建立物件 // **獲取有參構造方法的引數是 有參構造方法的引數類的檔案型別** Constructor<?> constructor2 = c.getConstructor(String.class,int.class); // 建立物件 Object object2 = constructor2.newInstance("張三",30); System.out.println(object2);
// 通過class檔案物件,快速建立物件 newInstance()
/*
* 通過Class檔案物件 快速建立物件
* 前提:
* 1.類必須用public修飾
* 2.必須提供無參構造方法
* 3.該無參的構造方法必須是public修飾
*/
Class<?> c = Class.forName("com.reflect.Person");
// 快速建立物件(直接使用類中的無參構造方法建立)
Object object = c.newInstance();
System.out.println(object);
// 獲取所有的構造方法,包括私有構造方法 getDeclaredConstructors()
// 特殊: 要開啟私有方法的使用許可權 setAccessible(true)
Class<?> c = Class.forName("com.reflect.Person");
//獲取類中所有的構造方法(包括私有)
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructors) {
System.out.println(constructor);
}
// 獲取私有的構造方法
Constructor<?> declaredConstructor = c.getDeclaredConstructor(int.class,String.class);
// 開啟私有方法的使用許可權
declaredConstructor.setAccessible(true);
// 建立物件
Object object = declaredConstructor.newInstance(30,"張三");
System.out.println(object);
獲取成員變數
// 獲取所有的公開的成員變數
Class<?> c = Class.forName("com.reflect.Person");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
// 單獨獲取指定的成員變數
// 引數是 成員變數的名稱
Field field = c.getField("name");
// 建立一個Person物件
Object object = c.newInstance();
// 通過反射,給(物件)該屬性賦值(value)
field.set(object, "wangjun");
// 檢視物件的成員變數
System.out.println(object);
// 獲取私有的成員變數
Field declaredField = c.getDeclaredField("age");
// 開啟私有的許可權
declaredField.setAccessible(true);
// 設定私有的成員變數
declaredField.set(object, 23);
// 列印物件的成員變數
System.out.println(object);
例題 :
/*
利用反射完成以下方法
1.此方法可將obj物件中名為propertyName的屬性的值設定為value.
相當於用反射 寫一個set方法
引數:
1.賦值的物件
2.屬性名字
3.給該屬性賦的值
2.此方法可以獲取obj物件中名為propertyName的屬性的值
相當於用反射 寫一個get方法
引數:
1.賦值的物件
2.要獲取的屬性的名
*/
public static void main(String[] args) throws Exception {
// 測試
Class<?> c = Class.forName("com.lanou3g.reflect.Person");
Object object = c.newInstance();
setName(object, "name", "王五");
System.out.println(object);
Object name = getName(object, "name");
System.out.println(name);
}
// 賦值
public static void setName(Object object,String name,Object value) throws Exception{
// 獲取.class檔案物件
Class<? extends Object> class1 = object.getClass();
// 從檔案中提取屬性
Field declaredField = class1.getDeclaredField(name);
// 開啟許可權
declaredField.setAccessible(true);
// 賦值
declaredField.set(object, value);
}
public static Object getName(Object object,String name) throws Exception {
// 獲取.class檔案物件
Class<? extends Object> c = object.getClass();
// 獲取對應的成員變數
Field declaredField = c.getDeclaredField(name);
// 開啟許可權
declaredField.setAccessible(true);
// 從物件中獲取name的值
Object value = declaredField.get(object);
return value;
}
獲取成員方法
Class<?> c = Class.forName("com.reflect.Person");
// 獲取類中所有的公開的成員方法(包括父類的)
Method[] methods = c.getMethods();
// for (Method method : methods) {
// System.out.println(method);
// }
// 獲取指定的成員方法
// 引數1 獲取的方法名
// 引數2 獲取的 成員方法的引數的class型別(沒引數就不填)
Method method = c.getMethod("speak",String.class);
// 建立一個物件
Object object = c.newInstance();
// 呼叫該方法
// 引數1: 呼叫該方法的物件
// 引數2: 呼叫該方法 要傳入的引數
// 返回值: 呼叫該方法的返回值
Object invoke = method.invoke(object,"王五6666");
System.out.println(invoke);
// 獲取所有的成員方法(包括私有)
Method[] declaredMethods = c.getDeclaredMethods();
// 獲取私有方法
Method declaredMethod = c.getDeclaredMethod("play", String.class);
// 開啟許可權
declaredMethod.setAccessible(true);
// 呼叫方法
Object invoke2 = declaredMethod.invoke(object, "lol");
System.out.println(invoke2);
例題
/*
* 利用反射
* 向ArraryList<String>中 新增 Integer資料 Person物件
* 注意: 編譯成class檔案 泛型不存在
*/
ArrayList<String> list = new ArrayList<>();
// 獲取.class檔案物件
Class<?> c = Class.forName("java.util.ArrayList");
// 獲取所有方法
Method declaredMethod = c.getDeclaredMethod("add",Object.class);
// 開啟許可權
declaredMethod.setAccessible(true);
// 呼叫方法
Object invoke = declaredMethod.invoke(list, 123);
Object invoke2 = declaredMethod.invoke(list, new Person("張三", 23));
Object invoke3 = declaredMethod.invoke(list, "哈哈");
System.out.println(list);
