问七:谈谈ClassLoader的双亲委派机制?
原理图:
代码实现:
这段代码的意思是:如果当前类加载器还有父类,就委托父类进行类加载,这个过程一直持续到BootstrapClassLoader这个类中,如果没有则报错。如果某一个父类中有,则加载到内存中,同时findLoadedClass就能够得到加载后的class,直接跳过父类加载器以外的加载器。
回答:
JDK有三中类加载器:用来加载核心类库的引导类加载器(BootStrap ClassLoader)、用来加载拓展类库的拓展类加载器(Extension ClassLoader)、用来加载类路径下文件的程序类加载器(App ClassLoader),当然我们也可以自己通过继承ClassLoader实现Custom ClassLoader。
双亲委派机制就是当JVM收到一个类加载请求的时候,不会直接让当前类的类加载器加载该类,而是将请求委派给它的上层类加载器,源代码通过一个if else的判断来实现,会先查看它的parent是否为空,如果不为空就交给父类的loadClass方法进行加载,如果为空,就代表请求请求已经到达了最顶层的引导类加载器,然后逐层向下递归加载该类,如果某一层的类加载器找到了就直接加载返回,如果都找不到,那就抛出ClassNotFoundException的异常。
为什么要使用双亲委派机制去加载类呢?
避免自定义的类覆盖核心类库的行为。比如我们可以自定义一个java.lang.Object的类,如果没有双亲委派机制,那么java.lang.Object的类加载请求就可能被App ClassLoader处理,这样就会加载自定义的java.lang.Object从而屏蔽了核心类库中的Object,影响JVM的正常工作。
自定义类加载器的步骤与优势:
自定义类加载器步骤:
* 定义一个类,继承 ClassLoader
* 重写 loadClass 方法
* 实例化 Class 对象
自定义类加载器的优势:
* 类加载器是 Java 语言的一项创新,也是 Java 语言流行的重要原因之一,它最初的设计是为了满足 java applet 的需求而开发出来的
* 高度的灵活性
* 通过自定义类加载器可以实现热部署
* 代码加密
附加:
1.类ClassLoader是一个抽象类,Application ClassLoader和Extension ClassLoader的具体实现类分别是sun.misc.Launcher$AppClassLoader和sun.misc.Launcher$ExtClassLoader,Bootstrap ClassLoader不是由Java实现的,没有对应的类。
2.每个Class对象都有一个方法,可以获取实际加载它的ClassLoader,方法是:
public ClassLoader getClassLoader()
3.ClassLoader有一个方法,可以获取它的父ClassLoader:
public final ClassLoader getParent()
4.如果ClassLoader是Bootstrap ClassLoader,返回值为null
5.ClassLoader有一个静态方法,可以获取默认的系统类加载器:
public static ClassLoader getSystemClassLoader()
6.ClassLoader中有一个主要方法,用于加载类:
public Class<?> loadClass(String name) throws ClassNotFoundException
7.在反射中,有两个方法:
public static Class<?> forName(String className)
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
第一个方法使用系统类加载器加载。第二个指定ClassLoader,参数initialize表示,加载后,是否执行类的初始化代码(如static语句块),没有指定默认为true