参考了这篇双亲委派机制,就再也不会云里雾里啦!

我是方圆,愿你我皆能理解双亲委派机制

1. 在之前,不得不先理解类加载器

我们先来看一段简单的代码

public class Car {

    public static void main(String[] args) {
		//实例化
        Car car = new Car();
        //获取Car Class模板
        System.out.println(car.getClass());

        //应用程序类加载器,AppClassLoader
        System.out.println(car.getClass().getClassLoader());

        //扩展类加载器,ExtClassLoader
        System.out.println(car.getClass().getClassLoader().getParent());

        //虽然为null,是java调用不到,实际上它是启动类加载器,BootstrapClassLoader
        //主要负责加载核心类库
        System.out.println(car.getClass().getClassLoader().getParent().getParent());
    }
}

从上方代码中,我们可以看到,从实体类一直获取到启动类加载器,从下图中理解更直观。
在这里插入图片描述
我们可以发现有三种类加载器

  1. 最底层的,Application ClassLoader:加载classpath上指定的类库
  2. 其次,Extension ClassLoader:加载jre/lib/ext/*.jar
  3. 最后是,Bootstrap ClassLoader:加载jre/lib/rt.jar

我们不妨画一幅图,理解一下
在这里插入图片描述
大家可以看见,我画了双向的箭头,下面就要聊聊双亲委派机制,理解了之后自然就明白了

2. 双亲委派机制

2.1 什么是双亲委派机制?

双亲委派机制是指当一个类加载收到一个类加载的请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器范围内找不到指定类时,子类加载器才会自己尝试加载。

读完这段概念,是不是还有点儿懵,下面我们来详细解析一下这个过程

2.2 双亲委派机制的工作过程

  1. 当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。
  2. 当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
  3. 如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
  4. 如果Extension ClassLoader加载失败,就会使用Application ClassLoader加载。
  5. 如果Application ClassLoader加载失败,就会使用自定义加载器去尝试加载。
  6. 如果均加载失败,就会抛出ClassNotFoundException异常。(这也是我们常见的一个异常)

2.3 我们拿代码来举一个例子

目录结构如下
在这里插入图片描述

package java.lang;

public class String {
    @Override
    public String toString() {
        return "简单测试,双亲委派机制";
    }
    public static void main(String[] args) {
        String s = new String();
		//在双亲委派机制的作用下,会发生异常
        s.toString();
    }
}

异常如下

在这里插入图片描述

我们也能从中理解到双亲委派机制的作用:保证安全,防止重复加载同一个.class,保证核心.class不能被篡改

2.4 看一下源码加深理解

下面是ClassLoader中,loadClass()方法

protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先检查这个class是否已经加载过了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // c==null表示没有加载,如果有父类的加载器则让父类加载器加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //如果父类的加载器为空 则说明递归到bootStrapClassloader了
                        //bootStrapClassloader比较特殊无法通过get获取
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {}
                if (c == null) {
                    //如果bootstrapClassLoader 仍然没有加载过,则递归回来,尝试自己去加载class
                    long t1 = System.nanoTime();
                    c = findClass(name);
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

在这里插入图片描述

原创文章 56 获赞 19 访问量 6018

猜你喜欢

转载自blog.csdn.net/qq_46225886/article/details/106031944
今日推荐