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()
}
}