前言
在討論之前,首先要明白一個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....