類(lèi)的加載過(guò)程
首先編譯打包--> 驗(yàn)證:驗(yàn)證字節(jié)碼文件-->準(zhǔn)備:給類(lèi)的靜態(tài)變量分配內(nèi)存酵颁,并賦默認(rèn)值-->解析:將符號(hào)引用替換為直接引用-->初始化:對(duì)類(lèi)的靜態(tài)變量初始化為指定的值水评,執(zhí)行靜態(tài)代碼塊
類(lèi)加載執(zhí)行的順序穴墅,先靜態(tài)代碼塊后構(gòu)造方法圆凰,先父類(lèi)后子類(lèi)
//父類(lèi)
public class ParentDemo {
static {
System.out.println("父類(lèi)靜態(tài)代碼塊");
}
{
System.out.println("父類(lèi)代碼塊");
}
public ParentDemo() {
System.out.println("父類(lèi)對(duì)象創(chuàng)建");
}
}
//子類(lèi)
public class ChildrenDemo extends ParentDemo {
static {
System.out.println("子類(lèi)靜態(tài)代碼塊");
}
{
System.out.println("子類(lèi)代碼塊");
}
public ChildrenDemo() {
System.out.println("子類(lèi)構(gòu)造方法");
}
public static void main(String[] args) {
ChildrenDemo childrenDemo = new ChildrenDemo();
System.out.println("main方法運(yùn)行");
}
}
運(yùn)行結(jié)果:
父類(lèi)靜態(tài)代碼塊
子類(lèi)靜態(tài)代碼塊
父類(lèi)代碼塊
父類(lèi)對(duì)象創(chuàng)建
子類(lèi)代碼塊
這里是子類(lèi)創(chuàng)建
main方法運(yùn)行
類(lèi)加載器
引導(dǎo)類(lèi)加載器:負(fù)責(zé)加載支持jvm運(yùn)行的位于jre目錄下的核心類(lèi)庫(kù)
擴(kuò)展類(lèi)加載器:負(fù)責(zé)加載支持jvm位于jre目錄下的ext擴(kuò)展目錄中的jar
應(yīng)用程序類(lèi)加載器:負(fù)責(zé)加載classpath路徑下的類(lèi)包精绎,主要就是加載自己寫(xiě)的那些類(lèi)
雙親委派機(jī)制
1.首先檢查下指定類(lèi)名是否已經(jīng)加載衰齐,如果加載過(guò)娘香,就直接返回
2.沒(méi)有加載過(guò),查看是否有父加載器荤傲,如果有父加載器垮耳,就用父加載器加載,或者調(diào)用bootstarp加載器記載
3.如果還沒(méi)有加載,就調(diào)用當(dāng)前類(lèi)的findClass方法加載
下邊是類(lèi)加載的實(shí)現(xiàn)方法loadClass遂黍,在這里實(shí)現(xiàn)了雙親委派機(jī)制
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//判斷是否有父加載器
if (parent != null) {
//調(diào)用父加載器loadClass方法氨菇,遞歸
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
// 調(diào)用當(dāng)前加載器的findClass方法
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
為什么要用雙親委派機(jī)制
沙箱安全機(jī)制:防止核心api文件被篡改,
避免類(lèi)的重復(fù)加載:確保被加載類(lèi)的唯一性