Java反射——java.lang.Class和類的加載


反射的基礎: java.lang.Class

Class類的實例對象,用於記錄類描述信息。
源碼說:represent classes and interfaces in a running Java application

Class類沒有公共的構造方法,無法通過new運算符實例化;只能通過對象的getClass方法,或是通過Class.forName(…)來獲得實例。

static ClassforName(String className)throws ClassNotFoundException 使用參數className來指定具體的類,來獲得相關的類描述對象,該方法有可能拋出類加載異常(ClassNotFoundException),必須捕捉
Class getSuperclass() 獲得當前類描述對象的父類的描述對象
String getName() 返回當前類描述對象的類名稱

獲取Class對象的三種方式:

public class _T11獲取Class {
	// Class:類描述對象
	// (源碼說:represent classes and interfaces in a running Java application)
	public static void main(String[] args) {
		Class<?> _class;
		// ***1*對象.getClass()
		String str = "";
		_class = str.getClass();
		System.out.println(_class + "-----對象名.getClass()");
		// ***2*類.class
		_class = String.class;
		System.out.println(_class + "-----類名.class");
		// ***3*Class.forName("")
		try {
			_class = Class.forName("java.lang.String");
			System.out.println(_class + "-----Class.forName(...)");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}

class java.lang.String-----對象名.getClass()
class java.lang.String-----類名.class
class java.lang.String-----Class.forName(...)

.getSuperclass()

_class.getSuperclass():獲得父類的描述對象

以下示例,打印StringBuffer的父類、父類的父類……

public class _T12getSuperclass {
	public static void main(String[] args) {
		System.out.println("-----.getSuperclass()獲得父類的描述對象-----");
		try {
			Class _class = Class.forName("java.lang.StringBuffer");
			// 循環打印父類信息,直到沒有父類
			while (_class != null) {
				System.out.println(_class);
				// getSuperclass():獲得父類的描述對象
				_class = _class.getSuperclass();
			}
		} catch (ClassNotFoundException cnfe) {
			cnfe.printStackTrace();
		}
	}
}

-----.getSuperclass()獲得父類的描述對象-----
class java.lang.StringBuffer
class java.lang.AbstractStringBuilder
class java.lang.Object

類的加載

Java程序運行在Java虛擬機進程中,同一個JVM的所有線程、所有變量都處於同一個進程里。
當系統出現以下幾種情況時,JVM進程將被終止:
|--程序正常結束。
|--程序運行到System.exit()或Runtime.getRuntime().exit()代碼。
|--程序執行過程中遇到未捕獲的異常或錯誤。
|--強制結束JVM進程。

類加載,是指將類的.class文件讀入內存,並為之創建一個java.lang.Class對象。

class Tester {
	static {
		System.out.println("靜態初始化塊...");
	}
	public Tester() {
		System.out.println("構造方法...");
	}
}
public class _T21TestClassLoader {
	public static void main(String[] args) throws ClassNotFoundException {
		ClassLoader _cLoader = ClassLoader.getSystemClassLoader();
		System.out.println("=====loadClass():加載類,但不做初始化=====");
		String _包類名 = "Tester";
		Class<?> loadClass = _cLoader.loadClass(_包類名);
		System.out.println("加載即得Class:" + loadClass);
		// -----------------------------------------------------
		System.out.println("=====Class.forName():初始化(靜態代碼塊執行)=====");
		Class.forName(_包類名);
	}
}

=loadClass():加載類,但不做初始化=
加載即得Class:class Tester
=Class.forName():初始化=
靜態初始化塊...

static變量的初始化

使用static final的變量(常量),如果值可以在編譯期確定,則類不需要初始化。

// static final修飾的變量,被用於“常量”,更類似於“宏定義”。
// 當其在編譯器能確定時,不需要初始化類,使用“宏變量”替換的形式進行編譯;
// 當其不能在編譯期確定時,需要初始化類;
// 如果未加final,不是“宏定義”,需要初始化類。
class StaticField {
	static {
		System.out.println("---此代碼不執行---");
	}
	static final String compileConstant = "static final變量,編譯時能確定,類不做初始化,使用'宏替換'的形式編譯";
}
class StaticField2 {
	static {
		System.out.println("【2:此代碼執行,表示初始化過了】");
	}
	static final String compileConstant = "static final變量,編譯時不能確定時,運行時才確定。"
			+ System.getProperty("os.name");
}
class StaticField3 {
	static {
		System.out.println("【3:此代碼執行,因為就不是final】static{}變量不是final,編譯時能確定,變量");
	}
	static String compileConstant = "非final的static變量";
}
public class _T22宏定義常量 {
	public static void main(String[] args) {
		System.out.println("\t" + StaticField.compileConstant);
		System.out.println("\t" + StaticField2.compileConstant);
		System.out.println("\t" + StaticField3.compileConstant);
	}
}

運行結果:

	static final變量,編譯時能確定,類不做初始化,使用'宏替換'的形式編譯
【2:此代碼執行,表示初始化過了】
	static final變量,編譯時不能確定時,運行時才確定。Windows 10
【3:此代碼執行,因為就不是final】static{}變量不是final,編譯時能確定,變量
	非final的static變量


免責聲明!

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



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