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()獲得構造函數等,這為後續的反射代碼鋪平了道路。