1 public Class loadClass(String name) throws ClassNotFoundException { 2 return loadClass(name, false); 3 } 4 5 protected Class loadClass(String name, boolean resolve) 6 throws ClassNotFoundException 7 { 8 synchronized (getClassLoadingLock(name)) { 9 // First, check if the class has already been loaded10 Class c = findLoadedClass(name);11 if (c == null) {12 long t0 = System.nanoTime();13 try {14 if (parent != null) {15 c = parent.loadClass(name, false);16 } else {17 c = findBootstrapClassOrNull(name);18 }19 } catch (ClassNotFoundException e) {20 // ClassNotFoundException thrown if class not found21 // from the non-null parent class loader22 }23 24 if (c == null) {25 // If still not found, then invoke findClass in order26 // to find the class.27 long t1 = System.nanoTime();28 c = findClass(name);29 30 // this is the defining class loader; record the stats31 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);32 sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);33 sun.misc.PerfCounter.getFindClasses().increment();34 }35 }36 if (resolve) {37 resolveClass(c);38 }39 return c;40 }41 }
从源码(jdk1.8)中看loadClass这个方法,注释上已经说的很清楚了,调用findLoadedClass方法检查有没有加载过这个类,如果没有就调用parent的loadClass方法,从底层一级级往上。如果找到最后都没有ClassLoader加载过这个类,就调用findClass方法查找这个类,然后又从顶层一级级往下调用findClass方法,如果有自定义ClassLoader的话最后会走到自定义的findClass方法,最终都没找到就抛出ClassNotFoundException。
为什么要使用双亲委派机制去加载类
-
比如两个类A和类B都要加载System类:
-
如果不用委托而是自己加载自己的,那么类A就会加载一份System字节码,然后类B又会加载一份System字节码,这样内存中就出现了两份System字节码。
-
如果使用委托机制,会递归的向父类查找,也就是首选用Bootstrap尝试加载,如果找不到再向下。这里的System就能在Bootstrap中找到然后加载,如果此时类B也要加载System,也从Bootstrap开始,此时Bootstrap发现已经加载过了System那么直接返回内存中的System即可而不需要重新加载,这样内存中就只有一份System的字节码了。
-
如果有人想篡改System类,如String.java,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了,就算自己重写,也总是使用Java系统提供的System,自己写的System类根本没有机会得到加载。从一定程度上防止了危险代码的植入。