Class的裝載分了三個階段,loading,linking和initializing。java
Class.forName(xxx.xx.xx)加載對應類的字節碼,返回的是一個類 ,靜態代碼是和class綁定的class裝載成功就表示執行了你的靜態代碼了,也就是說JVM會執行該類的靜態代碼段並且之後不會再走這段靜態代碼了。調用此方法等效於Class.forName(className, true, this.getClass().getClassLoader())注意第二個參數,是指Class是否被link。Class.forName(className)裝載的class已經被link,而ClassLoader.loadClass(className)裝載的class尚未被link。ClassLoader.loadClass方法只是將class加載到JVM中,並不會執行其靜態初始化代碼。mysql
Class.forName( )靜態方法的目的是爲了動態加載類。在加載完成後,通常還要調用Class下的newInstance( )靜態方法來實例化對象以便操做。sql
A a = (A)Class.forName("package.A").newInstance()和 A a = new A()是同樣的效果。數據庫
從JVM的角度看,咱們使用關鍵字new建立一個類的時候,這個類能夠沒有被加載。可是使用newInstance()方法的時候,就必須保證:
一、這個類已經加載;
二、這個類已經鏈接了。
ide
而完成上面兩個步驟的正是Class的靜態方法forName()所完成的,這個靜態方法調用了啓動類加載器,即加載 java API的那個加載器。this
那麼爲何會有兩種建立對象方式?這主要考慮到軟件的可伸縮、可擴展和可重用等軟件設計思想。 spa
Java中工廠模式常常使用newInstance()方法來建立對象,所以從爲何要使用工廠模式上能夠找到具體答案。 設計
例如: xml
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就能夠。 咱們能夠在調用class的靜態加載方法forName時得到更好的靈活性,提供給了一種降耦的手段。
有數據庫開發經驗朋友會發現,爲何在咱們加載數據庫驅動包的時候有的卻沒有調用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()); } }
}
打開com.mysql.jdbc.Driver的源代碼看看,
static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
原來,Driver在static塊中會註冊本身到java.sql.DriverManager。而static塊就是在Class的初始化中被執行。既然在靜態初始化器的中已經進行了註冊,因此咱們在
使用JDBC時只須要Class.forName(XXX.XXX);就能夠了。
newInstance: 弱類型。低效率。只能調用無參構造。 new: 強類型。相對高效。能調用任何public構造。