首先来了解一下类加载器,类加载器的工作是将.class文件加载到内存中,在方法区创建数据结构,并在堆中创建类的对象以便调用方法区的方法。JAVA提供了三种类加载器:
一.启动类加载器(Bootstrap.ClassLoader),加载<JAVA_HOME>/lib路径下的核心类库。
二.扩展类加载器(Extending.ClassLoader),加载<JAVA_HOME>/lib/ext路径下的扩展类库。
三.应用类加载器(Application.ClassLoader),加载当前类路径或者导入的类库路劲下的类库。应用类加载器可以自定义。
这儿有一个父类加载器的概念,启动类加载器是扩展类加载器的父类,而扩展类加载器是应用类加载器的父类。双亲委派模型加载的原理是这样的:
1.首先应用类加载器会收到加载类的请求,收到请求后不立即加载,而是调用其父类加载器即扩展类加载器去加载。
2.扩展类加载器收到加载请求后也不会立即加载,而是调用其父类加载器启动类加载器去加载。
3.启动类加载器收到加载请求后,会去<JAVA_HOME>/lib路径下寻找需要加载的类,若找到则加载,若找不到则回退请求其子类加载器即扩展类加载器去加载。
4.扩展类加载器收到请求后,会去<JAVA_HOME>/lib/ext路径下寻找需要加载的类,若找到则加载,若找不到则回退请求其子类加载器即应用类加载器去加载。
5.应用类加载器收到请求后,会去当前类路径或者导入类库的路径下寻找需要加载的类,若找到则加载,若找不到则抛出ClassNotFoundException异常。
使用双亲委派模型去加载类最大的好处就是可以避免重复加载类。这也是为什么重复加载类也会抛出ClassNotFoundException异常的原因。