咱們都知道Java的反射機制中有三種獲取類對象的方式,那麼這幾種方式的區別究竟是什麼呢?
一、new Object().getClass 二、Object.class 三、Class.forName("java.util.String")
由於類對象與類的加載息息相關,因此爲了展現區別,咱們先加入動態的和靜態的代碼塊。
public class CalBean { static { System.out.println("靜態的代碼塊。"); } { System.out.println("動態的代碼塊。"); } public CalBean() { System.out.println("構造方法"); } private Integer num1; private Integer num2; public Integer getNum1() { return num1; } public void setNum1(Integer num1) { this.num1 = num1; } public Integer getNum2() { return num2; } public void setNum2(Integer num2) { this.num2 = num2; } }
建立一個測試單元:java
@SuppressWarnings("unused") @org.junit.Test public void test() { Class<CalBean> cla1 = CalBean.class; System.out.println("==================================="); try { Class<?> cla2 =Class.forName("com.zking.entity.CalBean"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("==================================="); Class<? extends CalBean> cla3 = new CalBean().getClass(); }
控制檯結果:數據結構
結果能夠看到,類名.class的方式並未執行該類的代碼塊或者是代碼。
而forName的方式執行了該類的靜態代碼塊。
實例對象.getClass()的方式打印全部內容的緣由顯而易見,由於要先實例化。測試
咱們將.class方式與實例對象.getClass()組合測試:this
@SuppressWarnings("unused") @org.junit.Test public void test() { Class<CalBean> cla1 = CalBean.class; System.out.println("==================================="); Class<? extends CalBean> cla3 = new CalBean().getClass(); }
控制檯結果:spa
能夠看到.class方式仍然沒有輸出,實例對象.getClass()方式將全部的內容打印。code
這裏,咱們測試一下三種方式獲取到的類對象是否相等:對象
@SuppressWarnings("unused") @org.junit.Test public void test() { try { Class<CalBean> cla1 = CalBean.class; System.out.println("==================================="); Class<?> cla2 =Class.forName("com.zking.entity.CalBean"); System.out.println("==================================="); Class<? extends CalBean> cla3 = new CalBean().getClass(); System.out.println(cla1 == cla2); System.out.println(cla2 == cla3); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
等於號判斷引用地址:blog
三種方式獲取到的是同一個對象,爲何呢?
這就涉及到類的加載過程,咱們知道類加載過程分:加載階段、鏈接階段和初始化階段。
類的加載階段是將class文件中的二進制數據讀取到內存中,而後將該字節流所表明的靜態存儲結構轉化爲方法區中運行時的數據結構,而且在堆內存中生成一個該類的java.lang.class對象,做爲方法區數據結構的入口。
類加載階段的最終產物是堆內存中的class對象,對於同一個Classloader對象,無論某個類被加載多少次,對應堆內存中的class對象始終只有一個。
也就是說不管經過哪一種形式來獲取Class對象,得到的都是堆內存中對應的Class對象。