java反射的理解
初學者可能會想反射是什么,有什么作用。那我就以一個簡單的小需求開始?,F在有3個類,A,B,C. 現在我想要一個方法,根據輸入的字符串,獲取相應的實例對象,即當我給這個對象傳入“A”的時候,我要獲取一個A實例,傳入“B”的時候獲取一個B實例,有人說用if, 那么如果有1000個類,就用1000個if或者case么,而且,如果不事先知道有多少種情況呢?要解決這個問題,我們先從基礎知識開始學習。
在Java程序執行的時候,在這個進程中,內存分為代碼區,靜態存儲區,堆內存和棧內存。一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個變量時,java就在棧中為這個變量分配內存空間,當超過變量的作用域后,java會自動釋放掉為該變量分配的內存空間,該內存空間可以立刻被另作他用。堆內存用于存放由new創建的對象和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。靜態存儲區,主要是用來存儲字符串和類的靜態成員變量等。現在說到了對于反射來講很重要的一塊內存,代碼區(CodeSegment)。代碼區主要存放的是加載到內存的二進制文件。注意,這不是對象實例,而是那些一個個還沒有被喚醒的.class文件。
從面相對象的角度來講,這些文件都是一類,都是Class類。至于如何理解.class文件對象和實例對象,我是這樣理解的。在代碼區的.class對象就像是下載視頻的種子,雖然它并不是一個實實在在的視頻,但是必須要通過這個種子才能獲得視頻文件,而且一個種子可以使用多次。相對應的,在程序中.class文件對象,要通過這個對象來獲取需要的對象,而且能多次使用。
在Java虛擬機中,有一個很重要的搬運工的角色,就是ClassLoader,這是一大類Class,它們的作用就是把相應的用到的二進制的Class文件加載到內存中。注意,這里有一個動態的加載機制,不是說,在程序啟動的時候,如果ClassPath下有100個.class文件,就會把所有的二進制碼一下子加載到內存中,而是剛剛開始的時候JVM使用ClassLoader把最初的幾個.class二進制碼Load到內存中,之后的是用到的時候才加載,慢慢的會有更多的加載到存中。當然也可以通過代碼顯示的要求立即把相應的二進制類代碼加載到內存,如JDBC驅動的加載 Class.forName("com.mysql.jdbc.Driver")
在這里有一個相關的知識點就是static靜態語句塊的問題。有人說,靜態語句塊是第一次new對象的時候執行,這種說法是不準確的,確切的說,是加載到內存中的時候執行。一般來講我們自己寫的類,是用的時候才加載到內存,而我們用的方式,一般都是new一個對象,一般不會強制顯示的去加載,所以,大家就以為是第一次實例化的時候執行。如果我們使用Class.Forname顯示的把它load到內存,而并不new對象,可以發現,此時靜態代碼塊也執行了。
現在解決最初提出的那個問題,只需要一句代碼
String type = “A”;
Object o = Class.forName(type).newInstance();
下面是有關反射使用的一些常用的方法,包括獲取成員方法等。從面相對象的角度看,類中的一個個屬性或者方法都是對象,要讓其執行,調用invoke就可以了。