双亲委派机制

java面试总结 -------双亲委派模型

双亲委派模型是类加载器中一个重要的知识点。


类加载器模型

在这里插入图片描述
根据上图类加载模型,类加载器由三部分组成,

  • 位于最上端也就是顶层父类的是根类加载器,它只加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库,此加载器由c++实现。
  • 然后下一层即根类加载器的子类加载器是拓展类加载器,由根类加载器加载,拓展类加载器只加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。
  • 再下面就是应用类加载器,由拓展类加载器加载,应用类加载器为Java默认加载器.
  • 然后再下面就是用户的自定义加载器,由应用类加载器加载。

所以,从上到下为父子关系,且三个加载器中除了根类加载器,拓展类加载器应用类加载器,有且只有一个父加载器。

双亲委托机制流程(见上图)

  • 当一个类需要加载时,当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。且每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。
  • 如果当前类没有加载,则会向父加载器查询是否加载,若有,则返回类,若无,再向父加载器的父加载器查询,周而复始下去,知道查询到了根类加载器。
  • 如果根类加载器有,则返回,若无,则从根类加载器向下尝试是否能加载,再从根类加载器尝试是否能加载,不能则交给子类尝试加载,周而复始直到能加载此类为止。
  • 一般来说,用户的自定义类均从应用类加载器加载,即从下往上找是否加载到根类加载器,再从上往下交给应用类加载器加载完成并返回。

实例详解

public class MyTest5 {
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("java.lang.String");
        System.out.println(clazz.getClassLoader());
    }
}

在这个例子中,我们先用Class.forName获得了String的类,然后使用getClassLoader方法获得该类的加载器,在ClassLoadergetClassLoader方法源码中,有这么一行注释:

Returns the class loader for the class. Some implementations may use
null to represent the bootstrap class loader. This method will return
null in such implementations if this class was loaded by the bootstrap
class loader.

该注释大概意思时,该方法返回类的类加载器,如果该类的加载器是根类加载器就返回null。
由于String方法是属于jt.jar包的所以由根类加载加载,输出结果为null。

public class MyTest5 {
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("classloader.MyTest5");
        System.out.println(clazz.getClassLoader());
    }
}

这里我们输出用户自定义类的类加载器,由双亲委派机制可以得出,该类的类加载器为应用类加载器,所以它的输出结果为:
在这里插入图片描述
即应用类加载器(AppClassLoader)

另:getClassLoader方法不是对类的主动使用

public class MyTest6 {
    public static void main(String[] args) {
        ClassLoader classLoader=ClassLoader.getSystemClassLoader();
        while (null!=classLoader){
            System.out.println(classLoader);
            classLoader = classLoader.getParent();
        }
        System.out.println(classLoader);
    }
}

在这段代码中,我们先获得了系统类加载器(即应用类加载器),然后循环输出父类直到为null为止,
该代码输出结果为:
在这里插入图片描述
从这张图中,可以看出,系统加载器的父加载器是拓展类加载器,拓展类加载器的父加载器是根类加载器
(输出为null)
所以从实例三可以看出类加载器的层次关系。

几个重要api

  • clazz.getClasLoader():获得当前类的ClassLoader
  • Thread.currentThread().getContextClassLoader():获得当前线程上下文的ClassLoader
  • ClassLoader.getSystemCassLoader():获得系统的ClassLoader
  • DriverMangager,getCallerClassLoader():获得调用者的ClassLoader

资料:双亲委托机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值