@
目錄- 一、類的加載概述
- 二、反射的基本使用
- 2.1 獲取Class位元組碼物件
- 2.2 獲取構造方法
- 2.3 獲取成員變數
- 2.4 獲取成員方法并使用
- 三、案例
- 3.1 通過反射運行組態檔
- 3.2 通過反射越過泛型檢查
- 3.3 通過反射寫一個Tool工具類,設定任意物件的任意屬性
一、類的加載概述
加載
- 就是指將class檔案讀入記憶體,并為之創建一個Class物件
- 任何類被使用時系統都會建立一個Class物件
連接
- 驗證:是否有正確的內部結構,并和其他類協調一致
- 準備:負責為類的靜態成員分配記憶體,并設定默認初始化值
- 決議:將類的二進制資料中的符號參考替換為直接參考
初始化
- 就是我們之前講過的初始化步驟
類的初始化時機(什么時候被加載)
- 創建類的實體
- 用到類的靜態變數
- 用到類的靜態方法
- 使用反射方式強制創建某個類或介面對應的
java.lang.Class物件- 初始化某個類的子類 直接使用
java.exe命令來運行某個主類
類加載器
引導類加載器(Bootstrap ClassLoader)
- 引導類加載器是jvm在運行時,內嵌在jvm中的一段特殊的用來加載java核心類別庫的C++代碼,String.class 物件就是由引導類加載器加載的,引導類加載器具體加載哪些核心代碼可以通過獲取值為 "sun.boot.class.path" 的系統屬性獲得,引導類加載器不是java原生代碼撰寫的,所以其也不是java.lang.ClassLoader類的實體,其沒有getParent方法,
拓展類加載器(Extension ClassLoader)
- 拓展類加載器用來加載jvm實作的一個拓展目錄,該目錄下的所有java類都由此類加載器加載,此路徑可以通過獲取"java.ext.dirs"的系統屬性獲得,拓展類加載器就是java.lang.ClassLoader類的一個實體,其getParent方法回傳的是引導類加載器(在 HotSpot虛擬機中用null表示引導類加載),
應用類加載器(Application ClassLoader)
- 應用類加載器又稱為系統類加載器,開發者可用通過 java.lang.ClassLoader.getSystemClassLoader()方法獲得此類加載器的實體,系統類加載器也因此得名,其主要負責加載程式開發者自己撰寫的java類,一般來說,java應用都是用此類加載器完成加載的,可以通過獲取"java.class.path"的系統屬性(也就是我們常說的classpath)來獲取應用類加載器加載的類路徑,應用類加載器是java.lang.ClassLoader類的一個實體,其getParent方法回傳的是拓展類加載器,
二、反射的基本使用
2.1 獲取Class位元組碼物件
getClass()
.class
Class.forName("檔案全路徑")
2.2 獲取構造方法
獲取所有
public Constructor[] getConstructors()
public Constructor[] getDeclaredConstructors()
獲取單個
public Constructor<T> getConstructor(Class<?>...parameterTypes);//帶有引數
getDeclaredConstructor();//獲取私有構造方法物件
con.setAccessible(true;//指反射的物件在使用時應取消java語言訪問檢查,暴力訪問
con.newInstance();//使用構造方法物件表示的構造方法來創建該構造方法的宣告類的新實體
代碼:獲取無參建構式
public class ReflexDemo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 獲取位元組碼物件
Class person = Class.forName("Person");
// 獲取構造方法
Constructor constructor = person.getConstructor();
// 實體化物件
Object obj = constructor.newInstance();
System.out.println(obj);//Person@1b6d3586
}
}
代碼:獲取帶參建構式
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class person = Class.forName("Person");
Constructor constructor = person.getConstructor(String.class, String.class, int.class);
Object obj = constructor.newInstance("張三","男",20);
System.out.println(obj);
}
代碼:獲取私有建構式
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class person = Class.forName("Person");
Constructor constructor = person.getDeclaredConstructor(String.class, String.class, int.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance("張三","男",20);
System.out.println(obj);
}
注意:如果不設定 constructor.setAccessible(true);
會報錯:java.lang.IllegalAccessException: Class ReflexDemo01 can not access a
member of class Person with modifiers "private"
2.3 獲取成員變數
獲取所有
- Field[] getFields()
- Field[] getDeclaredFields()
獲取單個
- Filed getField("成員變數名")
- Field getDeclaredField()
- field.setAccessible(true)
2.4 獲取成員方法并使用
- getMethods
- getDeclaredMethods
- getMethod
- getDeclaredMethod
- method.setAccessible(true)
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class person = Class.forName("Person");
Constructor constructor = person.getDeclaredConstructor(String.class, String.class, int.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance("張三","男",20);
// Method[] methods = c.getMethods(); // 獲取自己的包括父親的公共方法
// Method[] methods = c.getDeclaredMethods(); // 獲取自己的所有的方法
//Method[] methods = c.getMethod(String name,Class<?>... parameterTypes)
// 第一個引數表示的方法名,第二個引數表示的是方法的引數的class型別
Method method01 = person.getMethod("method01");
Method method02 = person.getMethod("method02", String.class);
Method method03 = person.getDeclaredMethod("method03", String.class, int.class);
method03.setAccessible(true);
method01.invoke(obj);
method02.invoke(obj,"hello");
Object resultStr = method03.invoke(obj, "hello", 123);
System.out.println(resultStr);
}
三、案例
3.1 通過反射運行組態檔
/**
* 通過反射運行組態檔
*/
public class ReflexDemo02 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 讀取鍵值對資料
Properties prop = new Properties();
FileReader fr = new FileReader("F:\\Projects\\idea_projects\\javaseTest\\09reflex\\src\\class.txt");
prop.load(fr);
fr.close();
// 獲取檔案資料
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
// 反射
Class c = Class.forName(className);
Constructor constructor = c.getConstructor();
Object obj = constructor.newInstance();
Method method = c.getMethod(methodName);
method.invoke(obj);
}
}
3.2 通過反射越過泛型檢查
/**
* 通過反射越過泛型檢查
*/
public class ReflexDemo03 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 創建集合
ArrayList<Integer> arrayList = new ArrayList<Integer>();
// arrayList.add(123);
// arrayList.add("hello");//直接呼叫編譯期就會報錯
Class c = arrayList.getClass();
Method m = c.getMethod("add", Object.class);
m.invoke(arrayList,"hello");
m.invoke(arrayList,"world");
m.invoke(arrayList,"java");
System.out.println(arrayList);//[hello, world, java]
}
}
3.3 通過反射寫一個Tool工具類,設定任意物件的任意屬性
public class PropertyTools {
/**
* 給傳入物件設定屬性
*/
public void setProperty(Object obj,String propertyName,Object value) throws NoSuchFieldException, IllegalAccessException {
// 根據物件獲取位元組碼物件
Class c = obj.getClass();
// 根據名稱獲取成員變數
Field field = c.getDeclaredField(propertyName);
// 取消訪問檢查
field.setAccessible(true);
// 給物件的成員變數賦值為指定的值
field.set(obj,value);
}
/**
* 測驗該工具類
*/
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person();
PropertyTools tools = new PropertyTools();
tools.setProperty(person,"name","林青霞");
tools.setProperty(person,"sex","女");
tools.setProperty(person,"age",20);
System.out.println(person);//Person{name='林青霞', sex='女', age=20}
}
}
感覺這個案例很能說明:反射破壞了封裝性
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/181220.html
標籤:Java
上一篇:COLA的擴展性使用和原始碼研究
