RTTI的初期想法非常簡單:當有一個指向基礎型別base type的reference時,RTTI機制讓你的一找出其所指的確切型別,不過當拓展到java.lang.reflection的時候,展現了全新的功能.即現在的java中存在兩種形式的rtti:傳統的rtti;reflection機制
為什麼要使用rtti?上面的目的就是原因,比如向下轉型downcasting/強制轉型.
Class類對象以及他的裝載時機。
如何取得某個類/對象的Class對象?
1.Class.forName("Gum");//可能導致執行期異常,比如說找不到Gum類,可以用於編譯時間還未形成的類
2.Gum.class;//這種方式要求編譯時間就裝載Gum類,所以可以執行編譯檢查,一般不會出現找不到Gum類的情況,而且因為不是函數,效能得到最佳化.
我們明確知道Circle也是一個Shape,所以編譯器能夠自動上溯造型,但卻不能保證一個Shape肯定是一個Circle.因此,編譯器不允許自動下溯造型,除非明確指定一次這樣的造型.
轉型之前最好執行類型檢查:(避免執行期異常ClassCastException)
1.傳統轉型:.instanceof if(x instanceof Dog) //這種運算子是使用老式關鍵字,他要求x必須為ref,所以不能用基本類型變數名,而後面的Dog也必須是Class,所以還是不能用基本類型.同時有個缺點就是Dog本身必須是Class名,根本不能用某種變數替換,相比於下面的方法缺少靈活性.
2.操作Class對象:Class.isInstance(obj)//比如Class c=Dog.class;if(c.isInstance(x))....obj也要求是object,輸入基本類型系統會用基本類別wrap之,然後再判斷,注意用基本類型來判斷如int.class.isInstance(x)肯定會返回false,實在想不出你為啥要判斷一個變數是否為基本類型...
Java運用Class對象來執行其RTTI機制——即使你所作的只是轉型動作。
Class類型裡面的幾個有用的函數
getInterfaces() :Class[] //返回一系列介面的class對象。
newInstance() :Object //虛擬建構函式:我不知道你具體是什麼東西,不過你給我適當的產生一個.若從表面看,Class的newInstance()方法似乎是複製(clone())一個對象的另一種手段。但兩者是有區別的。利用newInstance(),我們可在沒有現成對象供“複製”的情況下建立一個對象。就象上面的程式示範的那樣,當時沒有Toy對象,只有cy——即y的Class對象的一個控制代碼。利用它可以實現“虛擬構建器”。換言之,我們表達:“儘管我不知道你的準確類型是什麼,但請你無論如何都正確地建立自己。”
static Class.forName("Gum"):Class
isInterface():bool //判斷某個Class對象是否為interface.
getName():string //得到Class對象所屬的類型的名字。
getSuperclass()
總之,有了某個類的Class對象,他的祖宗十八代都可以查出來。
事實上。RTTI和多態上有重複的功能,先嘗試使用多態,最後才使用RTTI,記住,不要濫用RTTI.
Reflection機制也是通過Class類對象來實現的.
個人感覺他只不過是通過Class類對象暴露了一組共用的借口.我們可以查詢並調用之,而並不用知道某個特定類的全部資訊.事實上他並沒有什麼特別的神奇之處,總感覺有點似曾相識,有點像COM中提供的IUNKNOWN介面,或者IDL語言的作用?
採用傳統RTTI:編譯器在編譯器即開啟並檢查.class檔案,但如果採用Reflection機制,編譯器並不會取用.class檔案.它會由執行期環境加以開啟和檢查.由此我們可以看出reflection的使用場合:JavaBeans,RMI,object serialization.或者無法得知某.class檔案提供的介面時.基本上我們編成的過程中不會直接用到Reflection.
即reflection的意思是我們用Class.forName()尋找的class資訊編譯期間完全不可得,但是在啟動並執行時候可以得到,我們一樣可以查他的祖宗十八代。可以在運行時做任何編譯是想做的事,比如我可以Class.forName()載入執行期才可見的某class,然後可以用class.newInstance(Constructor)來調用該類的某個建構函式構造一個對象,然後用method.invoke(args)來調用這個對象的某個方法。注意reflection機制拓展了Class類來支援更強的非基本rtti功能。
傳統RTTI和“反射”之間唯一的區別就是對RTTI來說,編譯器會在編譯期開啟和檢查.class檔案。換句話說,我們可以用“普通”方式調用一個對象的所有方法;但對“反射”來說,.class檔案在編譯期間是不可使用的,而是由運行期環境開啟和檢查。
想象一下javabean的實現吧,但是RMI,object serialization裡如何應用reflection倒是需要仔細研究。
查一下java.lang.reflection包,發現包含以下內容:
介面 Member
類 Array
Constructor
Field
Method
Modifier
異常 InvocationTargetException