反射
類加載器
類加載
當程式要使用某個類時,如果該類還未被加載到記憶體中,則系統會通過類得加載,類的連接,類的初始化這三個步驟來對類進行初始化,如果不出現意外情況,JVM將會連續完成這三個步驟,所以有時也把這三個步驟統稱為類加載或類初始化
-
類加載:
- 就是將class檔案讀入記憶體,并為之創建一個java.lang.Class物件
- 任何類被使用時,系統都會為之創建一個java.lang.Class物件
-
類的連接
- 驗證階段:用于檢測被類加載的類是否具有正確的內部結構,并和其他類協調一致
- 準備階段:負責為類的類變數分配記憶體,并設定默認初始值
- 決議階段:將類的二進制資料中的符號參考替換為直接參考
-
類的初始化
- 在該階段,主要對類變數進行初始化
- 類初始化步驟
- 假如類還未被加載和連接,則程式先加載并連接該類
- 假如該類的直接父類還未被初始化,則先初始化直接父類
- 假如類中有初始化陳述句,則系統依次執行這些初始化陳述句
在執行第二個步驟時,系統對直接父類的初始化步驟也遵循初始化步驟1-3
- 類的初始化時機:
- 創建類的實體
- 呼叫類的類方法
- 訪問類或者介面變數,或者為該類變數賦值
- 使用反射方式來強制創建某個類或者介面對應的java.lang.Class物件
- 初始化某個類的子類
- 直接使用java.exe命令來運行某個主類
類加載器
作用:
- 負責將.class檔案加載到記憶體中,并為之生成對應的java.lang.Class物件
- 雖然我們不過分關系類加載機制,但是了解這個機制我們就能更好的理解程式的運行
JVM的類加載機制:
- 全盤負責:就是當一個類加載器負責加載某個Class時,該Class所依賴的和參考的其他Class也將由該類加載器負責載入,除非顯示使用另外一個類加載器來載入
- 父類委托:就是當一個類加載器負責加載某個Class時,先讓父類加載器試圖加載該Class物件時,只有在父類加載器無法加載類時才嘗試從自己的路徑中加載該類
- 快取機制:保證所有加載過的Class都會被快取,當程式需要使用某個Class物件時,類加載器先從快取區中搜索該Class,只有當快取區中不存在該Class物件時,系統才會讀取該類對應的二進制資料,并將其轉換成Class物件,存盤到快取區
ClassLoader:是負責加載類的物件
java運行時具有以下內置類加載器
- Bootstrap class loader:它是虛擬機的內置類加載器,通常表示為null,并且沒有父類null
- Platform class loader , 平臺類加載器可以看到所有平臺類 ,可以將其用作ClassLoader實體的父ClassLoader , 平臺類包括由平臺類加載器或其祖先定義的Java SE平臺API,其實作類和JDK特定的運行時類,
- System class loader , 它也被稱為應用程式類加載器 ,與平臺類加載器不同, 系統類加載器通常用于定義應用程式類路徑,模塊路徑和JDK特定工具上的類,
類加載器的繼承關系:System的父加載器為Platform,而Platform得父加載器為Bootstrap
ClassLoader中得兩個方法
- static ClassLoader getSystemClassLoader():回傳用于委派得系統類加載器
- ClassLoader getParent():回傳父類加載器進行委派
public class Demo {
public static void main(String[] args) {
//系統類加載器
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c); //AppClassLoader
//系統類加載器得父類加載器
ClassLoader c2 = c.getParent();
System.out.println(c2);//PlatformClassLoader
ClassLoader c3 = c2.getParent();
System.out.println(c3);//null Bootstrap類加載器通常表示為null
}
}
反射
java反射機制:是指在運行時去獲取一個類得變數和方法資訊,然后通過獲取到得資訊來創建物件,呼叫方法得一種機制,由于這種動態性,可以極大得增強程式得靈活性,程式不用在編譯期就完成確定,在運行期仍然可以擴展,
獲取Class類得物件
想要用過反射去使用一個類,首先要獲取到該類的位元組碼檔案物件,也就是型別為Class型別的物件,
獲取Calss型別物件的三種方式
- 使用類的class屬性來獲取該類對應的Class物件,例如:Student.class將會回傳Student類對應的Class物件
- 呼叫物件的getClass()方法,回傳該物件所屬類對應的Class物件
- 該方法時Object類中的方法,所有的Java物件都可以呼叫該方法
- 使用Class類中的靜態方法forName(String className),該方法需要傳入字串引數,該字串引數的值是某個類的全路徑,也就是完整包名的路徑
public class Student {
//成員變數:一私,一默認,一公
private String name;
int age;
public String address;
//構造方法:一公,一私,一默認
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(int age, String address) {
this.age = age;
this.address = address;
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成員方法:一個私有,四公
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method" + s);
}
public String method3(String s, int i){
return s + "," + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
//使用類的class屬性來獲取該類對應的Class物件,
Class<Student> c1 = Student.class;
System.out.println(c1);
Class<Student> c2 = Student.class;
System.out.println(c1 == c2);
System.out.println("--------------");
//呼叫物件的getClass()方法,回傳該物件所屬類對應的Class物件
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1 == c3);
System.out.println("--------------");
//使用Class類中的靜態方法forName(String className)
Class<?> c4 = Class.forName("反射.獲取Class物件的三種方式.Student");//package 反射.獲取Class物件的三種方式;//最靈活
System.out.println(c1 == c4);
}
}
反射獲取構造方法并使用
public class Student {
//成員變數:一私,一默認,一公
private String name;
int age;
public String address;
//構造方法:一公,一私,一默認
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(int age, String address) {
this.age = age;
this.address = address;
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成員方法:一個私有,四公
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method" + s);
}
public String method3(String s, int i){
return s + "," + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
Class類中用于獲取構造方法的方法
- getConstructors?() 回傳一個包含 Constructor物件的陣列
import java.lang.reflect.Constructor;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Constructor<?>[] cons = c.getConstructors();
for (Constructor con : cons){
System.out.println(con);
}
}
}
- Constructor<?>[] getDeclaredConstructors?():回傳所有構造方法物件的陣列
import java.lang.reflect.Constructor;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Constructor<?>[] cons = c.getDeclaredConstructors();
for (Constructor con : cons){
System.out.println(con);
}
}
}
- Constructor
getConstructor?(Class<?>.. .parameterTypes):回傳單個公共構造方法
- Constuructor 類中用于創建物件的方法
- T newInstance?(Object... initargs):根據指定的構造方法創建物件
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
}
}
- Constructor
getDeclaredConstructor?(Class<?>... parameterTypes):回傳單個構造方法物件
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Constructor<?> con = c.getDeclaredConstructor();
Object obj = con.newInstance();
System.out.println(obj);
}
}
練習1
通過反射實作
- Student s = new Student("張三",18,"廣東")
- System.out.println(s)
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
//public Student(String name, int age, String address)
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);//基本資料型別也可以通過.class得到
Object obj = con.newInstance("張三", 18, "廣東");
System.out.println(obj);
}
}
練習2
- Student s = new Student("張三")
- System.out.println(s)
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
// private Student(String name) 私有無法創建物件需要暴力反射
Constructor<?> con = c.getDeclaredConstructor(String.class);
//暴力反射
//public void setAccessible (boolean flag):值為true,取消訪問檢測
con.setAccessible(true);
Object obj = con.newInstance("張三");
System.out.println(obj);
}
}
反射成員變數并使用
獲取成員變數的四個方法
- Field[] getFields?():回傳所有公共成員變數的陣列
import java.lang.reflect.Field;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
- Field[] getDeclaredFields?():回傳所有成員變數物件的陣列
import java.lang.reflect.Field;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
- Field getField?(String name)回傳單個公共成員變數物件
- Field類中用于給成員變數賦值的方法
- void set?(Object obj, Object value):給obj物件的成員變數賦值為value
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Field field = c.getField("address");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
field.set(obj, "西安");//給obj的成員變數addressfield賦值
System.out.println(obj);
}
}
- Field getDeclaredField?(String name):回傳單個成員變數物件
- Field類中用于給成員變數賦值的方法
- void set?(Object obj, Object value):給obj物件的成員變數賦值為value
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Field field = c.getDeclaredField("address");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
field.set(obj,"西安");//給obj的成員變數addressfield賦值
System.out.println(obj);
}
}
練習1
用反射
- Student s = new Student()
- s.name = "張三"
- s.age = "18"
- s.address = "西安"
- System.out.println(s)
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
//* Student s = new Student()
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
// * s.name = "張三"
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"張三");
// * s.age = "18"
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj,18);
//* s.address = "西安"
Field addressField = c.getDeclaredField("address");
addressField.set(obj,"西安");
System.out.println(obj);
}
}
反射獲取成員方法并使用
獲取成員方法的方法
- Method[] getMethods?():回傳所有公共成員方法物件的陣列,包括繼承的
import java.lang.reflect.Method;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
- Method[] getDeclaredMethods?():回傳所有成員方法物件的陣列,不包括繼承的
import java.lang.reflect.Method;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
- Method getMethod?(String name, Class<?>... parameterTypes):回傳單個共有成員方法物件
- Method類中用于呼叫成員方法的方法
- Object invoke?(Object obj, Object... args):呼叫obj物件的成員方法,引數是args,回傳值是Object型別
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//獲取Class物件
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
//創建物件
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method m = c.getMethod("method1");
m.invoke(obj);
}
}
- Method getDeclaredMethod?(String name, Class<?>... parameterTypes):回傳單個成員方法
- Method類中用于呼叫成員方法的方法
- Object invoke?(Object obj, Object... args):呼叫obj物件的成員方法,引數是args,回傳值是Object型別
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//獲取Class物件
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
//創建物件
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method m = c.getDeclaredMethod("function");
m.setAccessible(true);
m.invoke(obj);
}
}
練習
- Student s = new Student();
- s.method1()
- s.method2("張三")
- String ss = s.method3("張三",20)
- System.out.print(ss)
- s.function()
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("反射.獲取Class物件的三種方式.Student");
//Student s = new Student();
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//s.method1()
Method m1 = c.getMethod("method1");
m1.invoke(obj);
System.out.println("--------------");
//s.method2("張三")
Method m2 = c.getMethod("method2", String.class);
m2.invoke(obj,"張三");
System.out.println("--------------");
//String ss = s.method3("張三",20)
Method m3 = c.getMethod("method3", String.class, int.class);
Object ss = m3.invoke(obj, "張三", 20);
//System.out.print(ss)
System.out.println(ss);
System.out.println("--------------");
//s.function()
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
}
反射練習
- 有一個ArrayList
集合,現在我想在這個集合中添加一個字串資料如何實作?
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> array = new ArrayList<Integer>();
Class<? extends ArrayList> c = array.getClass();
Method m = c.getDeclaredMethod("add", Object.class);
m.invoke(array, "hello");
m.invoke(array, "world");
m.setAccessible(true);
array.add(10);
System.out.println(array);
}
}
- 通過組態檔運行類中的方法
class.txt:
className = 反射.練習運行組態檔指定內容.Student
methodName = study
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class Demo {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//開始
// Student s = new Student();
// s.study();
//現在要改成
// Teacher t = new Teacher();
// t.teach();
//需要來回修改靈活性不高
/*
class.txt
className = xxx
methodName = xxx
*/
//加載資料
Properties prop = new Properties();
FileReader fr = new FileReader("反射\\class.txt");
prop.load(fr);
fr.close();
/*
className = 反射.練習運行組態檔指定內容.Student
methodName = study
*/
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class<?> c = Class.forName(className);
Object obj = c.getConstructor().newInstance();
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/162468.html
標籤:Java
上一篇:Java收徒,高級架構師關門弟子
