1. 程式人生 > >RTTI與反射的區別和聯絡

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());
        
        
        
    }