程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深入研究java.lang.Class類

深入研究java.lang.Class類

編輯:關於JAVA
 Java

程序在運行時,Java運行時系統一直對所有的對象進行所謂的運行時類型標識。這項信息紀錄了每個對象所屬的類。虛擬機通常使用運行時類型信息選准正確方法去執行,用來保存這些類型信息的類是Class類。Class類封裝一個對象和接口運行時的狀態,當裝載類時,Class類型的對象自動創建。

  Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的,因此不能顯式地聲明一個Class對象。

  虛擬機為每種類型管理一個獨一無二的Class對象。也就是說,每個類(型)都有一個Class對象。運行程序時,Java虛擬機(JVM)首先檢查是否 所要加載的類對應的Class對象是否已經加載。如果沒有加載,JVM就會根據類名查找.class文件,並將其Class對象載入。

  基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也都對應一個 Class 對象。

  每個數組屬於被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。

  一般某個類的Class對象被載入內存,它就用來創建這個類的所有對象。

  一、如何得到Class的對象呢?有三種方法可以的獲取:

  1、調用Object類的getClass()方法來得到Class對象,這也是最常見的產生Class對象的方法。例如:

  MyObject x;

  Class c1 = x.getClass();

  2、使用Class類的中靜態forName()方法獲得與字符串對應的Class對象。例如:

  Class c2=Class.forName("MyObject"),Employee必須是接口或者類的名字。

  3、獲取Class類型對象的第三個方法非常簡單。如果T是一個Java類型,那麼T.class就代表了匹配的類對象。例如:

  Class cl1 = Manager.class;

  Class cl2 = int.class;

  Class cl3 = Double[].class;

  注意:Class對象實際上描述的只是類型,而這類型未必是類或者接口。例如上面的int.class是一個Class類型的對象。由於歷史原因,數組類型的getName方法會返回奇怪的名字。

  二、Class類的常用方法

  1、getName()

  一個Class對象描述了一個特定類的屬性,Class類中最常用的方法getName以 String 的形式返回此 Class 對象所表示的實體(類、接口、數組類、基本類型或 void)名稱。

  2、newInstance()

  Class還有一個有用的方法可以為類創建一個實例,這個方法叫做newInstance()。例如:

  x.getClass.newInstance(),創建了一個同x一樣類型的新實例。

  newInstance()方法調用默認構造器(無參數構造器)初始化新建對象。

  3、getClassLoader()

  返回該類的類加載器。

  4、getComponentType()

  返回表示數組組件類型的 Class。

  5、getSuperclass()

  返回表示此 Class 所表示的實體(類、接口、基本類型或 void)的超類的 Class。

  6、isArray()

  判定此 Class 對象是否表示一個數組類。

 三、Class的一些使用技巧

  1、forName和newInstance結合起來使用,可以根據存儲在字符串中的類名創建對象。例如:

  Object obj = Class.forName(s).newInstance();

  2、虛擬機為每種類型管理一個獨一無二的Class對象。因此可以使用==操作符來比較類對象。例如:

  if(e.getClass() == Employee.class)...

  四、Class的forName() 和 ClassLoader 的 loadClass 方法

  關於forName()方法

  這個方法總是返回要加載的類的Class類的實例。

  1、forName(String className)單參數時, initialize=true。

  a.總是使用當前類裝載器(也就是裝載執行forName()請求的類 的類裝載器)。

  b.總是初始化這個被裝載的類(當然也包括:裝載、連接、初始化)。

  2、forName(String className, boolean initialize, ClassLoader loader)。

  a.loader指定裝載參數類所用的類裝載器,如果null則用bootstrp裝載器。

  b.initialize=true時,肯定連接,而且初始化了。

  c.false時,絕對不會初始化,但是可能被連接了,但是這裡有個例外,如果在調用這個forName()前,已經被初始化了,那麼返回的類型也肯定是被初始化的(當然,這裡也暗含著:被同一個loader所裝載的,而且這個類被初始化了)。

  關於用戶自定義的類裝載器的loadClass()方法。

  1、loadClass(String name)單參數時, resolve=false。

  a.如果這個類已經被這個類裝載器所裝載,那麼,返回這個已經被裝載的類型的Class的實例,否則,就用這個自定義的類裝載器來裝載這個class,這時不知道是否被連接。絕對不會被初始化。

  b.這時唯一可以保證的是,這個類被裝載了。但是不知道這個類是不是被連接和初始化了。

  2、loadClass(String name, boolean resolve)。

  a.resolve=true時,則保證已經裝載,而且已經連接了。resolve=falses時,則僅僅是去裝載這個類,不關心是否連接了,所以此時可能被連接了,也可能沒有被連接。

  為什麼 forName()是會執行 static 語句,因為默認情況它總是初始化這個被裝載的類。

  jvm會執行靜態代碼段,你要記住一個概念,靜態代碼是和class綁定的,class裝載成功就表示執行了你的靜態代碼了。而且以後不會再走這段靜態代碼了。

  Class.forName(xxx.xx.xx) 返回的是一個類。

  Class.forName(xxx.xx.xx);的作用是要求JVM查找並加載指定的類,也就是說JVM會執行該類的靜態代碼段。

  五、newInstance()方法和new關鍵字

  在初始化一個類,生成一個實例的時候,newInstance()方法和new關鍵字除了一個是方法,一個是關鍵字外,最 主要有什麼區別?它們的區別在於創建對象的方式不一樣,前者是使用類加載機制,後者是創建一個新類。那麼為什麼會有兩種創建對象方式?這主要考慮到軟件的 可伸縮、可擴展和可重用等軟件設計思想。

  從JVM的角度看,我們使用關鍵字new創建一個類的時候,這個類可以沒有被加載。但是使用 newInstance()方法的時候,就必須保證:1、這個類已經加載;2、這個類已經連接了。而完成上面兩個步驟的正是Class的靜態方法 forName()所完成的,這個靜態方法調用了啟動類加載器,即加載 Java

 API的那個加載器。

  可以看出,newInstance()實際上是把new這個方式分解為兩步,即首先調用Class加載方法加載某個類,然後實例化。 這樣分步的好處是顯而易見的。我們可以在調用class的靜態加載方法forName時獲得更好的靈活性,提供給了一種降耦的手段。

  最後用最簡單的描述來區分new關鍵字和newInstance()方法的區別:

  newInstance:弱類型。低效率。只能調用無參構造。

  new: 強類型。相對高效。能調用任何public構造。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved