@ 一、類的載入概述 載入 就是指將class文件讀入記憶體,併為之創建一個Class對象 任何類被使用時系統都會建立一個Class對象 連接 驗證:是否有正確的內部結構,並和其他類協調一致 準備:負責為類的靜態成員分配記憶體,並設置預設初始化值 解析:將類的二進位數據中的符號引用替換為直接引用 初始化 ...
@目錄
一、類的載入概述
載入
- 就是指將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}
}
}
感覺這個案例很能說明:反射破壞了封裝性