Class.forName和ClassLoader有啥區別?

Java中的Class.forName()和ClassLoader 都可以對類進行加載,在學習mysql期間可能會經常用到Class.forName(),ClassLoader負責將Class的字節碼形式轉換成內存形式的 Class 對象。字節碼可以來自於磁盤文件,也就是XXXX.class,也可以來自jar包裏的XXXX.class,也可以來自遠程服務器提供的字節流,字節碼的本質就是一個字節數組[]byte。

實際上Class.forName()方法也是調用的 ClassLoader 來實現的。
forName方法最後調用 forName0(本地方法),第二個參數被默認設置爲了 true,這個參數代表是否對加載的類進行初始化,設置爲 true 時會類進行初始化,代表會執行類中的靜態代碼塊,以及對靜態變量的賦值等操作。

 @CallerSensitive
 public static Class<?> forName(String className)
             throws ClassNotFoundException {
     Class<?> caller = Reflection.getCallerClass();
     return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
 }

他還有個重載方法,可以手動選擇在加載類時是否要對其類進行初始化。

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

編寫一個類測試一下。

public class Test {
    static {
        System.out.println("靜態代碼快");
    }
    public static final String title=getTitle();

    private static String getTitle(){
        System.out.println("執行getTitle()");
        return "TITLE";
    }
}

測試方法:

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("com.hxl.Test");
    }
}

運行結果:

靜態代碼快
執行getTitle()

根據運行結果得出 Class.forName 加載類時將類進了初始化,再看Classloader。

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
      ClassLoader.getSystemClassLoader().loadClass("com.hxl.Test");
    }
}

而 ClassLoader 的 loadClass 並沒有對類進行初始化,只是把類加載到了虛擬機中。

最後在說說JDBC,我們使用 JDBC 時通常是使用 Class.forName() 方法來加載數據庫連接驅動。這是因爲在 JDBC 規範中明確要求 Driver(數據庫驅動)類必須向 DriverManager 註冊自己。

以 MySQL 的驅動爲例,我們看到 Driver 註冊到 DriverManager 中的操作寫在了靜態代碼塊中,這就是爲什麼在寫 JDBC 時使用 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!");
        }
    }
    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章