java 類名.class、object.getClass()和Class.forName()的區別 精析


 

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("--------執行非靜態代碼塊--------");
	}

}
  注意:
   類名一定不能是ClassLoader.java,因為已經存在java.lang.ClassLoader了,如果還命名為ClassLoder,會影響測試結果;
  起初自己發現了新大陸,原來是個坑,空歡喜一場!
/**
 * 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();

  測試結果:  

 

寫在最后

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM