RTTI與反射的區別和聯絡
為什麼會有反射?
假如你在程式執行過程中,從磁碟上或者從網路上讀取接收了一串代表一個類的位元組,既然這個類在你的程式被編譯很久之後才出現,那麼你怎樣使用這樣的類呢?
解決:Class類和java.lang.reflect類庫一起對反射的概念進行了支援。
下面講的Class類將不僅僅侷限在反射這個概念上:
Class類:
每個類和介面都有且僅有一個Class型別的物件,它由JVM自行建立,並且僅載入一次。每個類每個物件的建立都依賴於該類的Class型別物件。
如何獲得一個類的Class物件?分為兩種情況:
一:如果該類在編譯前就已知。也就是該類在classPath路徑下。這就是RTTI。
1)Class c = 類名.Class
2)Class c = Class.forName(String className)
二:如果該類編譯器未知,也就是在程式執行時才知道的。這就是反射
1)Class c = Class.forName(String arg[0])
java.lang.reflect類庫:
改類庫中的Field類提供獲取該不確定類中的欄位的api
Class<?> c = Class.forNmae(Stringarg[0]);
Field[] fields = c.getFields();
該類庫中的Method類提供獲取該不確定類中的方法的api
Method[] methods = c.get Methods()
該類庫中的Constructor類提供獲取該不確定類中的構造器的api
Constructor []constructor= c.getConstructors()
注:想了解更多實用api請自行search for jdk文件
我們現在再來想為什麼要有反射?
我們看我們遇到的問題是什麼?在編譯時編譯器不知道某個特定類的資訊,本質是編譯時無法獲得並開啟特定類的.class檔案,而是在程式執行起來時jvm才擁有該特定類的.class檔案。那麼,如何使用這樣的檔案呢?於是“反射”這個概念應運而生---提供在執行時操作.class檔案的統一API。
所以,我們要認識到反射機制並沒有什麼神奇之處。反射與RTTI的本質區別只是檢查一個類的.class檔案的時機不同:
反射:.class 檔案是在編譯時不可獲得的,所以在執行時開啟和檢查未知類的.class檔案從而變已知。
RTTI: .class 檔案是在編譯時開啟和檢查。
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, MalformedURLException {
//class.forName()
Class c1 = Class.forName("RTTI.model.PersonXYZ");
Method[] m = c1.getMethods();
for(int i=0;i<m.length;i++){
System.out.println(m[i].getName());
}
System.out.println(c1.getName());
Method ms = c1.getMethod("say",String.class);
ms.invoke(c1.newInstance(),"10");
//類字面常量
Class c2 = PersonXYZ.class;
PersonXYZ p2 = (PersonXYZ)c2.newInstance();
p2.say("12");
//載入外部的class
URLClassLoader classLoader = new URLClassLoader(new URL[] { new URL("file:F:\\") });
Class myClass = (Class)classLoader.loadClass("aa");
Method myt = myClass.getMethod("say");
myt.invoke(myClass.newInstance());
}