理解java.lang.Class類
Java Class類理解:
首先,Class是一個java類,跟Java API中定義的諸如Thread、Integer類、我們自己定義的類是一樣,也繼承了Object(Class是Object的直接子類)。總之,必須明確一點,它其實只是個類,只不過名字比較特殊。更進一步說,Class是一個java中的泛型型別。
對於我們自己定義的類,我們用類來抽象現實中的某些事物,比如我們定義一個名稱為Car的類來抽象現實生活中的車,然後可以例項化這個類,用這些例項來表示我的車、你的車、黃的車、紅的車等等。
好了,現在回到Class 類上來,這個類它抽象什麼了?它的例項又表示什麼呢?
在一個執行的程式中,會有許多類和介面存在。我們就用Class這個來來表示對這些類和介面的抽象,而Class類的每個例項則代表執行中的一個類。例如,執行的程式有A、B、C三個類,那麼Class類就是對A、B、C三個類的抽象。所謂抽象,就是提取這些類的一些共同特徵,比如說這些類都有類名,都有對應的hashcode,還有其他一些後設資料。
需要注意的是,這個特殊的Class類沒有公開的建構函式,那怎麼獲取Class類的例項呢?有幾個途徑。
1. 當Java虛擬機器載入一個類的時候,它就會自動建立一個Class類的例項來表示這個類。例如,虛擬機器載入Car這個來的時候,它就會建立一個Class類的例項。然後可以通過以下方法獲得這個Class物件:
java.lang.ClassclassObj = ClassName.class;
2. 可以通過呼叫類載入器(ClassLoader)的defineClass()方法來得到一個例項。這個方法接受一個byte陣列,載入這個byte陣列否成的class類,同時例項化一個Class物件。
3. ClassName.class( ) ClassName.getClass( )
現在來分析一下Class類的原始碼(java.lang.Class):
public final
class Class<T> implementsjava.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {…
ClassClass<T>,前一個Class表示這是一個類的宣告,第二個Class是類的名稱,<T>表示這是一個泛型類,帶有引數T.同時,Class類實現了許多介面。
緊接著定義了幾個靜態變數:
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
接著定義一個本地方法registerNatives(),並在靜態塊中呼叫:
private static native void registerNatives();
static {
registerNatives();
}
私有的建構函式:
private Class() {}
訪問修飾符是private,程式設計師是無法直接呼叫這個建構函式,只能通過JVM來呼叫它,構造一個Class例項。
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class"))
+ getName();
}
這是Class物件例項的字串表示方法,應該不陌生。那麼,它返回什麼東西呢?
>如果這個Class物件例項所表示的是一個Java類,則返回class full_classname.
例如java.lang.Math.java這個類,它所對應的Class例項的toString方法返回的就是class java.lang.Math
>如果是介面,將class改成interface。還有一種特殊情況,如果Class例項表示的是void型別,則發揮void。如果是基本型別,一樣的返回基本型別的名稱。
靜態方法forName:
public static Class<?> forName(String className)
throws ClassNotFoundException{
return forName0(className,true, ClassLoader.getCallerClassLoader());
}
根據給定的類名引數className,查詢與className相對應的Class例項,然後載入、連線該例項物件,之後返回這個Class例項。其中例如以下程式碼段將輸出:
class java.lang.Thread
public class ClassTest {
/**
* @param args
*/
public static void main(String[] args) {
try {
System.out.println( Class.forName("java.lang.Thread") );
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("No ClassNamed java.lang.Thread");
}
}
}
forName方法過載:
public static Class<?> forName(String name, boolean initialize,
ClassLoaderloader)
throws ClassNotFoundException
{
if (loader == null) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader ccl = ClassLoader.getCallerClassLoader();
if (ccl != null) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize,loader);
}
注意到這個forName過載方法中多了兩個方法引數,其中initialize這個boolean型別指定是否要初始化對應的Class例項,loader指定載入Class例項的載入器。留意這個方法可能丟擲的異常還是比較多的,比如連線失敗、找不到對應的類等等。
forName0本地方法:
private static native Class<?> forName0(String name, boolean initialize,
ClassLoaderloader)
throws ClassNotFoundException;
這是一個本地方法,在前面的靜態方法forName的兩個版本中都呼叫了這個本地方法。
newInstance()方法:
public T newInstance() // T是個泛型引數,是Class例項所表示的Java類
throws InstantiationException,IllegalAccessException
{
if (System.getSecurityManager()!= null) {
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
}
return newInstance0(); //這是一個本地方法,也在Class類中定義
}
注意這是一個例項方法,必須由Class類的例項物件呼叫。例如,有一個代表java.lang.Thread類的Class例項物件objec1,也就是說,泛型引數T此時就是Thread,object1這個例項代表Thread這個類。好了,現在呼叫object1的newInstance方法,即object1.newInstance(),此時這個呼叫將返回一個Thread類的物件。簡單驗證:
public class ForName {
/**
* @param args
* @throwsIllegalAccessException
* @throwsInstantiationException
*/
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class<?> c = null ;
try {
c = Class.forName("java.lang.Thread");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Thread thread = (Thread) c.newInstance(); //型別轉化一下
System.out.println(thread.getId());
}
}
在我機子中,上述程式碼輸出 8 。即c.newInstance產生一個ID為8的新執行緒。
getClassLoader:
public ClassLoader getClassLoader() {
ClassLoader cl = getClassLoader0();
if (cl == null)
return null; // Bootstrap
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader ccl = ClassLoader.getCallerClassLoader();
if (ccl != null && ccl != cl&& !cl.isAncestor(ccl)) {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
return cl;
}
//Package-private to allow ClassLoader access
native ClassLoadergetClassLoader0(); // 本地方法
這個方法返回該Class物件代表的類的類載入器。如果類的載入器是Bootstrap,則返回null。下面的程式碼輸出:The ClassLoader of Thread Class is Bootstrap
Class<?> classObj= Thread.class;
ClassLoader loader = classObj.getClassLoader();
if (loader == null) {
System.out.println("TheClassLoader of Thread Class is Bootstrap");
} else {
System.out.println(loader);
}
獲取父類方法:getSuperclass()
public native Class<? super T> getSuperclass();
這是一個本地方法,這裡的邏輯有點饒,方法返回的是這個Class物件所代表的Java類的父類對應的的Class 物件。
例如: Thread.class.getSuperclass()將返回一個代表Thread類的Class物件,Thread.class.getSuperclass().toString()則輸出這個Class物件的字串表示:classjava.lang.Object。其實這裡的關係無非就是說Thread的超類是Object。只是饒了Class物件這個彎子,至於這麼繞有什麼好處,還沒有深刻體會。
(持續更新中)
相關文章
- Java中的java.lang.Class API 詳解JavaAPI
- Loader類理解
- 類管理解析
- 匿名內部類理解
- java內部類的理解Java
- 深入理解CSS偽類CSS
- 深入理解java巢狀類和內部類、匿名類Java巢狀
- Java的抽象類與介面理解Java抽象
- Java類載入原理解析Java
- 理解Python中的元類Python
- Java學習之Math類理解Java
- Java學習之File類理解Java
- 理解Javascript中類的定義JavaScript
- RoleAssigner類的理解疑惑
- Python 類屬性的理解Python
- OOP: 理解類和物件(1) (轉)OOP物件
- OOP: 理解類和物件(2) (轉)OOP物件
- INDEX JAVA 各類名詞理解 & 知識點理解 目錄IndexJava
- 理解Java中物件基礎Object類Java物件Object
- 深入理解JVM類載入器JVM
- 深入理解JVM類檔案格式JVM
- 深入理解JVM之類載入JVM
- Java類載入器深入理解Java
- 理解類引用這種型別 (轉)型別
- 如何理解Python3中的子類和父類?Python
- java中多型的理解——父類引用指向子類物件Java多型物件
- python 類和元類(metaclass)的理解和簡單運用Python
- 深入理解OSGi類載入機制
- java介面和抽象類的簡單理解Java抽象
- 關於抽象類和介面的初步理解抽象
- 深入理解JavaScript中的類繼承JavaScript繼承
- 2.1.5 Python元類深刻理解(metaclass)Python
- 理解JVM(四):JVM類載入機制JVM
- 深入理解JVM類載入機制JVM
- AI 能理解人類的情緒嗎?AI
- 我如何理解Java中抽象類和介面Java抽象
- 深入理解Java的介面和抽象類Java抽象
- 對於Objective-C新建類的理解Object