1. 程式人生 > >Class.forName用法(詳解)

Class.forName用法(詳解)

主要功能
Class.forName(xxx.xx.xx)返回的是一個類。
Class.forName(xxx.xx.xx)的作用是要求JVM查詢並載入指定的類,也就是說JVM會執行該類的靜態程式碼段。

下面,通過解答以下三個問題的來詳細講解下Class.forName()的用法。
一.什麼時候用Class.forName()?
先來個熱身,給你一個字串變數,它代表一個類的包名和類名,你怎麼例項化它?你第一想到的肯定是new,但是注意一點:
A a = (A)Class.forName(“pacage.A”).newInstance();
這和你 A a = new A(); 是一樣的效果。

現在言歸正傳。
動態載入和建立Class 物件,比如想根據使用者輸入的字串來建立物件時需要用到:
String str = “使用者輸入的字串” ;
Class t = Class.forName(str);
t.newInstance();

在初始化一個類,生成一個例項的時候,newInstance()方法和new關鍵字除了一個是方法,一個是關鍵字外,最主要有什麼區別?

它們的區別在於建立物件的方式不一樣,前者是使用類載入機制,後者是建立一個新類。

那麼為什麼會有兩種建立物件方式?這主要考慮到軟體的可伸縮、可擴充套件和可重用等軟體設計思想。

Java中工廠模式經常使用newInstance()方法來建立物件,因此從為什麼要使用工廠模式上可以找到具體答案。 例如:
class c = Class.forName(“Example”);
factory = (ExampleInterface)c.newInstance();

其中ExampleInterface是Example的介面,可以寫成如下形式:
String className = “Example”;
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();

進一步可以寫成如下形式:
String className = readfromXMlConfig;//從xml 配置檔案中獲得字串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();

上面程式碼已經不存在Example的類名稱,它的優點是,無論Example類怎麼變化,上述程式碼不變,甚至可以更換Example的兄弟類Example2 , Example3 , Example4……,只要他們繼承ExampleInterface就可以。

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

現在可以看出,newInstance()實際上是把new這個方式分解為兩步,即首先呼叫Class載入方法載入某個類,然後例項化。

這樣分步的好處是顯而易見的。我們可以在呼叫class的靜態載入方法forName時獲得更好的靈活性,提供給了一種降耦的手段。

二.new 和Class.forName()有什麼區別?
其實上面已經說到一些了,這裡來做個總結:
首先,newInstance( )是一個方法,而new是一個關鍵字;
其次,Class下的newInstance()的使用有侷限,因為它生成物件只能呼叫無參的建構函式,而使用 new關鍵字生成物件沒有這個限制。
簡言之:
newInstance(): 弱型別,低效率,只能呼叫無參構造。
new: 強型別,相對高效,能呼叫任何public構造。
Class.forName(“”)返回的是類。
Class.forName(“”).newInstance()返回的是object 。
三.為什麼在載入資料庫驅動包的時候有用的是Class.forName( ),卻沒有呼叫newInstance( )?
在Java開發特別是資料庫開發中,經常會用到Class.forName( )這個方法。
通過查詢Java Documentation我們會發現使用Class.forName( )靜態方法的目的是為了動態載入類。
通常編碼過程中,在載入完成後,一般還要呼叫Class下的newInstance( )靜態方法來例項化物件以便操作。因此,單使用Class.forName( )是動態載入類是沒有用的,其最終目的是為了例項化物件。

相關英文參考文獻如下:
we just want to load the driver to jvm only, but not need to user the instance of driver,
so call Class.forName(xxx.xx.xx) is enough, if you call Class.forName(xxx.xx.xx).newInstance(),
the result will same as calling Class.forName(xxx.xx.xx),
because Class.forName(xxx.xx.xx).newInstance() will load driver first,
and then create instance, but the instacne you will never use in usual,
so you need not to create it.

========================== 華麗的分割線 =============================

終於明白為什麼載入資料庫驅動只用Class.forName()了!!

   
   在Java開發特別是資料庫開發中,經常會用到Class.forName( )這個方法。

通過查詢Java Documentation我們會發現使用Class.forName( )靜態方法的目的是為了動態載入類。

在載入完成後,一般還要呼叫Class下的newInstance( )靜態方法來例項化物件以便操作。因此,單單使用Class.forName( )是動態載入類是沒有用的,其最終目的是為了例項化物件。 
   這裡有必要提一下就是Class下的newInstance()和new有什麼區別?,首先,newInstance( )是一個方法,而new是一個關鍵字,其次,Class下的newInstance()的使用有侷限,因為它生成物件只能呼叫無參的建構函式,而使用 new關鍵字生成物件沒有這個限制。 
   好,到此為止,我們總結如下: 
   Class.forName("")返回的是類 
   Class.forName("").newInstance()返回的是object 
   有資料庫開發經驗朋友會發現,為什麼在我們載入資料庫驅動包的時候有的卻沒有呼叫newInstance( )方法呢?即有的jdbc連線資料庫的寫法裡是Class.forName(xxx.xx.xx);而有一 些:Class.forName(xxx.xx.xx).newInstance(),為什麼會有這兩種寫法呢?
   剛才提到,Class.forName("");的作用是要求JVM查詢並載入指定的類,如果在類中有靜態初始化器的話,JVM必然會執行該類的靜態程式碼 段。而在JDBC規範中明確要求這個Driver類必須向DriverManager註冊自己,即任何一個JDBC Driver的 Driver類的程式碼都必須類似如下:
  public class MyJDBCDriver implements Driver {
   static {
     DriverManager.registerDriver(new MyJDBCDriver());
  }
  }
 既然在靜態初始化器的中已經進行了註冊,所以我們在使用JDBC時只需要Class.forName(XXX.XXX);就可以了。

貼出Proxool 連線池的靜態初始化方法:

public class ProxoolDriver implements Driver {

    private static final Log LOG = LogFactory.getLog(ProxoolDriver.class);

    static {
        try {
            DriverManager.registerDriver(new ProxoolDriver());
        } catch (SQLException e) {
            System.out.println(e.toString());
        }
    }

}