什么是反射,反射原理
java類的執行需要經歷以下過程
編譯:.java文件編譯后生成.class字節碼文件
加載:類加載器負責根據一個類的全限定名來讀取此類的二進制字節流到JVM內部,並存儲在運行時內存區的方法區,然后將其轉換為一個與目標類型對應的java.lang.Class對象實例
連接:細分三步
驗證:格式(class文件規范) 語義(final類是否有子類) 操作
准備:靜態變量賦初值和內存空間,final修飾的內存空間直接賦原值,此處不是用戶指定的初值。
解析:符號引用轉化為直接引用,分配地址
初始化:有父類先初始化父類,然后初始化自己;將static修飾代碼執行一遍,如果是靜態變量,則用用戶指定值覆蓋原有初值;如果是代碼塊,則執行一遍操作。
什么是反射:
Java的反射就是利用上面第二步加載到jvm中的.class文件來進行操作的。.class文件中包含java類的所有信息,當你不知道某個類具體信息時,可以使用反射獲取class,然后進行各種操作。
Java反射就是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;並且能改變它的屬性
要想解剖一個類,必須先要獲取到該類的字節碼文件對象(class)。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象.)
關於class對象和這個Class類
- Class對象的由來是將class文件讀入內存,並為之創建一個Class對象
Class類
class類 :代表一個類,是Java反射機制的起源和入口
用於獲取與類相關的各種信息, 提供了獲取類信息的相關方法
Class類繼承自Object類
Class類是所有類的共同的圖紙
每個類有自己的對象,同時每個類也看做是一個對象,有共同的圖紙Class,存放類的結構信息,能夠通過相應方法取出相應的信息:類的名字、屬性、方法、構造方法、父類和接口。
獲取class對象(反射入口)的三種方式
要想操作反射,必須先拿到反射的入口
1,通過通過Class.forName("全類名") 靜態方法來獲取,用的最多
Class c3 = Class.forName("reflect_fanshe.Person");
Class<?> perClazz = Class.forName("reflect_fanshe.Person");
2,類名.class
/2、類名.class 的方式得到,該方法最為安全可靠,程序性能更高
// 這說明任何一個類都有一個隱含的靜態成員變量 class
Class c2 = Person.class;
Class<?> perClazz2 = Person.class;
3,對象.getClass()
Person person = new Person(); Class<?> perClazz3 = person.getClass();
Class具有的部分方法如下:
getName():獲得類的完整名字。
getFields():獲得類的public類型的屬性。
getDeclaredFields():獲得類的所有屬性。包括private 聲明的和繼承類
getMethods():獲得類的public類型的方法。
getDeclaredMethods():獲得類的所有方法。包括private 聲明的和繼承類
getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name參數指定方法的名字,parameterTypes 參數指定方法的參數類型。
getConstructors():獲得類的public類型的構造方法。
getConstructor(Class[] parameterTypes):獲得類的特定構造方法,parameterTypes 參數指定構造方法的參數類型。
newInstance():通過類的不帶參數的構造方法創建這個類的一個對象。
通過反射獲取對象的實例,並操作對象
1,class.newInstance() ,並強轉類型,然后就可以操作對象了,主要是調用方法。
2,操作屬性,可以操作類里面的public屬性和private屬性 如果屬性是private,正常情況下是不允許外界操作屬性值,這里可以用Field類的setAccessible(true)方法,暫時打開操作的權限
反射方法的使用之---通過反射運行配置文件內容
student類:
public class Student { public void show(){ System.out.println("is show()"); } }
配置文件以txt文件為例子(pro.txt):
className = cn.fanshe.Student
methodName = show
測試類:
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.Properties; /* * 我們利用反射和配置文件,可以使:應用程序更新時,對源碼無需進行任何修改 * 我們只需要將新類發送給客戶端,並修改配置文件即可 */ public class Demo { public static void main(String[] args) throws Exception { //通過反射獲取Class對象 Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student" //2獲取show()方法 Method m = stuClass.getMethod(getValue("methodName"));//show //3.調用show()方法 m.invoke(stuClass.getConstructor().newInstance()); } //此方法接收一個key,在配置文件中獲取相應的value public static String getValue(String key) throws IOException{ Properties pro = new Properties();//獲取配置文件的對象 FileReader in = new FileReader("pro.txt");//獲取輸入流 pro.load(in);//將流加載到配置文件對象中 in.close(); return pro.getProperty(key);//返回根據key獲取的value值 } }
需求:
當我們升級這個系統時,不要Student類,而需要新寫一個Student2的類時,這時只需要更改pro.txt的文件內容就可以了。代碼就一點不用改動
新寫一個student2的類:
public class Student2 { public void show2(){ System.out.println("is show2()"); } }
配置文件更改為:
className = cn.fanshe.Student2
methodName = show2
控制台輸出:is show2()