一.Java語言是先把Java源文件編譯成後綴爲class的字節碼文件,而後再經過ClassLoader機制把這些類文件加載到內存中,最後生成實例執行的,這是Java處理的基本機制,可是加載到內存中的數據的如何描述一個類的呢?好比在Dog.class文件中定義一個Dog類,那它在內存中是如何展示的呢?java
Java使用一個元類(MetaClass)來描述加載到內存中的類數據,這就是Class類,它是一個描述類的類對象,好比Dog.class文件加載到內存中後就會有一個class的實例對象描述之。由於是Class類是「類中類」,也就有預示着它有不少特殊的地方:編程
1. 無構造函數:Java中的類通常都有構造函數,用於建立實例對象,可是Class類卻沒有公共的構造方法,不能實例化,Class對象是在加載類時由Java虛擬機經過調用類加載器中的difineClass方法自動構造的,所以不能顯示的聲明一個class對象。框架
2. 基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也都對應一個 Class 對象,雖然8個基本類型在JVM中並非一個對象,它們通常存在於棧內存中,可是Class類仍然能夠描述它們,例如可使用int.class表示int類型的類對象。函數
虛擬機爲每種類型管理一個獨一無二的Class對象。也就是說,每一個類(型)都有一個Class對象。運行程序時,Java虛擬機(JVM)首先檢查是否所要加載的類對應的Class對象是否已經加載。若是沒有加載,JVM就會根據類名查找.class文件,並將其Class對象載入。其對象都是單例模式:一個Class的實例對象描述一個類,而且只描述一個類,反過來也成立。一個類只有一個Class實例對象,以下代碼返回的結果都爲true: 對象
下面咱們用java來看一看java語言自己是怎麼描述這個問題的。內存
public class Test {字符串
public static void main(String[] args) {get
People xiaoming = new People();原型
System.out.println(xiaoming.getClass());//小明這個對象爲People類的一個對象虛擬機
System.out.println(xiaoming.getClass().getClass());//People這個對象爲Class元類的一個對象
System.out.println(xiaoming.getClass().getClass().getClass());//Class這個對象爲Class元類的一個對象
}
}
class pyf.java.test.People
class java.lang.Class
class java.lang.Class
二.怎麼獲取類的元類型
那麼java中怎麼獲取一個類的元類呢?大概有下面這麼幾種方法:
1)類型.class (類屬性方式)
這種方式很直接,引用類型可使用該方式來獲取元類,基本類型也能經過該方式獲取元類
Class c1 = int.class;
Class c2 = InputStream.class;
2)實例.getClass()
這種方式是經過一個實例調用基類Object的方法
Person xiaoming = new Person();
Class<Person> cls = xiaoming.getClass();
Object的getClass方法原型以下:
public final native Class<?> getClass();
3)Class.forName(className)
這種方式,className指的是採用類的徹底限定名(完整的包名+類名,若是是內部類,則是包名+類名$內部類名),使用這種方式很靈活,由於參數是字符串,能夠結合配置文件來達到動態效果。
//假設類在pyf.java.demo包下,類名爲Person,則獲取方法以下
Class<?> cls = Class.forName("pyf.java.demo.Person");
Class.forName方式對於玩過jdbc的小夥伴應該很熟悉了,在加載jdbc驅動時就使用了該種方式
//DRIVER爲配置的jdbc驅動名稱
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
使用場景
獲取元類的場景通常是在用到反射時,由於經過元類能拿到類自己的信息,如類的成員變量,構造方法,方法等,這爲動態化編程帶來了方便,這也是不少框架的基礎。得到了Class對象後,就能夠經過getAnnotations()得到註解,經過getMethods()得到方法,經過getConstructors()得到構造函數等,後續的反射代碼鋪平了道路。
3、總結:
1.萬物皆對象 2.抽象是具體的抽象,具體是抽象的具體 3.實例,類,元類的關係:具體,抽象,再抽象 4.元類的三種獲取方式 類型.class,實例.getClass,Class.forName(「類徹底限定名」)