前言
在討論之前隐轩,首先要明白一個Java類加載到JVM中經(jīng)過的三個步驟
- 裝載: 查找和導(dǎo)入類或接口的二進(jìn)制數(shù)據(jù)
- 鏈接: 分別執(zhí)行 校驗(yàn),準(zhǔn)備戳晌,和解析
- 校驗(yàn): 檢查導(dǎo)入類或接口的二進(jìn)制數(shù)據(jù)的正確性陪拘;
- 準(zhǔn)備: **給類的靜態(tài)變量分配并初始化存儲空間菜枷; **
- 解析: 將符號引用轉(zhuǎn)成直接引用;
- 初始化: 激活類的靜態(tài)變量的初始化Java代碼和靜態(tài)Java代碼塊涮较。
兩者的區(qū)別
對于Class.forName方法來說
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
三個參數(shù)的含義分別是
- name: 要加載Class的名字
- initialize: 是否要初始化
- loader : 指定的classLoader
對于 ClassLoader.loadClass()
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
這個方法的兩個參數(shù)
- name : class的名字
- resolve : 是否要進(jìn)行鏈接
所以: 通過傳入的參數(shù)可以知道,Class.forName 執(zhí)行之后已經(jīng)對 被加載類的靜態(tài)變量分配完畢了存儲空間稠鼻,而classLoader.loadClass 并沒有一定執(zhí)行完
鏈接這一步.
使用的區(qū)別
當(dāng)你想動態(tài)加載一個類,而這個類又存在靜態(tài)代碼塊或者靜態(tài)變量狂票,而你在加載的時候就想同時初始化這些靜態(tài)代碼塊候齿。這個時候你可能更應(yīng)該偏向于使用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!");
}
}
........................省略代碼....................
可以看一個使用,這是一個用戶在嗎闺属,命令行調(diào)用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();
`.....
一些小的細(xì)節(jié)
- ClassLoader.forName方法如果穿入的Classloader對象為null是不會拋出空指針異常的慌盯,而是選擇使用Bootstrap ClassLoader去加載,但是我們知道Bootstrap只加載java core 庫掂器。 so....