1.介紹
getClass()介紹
java是面向對象語言,即萬物皆對象,所有的對象都直接或間接繼承自Object類;
Object類中有getClass()方法,通過這個方法就可以獲得一個實例對象在內存中的實際類型。
類名.class介紹
通過對類名的引用取得在內存中該類型的實際類型。
Class.forName("包名xx.類名xx")介紹
通過"包名+類名"的方式同樣可以取得在內存中該類型的實際類型。
2.區別
第一,類的加載方式不同
Class.forName()屬於動態加載類,在代碼運行時加載指定類;
Class.class屬於靜態加載類,在代碼編譯時加載指定類;
object.getClass()取決於對象的產生方式:
既可以是靜態加載類(通過new創建的對象),也可以是動態加載類(通過Class.forName(xx.xx)創建的對象,對象可能不存在)。
Class.forName("bbb").newInstance().getClass();
第二,Class對象的創建方式不同
Class.forName()
運行階段:JVM使用類裝載器, 將類裝入內存中,並對類進行初始化(靜態代碼塊、非靜態代碼塊、構造函數調用及靜態變量);
最后返回Class的對象。
類名.class
編譯階段:JVM使用類裝載器, 將類裝入內存中,並對類進行初始化操作;
最后返回Class的對象。
實例對象.getClass()
當調用getClass()方法時,該對象的類已經被加載到內存中並且完成了初始化操作;
直接返回Class的對象,沒有其它操作。
第三,對象與類的關系不同
通過類創建對象:
Class.forName(xxx.xx.xx)和Class.class返回的是一個類,調用newInstance()后才創建一個對象;
// 獲取類 Class<String> c = String.class; // 通過類創建對象 String s = c.newInstance();
通過對象獲取類:
object.getClass();
// 獲取類 Class<String> c = String.class; // 通過類創建對象 String s = c.newInstance(); // 通過對象獲取類 Class<? extends String> c2 = s.getClass();
3.測試
公用代碼
/** * class類加載 * @explain * @author Marydon * @creationTime 2018年10月19日上午9:26:29 * @version 1.0 * @since * @email marydon20170307@163.com */ public class ClassLoader2 { /** * 構造函數 * @explain 在類每次被實例化時執行 */ public ClassLoader2() { System.out.println("--------調用構造函數--------"); } /** * 靜態的參數初始化 * @explain 在類初次被加載到內存中時執行 */ static { System.out.println("--------執行靜態代碼塊--------"); } /** * 非靜態的參數初始化 * @explain 在類每次被實例化時執行 */ { System.out.println("--------執行非靜態代碼塊--------"); } }
/** * class類加載測試 * @explain * @author Marydon * @creationTime 2018年10月19日下午3:44:32 * @version 1.0 * @since * @email marydon20170307@163.com */ public class TestClassLoader2 { static { System.out.println("執行TestClassLoader2.class初始化操作!"); } public static void main(String[] args) throws ClassNotFoundException{ } }
測試:類.class
// 測試1:類.class Class<ClassLoader2> c = ClassLoader2.class; System.out.println(c);
測試結果:ClassLoader2.class在編譯時已經加載到了內存中。
判斷依據:靜態代碼塊並沒有執行!
測試:objet.getClass()
方式一:使用靜態加載類創建對象
Object cl2 = new ClassLoader2(); System.out.println(cl2.getClass());
測試結果:
方式二:使用動態加載類創建對象
System.out.println(Class.forName("test.ClassLoader2").newInstance().getClass());
說明:
無論是在通過動態加載類還是靜態加載類創建的ClassLoader2類的對象時,ClassLoader2類都會被重新加載到內存當中,
所以當調用.getClass()方法時,並不會執行任何類的初始化操作。
測試:Class.forName("包名.類名")
public static void main(String[] args) throws ClassNotFoundException { // 測試3:Class.forName() Class<?> c3 = Class.forName("test.ClassLoader2"); System.out.println(c3); }
測試結果:ClassLoader2.class在運行時被加載到內存中。
判斷依據:靜態代碼塊執行!
類比較(判斷是否時同一class類型)
在上面的main方法中添加
System.out.println("--------類比較--------"); System.out.println(c.equals(cl2.getClass())); System.out.println(c.equals(c3));
測試結果:
證實:非靜態代碼塊與構造函數,每次實例化都會被執行。(與文章主題無關)
在上面的main方法中添加
System.out.println("第二次實例化ClassLoader2"); ClassLoader2 cl3 = new ClassLoader2();
測試結果:
寫在最后
哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!