1 回答

TA貢獻1818條經(jīng)驗 獲得超11個贊
Class.forName 和 ClassLoader.loadClass 的區(qū)別
類加載
為了弄清楚 Class.forName
和 ClassLoader.loadClass
的區(qū)別, 首先我們需要了解 JVM 中類加載的步驟.
類的加載可以分為如下幾步
加載: 通過類的全限定名獲取到類的二進制流, 然后加載到 JVM 中
驗證: 確保Class 文件的字節(jié)流中包含的信息符合虛擬機的要求, 并且不會危害虛擬機的安全
準(zhǔn)備: 為類變量分配內(nèi)存空間并設(shè)置類變初始值
解析
初始化: 根據(jù)用戶指定的代碼初始化字段和其他資源, 執(zhí)行 static 塊.
Class.forName
當(dāng)我們通過:
Class.forName("com.test.MyObj")
來獲取一個 Class 時, 那么其實相當(dāng)于調(diào)用了 Class.forName(className, true, currentLoader)
, 這個方法的第二個參數(shù)表示是否需要初始化類. 我們設(shè)置為 true
, 因此 Class.forName 獲取到 Class 對象時, 會自動對類進行初始化的.
并且 Class.forName 加載類的 ClassLoader 和調(diào)用 Class.forName
所在的類的 ClassLoader 相同.
ClassLoader.loadClass
與 Class.forName
不同, 默認情況下 ClassLoader.loadClass
并不會初始化類, 即類加載的 初始化
步驟沒有執(zhí)行, 因此類中的靜態(tài)代碼塊不會執(zhí)行.
并且使用 ClassLoader.loadClass
時, 我們可以指定不同的 ClassLoader. 例如:
ClassLoader.getSystemClassLoader().loadClass("com.test.MyObj");
一個例子
public class MyObj {
static {
System.out.println("MyObj class init.");
}
}
public class Test implements Cloneable, Serializable {
public static void main(String[] args) throws Exception {
Class.forName("com.test.MyObj");
// ClassLoader.getSystemClassLoader().loadClass("com.test.MyObj");
}
}
那么上面的代碼中, Class.forName("com.test.MyObj")
的調(diào)用會觸發(fā) MyObj 的靜態(tài)代碼塊的執(zhí)行, 而 ClassLoader.getSystemClassLoader().loadClass("com.test.MyObj");
并不會.
這樣使用有什么好處?
我個人猜測, 應(yīng)該和 Spring IoC 的 Lazy loading 有關(guān), Spring IoC 為了加快初始化速度, 因此大量使用了延時加載技術(shù). 而使用 classloader 不需要執(zhí)行類中的初始化代碼, 可以加快加載速度, 把類的初始化工作留到實際使用到這個類的時候.
添加回答
舉報