java八股文面试[JVM]——双亲委派模型

1.当AppClassLoader 去加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委托给父加载器ExtClassLoader 去完成。

2.当ExtClassLoader去加载一个class时,它首先也不会去尝试加载这个类,而是把类加载请求委托给父加载器BootstrapClassLoader 去完成。

3.如果BootstrapClass加载失败(例如在JAVA_HOME/jre/lib里未找到该class),就会使用ExtClassLoader来尝试加载。

4.如果使用ExtClassLoader加载失败(例如在JAVA_HOME/jre/lib/ext里未找到该class),就会使用AppClassLoader来尝试加载。如果AppClassLoader也加载失败,则会抛出异常ClassNotFoundException

从代码层面了解几个Java中定义的类加载器及双亲委派模型的实现,他们的类图关系如下。

从图可以看出顶层的类加载器是抽象类abstract ClassLoader,其后所有的类加载器都继承自ClassLoader(不包括启动类加载器)。为了更好的理解双亲委派模型,ClassLoader源码中的loadClass(String)方法该方法加载指定名称(包括包名)的二进制类型,该方法在jdk1.2后不建议用户重写但是可以直接调用该方法。loadClass ()方法是ClassLoader类自己实现的,该方法中的逻辑就是双亲委派模式的实现loadClass(String name, boolean resolve)是一个重载方法,resolve参数代表是否生成Class对象的进行解析相关的操作,源码分析如下。

双亲委派模型意义总结来讲就是:

1.系统类防止内存中出现多份相同的字节码。

2.保证Java程序安全稳定运行。

加载类的三种方式

到这里,相信大家都对类加载器和类的加载都有一定的了解了,那么你知道嘛?常见的加载类的方式有三种。

  1. 静态加载:也就是使用new关键字来创建实例对象,
  2. 动态加载:使用Class.forName()动态加载(反射加载类型),然后调用类的newInstance()方法实例化对象。
  3. 动态加载:通过类加载器的loadClass()方法来加载类,然后调用类的newInstance()方法实例化对象。
三种方式的区别
  1. 第一种和第二种 方式使用的类加载器是相同的,都是当前类加载器(this.getClass().getClassLoader ()),第三种方式需要用户指定类加载器。
  2. 如果需要在当前类路径以外加载类,则只能使用第三种方式,第三种方式加载的类与当前类分属不同的命名空间
  3. 第一种方式是静态加载,第二种和第三种是动态加载。
两种异常(Exception)
  1. 静态加载的时候如果在运行环境中找不到要初始化的类,抛出的是NoClassDefFoundError。它在Java的异常体系中是一个**error**。
  2. 动态加载的时候如果运行环境中找不到要初始化的类,抛出的是ClassNotFoundException。它在Java的异常体系中是一个**checked异常**。
Class.forName与ClassLoader.loadClass的区别

首先,我们必须要明白类加载机制的三个主要过程是:加载-->连接-->初始化。

  • Class.forName():除了将类的.class文件加载到JVM中之外,还对类进行解释 ,执行类中的static块。
  • ClassLoder.loadClass():只是 将类的.class文件加载到JVM中,并不会执行类的static块,只有在newInstance才会执行static块
  • Class.forName(name, initialize, loader):带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数。创建类的对象 。

下面我们写下代码,加深一下影响。

java 复制代码
public class Demo {
    static {
        System.out.println("正在加载Demo...");
    }
}
java 复制代码
import java.lang.Class;

public class TestDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.使用 Class.forName()加载类,默认执行static块。
        Class.forName("Demo");
        //获得当前类的类加载器
        ClassLoader classLoader = Test.class.getClassLoader();
        //2.使用 Class.forName()加载类,并指定ClassLoader。初始化时不会执行static块。
        Class.forName("Demo", false, classLoader);
        //3.使用ClassLoader类的loadClass()方法加载类,不会执行初始化
        classLoader.loadClass("Demo");
    }
}

只有第一行代码输出了

知识来源:

【基础】双亲委派模型_哔哩哔哩_bilibili

深入理解Java类加载器(ClassLoader)

相关推荐
Freak嵌入式13 分钟前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
java·开发语言·数据结构·python·接口·抽象基类
前端小马23 分钟前
解决IDEA出现:java: 程序包javax.servlet不存在的问题
java·servlet·intellij-idea
IH_LZH1 小时前
Broadcast:Android中实现组件及进程间通信
android·java·android studio·broadcast
去看全世界的云1 小时前
【Android】Handler用法及原理解析
android·java
.Net Core 爱好者1 小时前
Redis实践之缓存:设置缓存过期策略
java·redis·缓存·c#·.net
晚睡早起₍˄·͈༝·͈˄*₎◞ ̑̑1 小时前
苍穹外卖学习笔记(五)
java·笔记·学习
码上一元1 小时前
【百日算法计划】:每日一题,见证成长(017)
java·算法
用生命在耍帅ㅤ1 小时前
java spring boot 动态添加 cron(表达式)任务、动态添加停止单个cron任务
java·开发语言·spring boot
longlongqin1 小时前
JVM 虚拟机的编译器、类加载过程、类加载器有哪些?
jvm
学java的小菜鸟啊1 小时前
第五章 网络编程 TCP/UDP/Socket
java·开发语言·网络·数据结构·网络协议·tcp/ip·udp