讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議101:注意Class類的特殊性 >

建議101:注意Class類的特殊性

Java語言是先把Java源文件編譯成後綴為class的字節碼文件,然後再通過ClassLoader機制把這些類文件加載到內存中,最後生成實例執行的,這是Java處理的基本機制,但是加載到內存中的數據是如何描述一個類的呢?比如在Dog.class文件中定義的是一個Dog類,那它在內存中是如何展現的呢?

Java使用一個元類(MetaClass)來描述加載到內存中的類數據,這就是Class類,它是一個描述類的類對象,比如Dog.class文件加載到內存中後就會一個Class的實例對像描述之。因為Class類是「類中類」,也就有預示著它有很多特殊的地方:

無構造函數。Java中的類一般都有構造函數,用於創建實例對象,但是Class類卻沒有構造函數,不能實例化,Class對象是在加載類時由Java虛擬機通過調用類加載器中的defineClass方法自動構造的。

可以描述基本類型。雖然8個基本類型在JVM中並不是一個對象,它們一般存在於棧內存中,但是Class類仍然可以描述它們,例如可以使用int.class表示int類型的類對象。

其對象都是單例模式。一個Class的實例對像描述一個類,並且只描述一個類,反過來也成立,一個類只有一個Class實例對象,如下代碼返回的結果都為true:


//類的屬性class所引用的對象與實例對象的getClass返回值相同

String.class.equals(new String().getClass())

"ABC".getClass().equals(String.class)

//class實例對像不區分泛型

ArrayList.class.equals(new ArrayList<String>().getClass()))


Class類是Java的反射入口,只有在獲得了一個類的描述對像後才能動態地加載、調用,一般獲得一個Class對像有三種途徑:

類屬性方式,如String.class。

對象的getClass方法,如new String().getClass()。

forName方法加載,如Class.forName("java.lang.String")。

獲得了Class對像後,就可以通過getAnnotations()獲得註解,通過getMethods()獲得方法,通過getConstructors()獲得構造函數等,這為後續的反射代碼鋪平了道路。