反射的基礎: 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變量