1、类加载器以及双亲委派机制
比如custom ClassLoader要加载一个类,会先询问它的parent类,然后AppClassLoader会看它有没有加载过这个类,如果没有继续询问它的parent即ExtensionClassLoader
直到询问至BootstrapClassLoader也没有加载,因为BootstrapClassLoader只负责加载核心类,所以加载失败。它的child即ExtensionClassLoader就会去尝试加载,但是这个类也不在它的加载
范围之内,也加载失败。最后就到了customlClassLoader这个加载器加载。(注意父类并不会主动调用子类去加载,而是父类加载失败后,子类再去尝试加载)。
双亲委派机制对于保证Java程序的稳定性起了十分重要的作用,在双亲委派机制下要加载一个类最终都会委派给顶端的BootstrapClassLoader进行加载,所以如果用户自己编写一个Java.lang.Object
类,并加载这个类并不会破坏程序的稳定性。
ClassLoader是这些类加载器的顶层父类,下面是其中加载源码:
1 protected Class<?> loadClass(String name, boolean resolve) 2 throws ClassNotFoundException 3 { 4 synchronized (getClassLoadingLock(name)) { 5 // First, check if the class has already been loaded 6 Class<?> c = findLoadedClass(name); 7 if (c == null) { 8 long t0 = System.nanoTime(); 9 try { 10 if (parent != null) { 11 c = parent.loadClass(name, false); 12 } else { 13 c = findBootstrapClassOrNull(name); 14 } 15 } catch (ClassNotFoundException e) { 16 // ClassNotFoundException thrown if class not found 17 // from the non-null parent class loader 18 } 19 20 if (c == null) { 21 // If still not found, then invoke findClass in order 22 // to find the class. 23 long t1 = System.nanoTime(); 24 c = findClass(name); 25 26 // this is the defining class loader; record the stats 27 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); 28 sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); 29 sun.misc.PerfCounter.getFindClasses().increment(); 30 } 31 } 32 if (resolve) { 33 resolveClass(c); 34 } 35 return c; 36 } 37 }
由代码可以看出,加载类的时候会先自己找,没找到就找它的父加载器,父加载器也是如此,就类似于递归操作。如果没有找到合适的父加载器就调用 findClass 方法自己加载。
1 protected Class<?> findClass(String name) throws ClassNotFoundException { 2 throw new ClassNotFoundException(name); 3 }
进入findClass就直接抛出了ClassNotFoundException。但是像AppClassLoader等继承与URLClassLoader,而URLClassLoader的父类的父类就是ClassLoader,并重写了此方法。
所以如果想自定义类加载器,就只要继承ClassLoader然后重写这个方法就行。