ClassLoader.loadClass 和Class.forName的區(qū)別

前言

在討論之前,首先要明白一個Java類加載到JVM中經過的三個步驟

  • 裝載: 查找和導入類或接口的二進制數據
  • 鏈接: 分別執(zhí)行 校驗,準備,和解析
  • 校驗: 檢查導入類或接口的二進制數據的正確性;
  • 準備: **給類的靜態(tài)變量分配并初始化存儲空間; **
  • 解析: 將符號引用轉成直接引用;
  • 初始化: 激活類的靜態(tài)變量的初始化Java代碼和靜態(tài)Java代碼塊。

兩者的區(qū)別

對于Class.forName方法來說

   public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)

三個參數的含義分別是

  • name: 要加載Class的名字
  • initialize: 是否要初始化
  • loader : 指定的classLoader

對于 ClassLoader.loadClass()

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException

這個方法的兩個參數

  • name : class的名字
  • resolve : 是否要進行鏈接

所以: 通過傳入的參數可以知道,Class.forName 執(zhí)行之后已經對 被加載類的靜態(tài)變量分配完畢了存儲空間,而classLoader.loadClass 并沒有一定執(zhí)行完 鏈接這一步.

使用的區(qū)別

當你想動態(tài)加載一個類,而這個類又存在靜態(tài)代碼塊或者靜態(tài)變量,而你在加載的時候就想同時初始化這些靜態(tài)代碼塊。這個時候你可能更應該偏向于使用Class.forName

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
........................省略代碼....................

可以看一個使用,這是一個用戶在嗎,命令行調用jdbc時的啟動入口

    public static void main(String[] args) throws Exception {
        String jdbcUrl = DEFAULT_URL;

        if ((args.length == 1) && (args[0] != null)) {
            jdbcUrl = args[0];
        }
      //可以看到這里是使用了Class.forName 方法而不是 Classloader.forName()
        Class.forName("com.mysql.jdbc.Driver").newInstance();
`.....

一些小的細節(jié)

  • ClassLoader.forName方法如果穿入的Classloader對象為null是不會拋出空指針異常的,而是選擇使用Bootstrap ClassLoader去加載,但是我們知道Bootstrap只加載java core 庫。 so....
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容