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();
測試結果:

寫在最后
哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!
