【基础篇】五、类的双亲委派机制

发布时间:2023年12月27日

1、双亲委派机制

JVM中有多个类加载器,某个类A,到底该由谁去加载 ? 双亲委派机制

该机制的作用:

  • 保证类加载的安全性:避免用户自定义一个java.lang.String恶意替换JDK的核心类库里的String类
  • 避免重复加载:避免同一个类被多次加载,提高效率

该机制的内容是,当一个类加载接收到加载类的任务时:

  • 自底向上查找是否已经被父加载器加载过,有则直接返回
  • 若没被加载,再自顶向下进行加载
    在这里插入图片描述

从下往上查找是否被加载过,没有则委派给父类加载器:

在这里插入图片描述

若全都没有被加载过,则从启动类加载器开始加载,当要加载的类不在启动类加载器的加载范围时,往下走到扩展类加载器,以此类推。

这种机制的好处是:控制了加载优先级,一个类优先去由启动类加载器去尝试加载

2、Java代码中去主动加载一个类


方式一:Class.forName( ),使用当前类的加载器去加载

方式二:classLoader对象.loadClass( ),使用指定的加载器对象去加载

public class LoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, IOException {
        //自己写的类
        ClassLoader classLoader = TestJvm.class.getClassLoader();
        System.out.println(classLoader);
        //尝试用应用类加载器去加载String类
        Class<?> clazz = classLoader.loadClass("java.lang.String");
        System.out.println(clazz.getClassLoader());
    }
}

运行结果的null,即说明还是用的启动类加载器加载的String,体现了双亲委派机制:

在这里插入图片描述

3、“父”加载器

双亲委派机制里的父加载器,这个父,不是Java继承的那个父,只是类加载器对象中有个成员变量叫parent,是上级关系,不是有继承关系。

在这里插入图片描述

应用程序加载器的parent属性为扩展类加载器,而扩展类加载器的parent为null,这是由于Java代码中没法拿到启动类加载器的对象,因此赋值为null。启动类加载器用c++编写,没有父加载器

在这里插入图片描述

Arthas工具查看类加载器的父子关系:

classloader -t

在这里插入图片描述

4、Q & A

Q:双亲委派机制?

A:

  • 某个类加载器加载一个类时,向上查找、向下加载,有加载过则直接返回,到顶层类加载器也没被加载过,再向下加载
  • 应用程序类加载器的父加载器是扩展类加载器,扩展类加载器的父加载器是启动类加载器,启动类加载器无父加载器
  • 好处是避免恶意替换JDK核心类以及避免重复加载
Q:如果一个类被三种类加载器都无法加载?

A:返回ClassNotFountException

Q:一个类重复出现在三个类加载器的范围,由谁来加载

A:由启动类加载器,其优先级最高

Q:自己的项目新建一个java.lang.String,能否被加载

A:否,会由启动类加载器加载JDK/rt.jar包下的String类

5、打破双亲委派机制

该机制下,向上查找、向下加载,如果有两个全类名相同的类,但内容不同,就只会有一个被加载。如Tomcat上运行多个web应用,其中两个web应用里都有com.plat.MyServlet类,则双亲委派机制下,后者不会被加载:

在这里插入图片描述

Tomcat使用了自定义类加载器来实现应用之间类的隔离。每一个应用会有一个独立的类加载器加载对应的类。

在这里插入图片描述

想打破类的双亲委派机制,方法有:

在这里插入图片描述

文章来源:https://blog.csdn.net/llg___/article/details/135231549
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。