Java代碼在計算機中經歷的三個階段
1.源代碼階段
.java源碼文件 ---》.class字節碼文件
2.Class類對象階段
類加載器 ---》Class類對象(反射機制)
(Class類對象包括,成員變量Field[] fields + 構造方法Constructor[] constructors + 成員方法Method[] methods)
3.運行時階段
Class類對象,創建對象
反射:將類的各個組成部分封裝爲其他對象,這就是反射機制。
反射的好處:1.可以在程序的運行過程中,操作這些對象
2.可以解耦,提高程序的可擴展性
獲取Class對象的方式:
1.源代碼階段
Class.forName("全類名"):將字節碼文件加載進內存,返回Class類對象
* 多用於配置文件,將類名定義在配置文件中。讀取配置文件,加載類。
2.Class類對象階段
類名.class:通過類名的屬性class來獲取
* 多用於方法的參數的傳遞。
3.運行時階段
對象.getClass():此方法在Object類中定義。
* 多用於對象的獲取字節碼的方式。
//1.
Class cls1= Class.forName("useless.Person");
System.out.println(cls1);
//2.
Class cls2= Person.class;
System.out.println(cls2);
//3.
Person p=new Person();
Class cls3=p.getClass();
System.out.println(cls3);
注:同一個字節碼文件(*.class)在一次程序運行過程中,只會被加載一次,不論通過哪一種方式獲取的Class對象都是同一個。
Class對象的使用
獲取功能:1.獲取成員變量們,getxxx()...getDeclaredFields()能獲取private修飾的變量
2.獲取構造方法們,
3.獲取成員方法們,
4.獲取類名
利用反射獲取成員變量
設置和獲取public,protected修飾的成員變量
Class personClass=Person.class;//獲取Class類對象
Person p=new Person();
Field field = personClass.getField("name");//獲取成員變量
field.set(p,"chenkai");//爲一個對象的成員變量設置值
System.out.println(field.get(p));//獲取一個對象的成員變量的值
設置和獲取private修飾的成員變量
Field ageField = personClass.getDeclaredField("age");
ageField.setAccessible(true);//忽略安全檢查,開啓暴力反射,訪問private變量
ageField.set(p, 10);
System.out.println(ageField.get(p));
利用反射獲取構造方法
利用獲取的構造方法生成新實例
Class personClass=Person.class;
Constructor constructor=personClass.getConstructor(String.class,int.class);
Object person=constructor.newInstance("lilili",29);
利用空構造函數生成新實例的另一種方法
Object person1=Person.class.newInstance();
利用反射獲取方法
獲取和執行方法
Class personClass=Person.class;
Person person=new Person("ck",18);
Method setAge=personClass.getMethod("setAge",int.class);//獲取有參方法
Method getAge=personClass.getMethod("getAge");//獲取無參方法
setAge.invoke(person,99);//執行有參方法
System.out.println(getAge.invoke(person));//執行無參方法
注:
personClass.getMethods();//此方法也會獲取其父類的public方法
反射的應用
需求:一個簡化框架,不改變該框架類的代碼,並能創建任意對象,執行任意方法。
實現需要:配置文件,反射
步驟:
1.將要創建的對象的全類名和需要執行的方法定義在配置文件中
2.在程序中加載讀取配置文件
3.使用反射技術來加載類文件進內存
4.創建方法
5.執行方法
代碼:
//1.加載配置文件
Properties pro=new Properties();//創建對象
ClassLoader classLoader=ReflectTest.class.getClassLoader();//獲取類加載器
InputStream is=classLoader.getResourceAsStream("useless/pro.properties");//通過類加載器獲取配置文件
pro.load(is);
//2.獲取配置文件中的數據
String className=pro.getProperty("className");
String methodName=pro.getProperty("methodName");
//3.加載該類進內存
Class myClass=Class.forName(className);
//4.創建對象,執行方法
Object obj=myClass.newInstance();
Method method=myClass.getMethod(methodName);
method.invoke(obj);
配置文件:
className=useless.Student
methodName=sleep
優點:
改配置文件更方便,不會影響已有代碼,擴展性也更強。