JVM:双亲委派机制&类加载器

JVM:双亲委派机制

  • 1. 例子
  • 2. 类加载器总结
  • 3. 类加载过程
  • 4. 双亲委派模型的执行流程:
  • 5. 双亲委派模型的好处

1. 例子

Java运行时环境有一个java.lang包,里面有一个ClassLoader
JVM:双亲委派机制&类加载器_第1张图片
JVM:双亲委派机制&类加载器_第2张图片

我们自定义一个String类在java.lang包下,下面的main方法报错。原因是: 根据双亲委派机制,会向上找先是找到了应用程序加载器(appClassLoader) ,然后向上找扩展类加载器(ExtClassLoader),最后找根类加载器(Boot Strap Loader),发现有String执行根加载器的也就是rt.jar包中的。 其实就是上级的加载器有的就执行上级的

2. 类加载器总结

JVM 中内置了三个重要的 ClassLoader:

  1. BootstrapClassLoader(启动类加载器) :最顶层的加载类,由 C++实现,通常表示为 null,并且没有父级,主要用来加载 JDK 内部的核心类库( %JAVA_HOME%/lib目录下的 rt.jar 、resources.jar 、charsets.jar等 jar 包和类)以及被 -Xbootclasspath参数指定的路径下的所有类。
  2. ExtensionClassLoader(扩展类加载器):主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类以及被 java.ext.dirs 系统变量所指定的路径下的所有类。
  3. AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

简单来说,类加载器的主要作用就是加载 Java 类的字节码( .class 文件)到 JVM 中(在内存中生成一个代表该类的 Class 对象)。 字节码可以是 Java 源程序(.java文件)经过 javac 编译得来,也可以是通过工具动态生成或者通过网络下载得来。

3. 类加载过程

  • 类加载过程:加载->连接->初始化。
  • 连接过程又可分为三步:验证->准备->解析。

JVM:双亲委派机制&类加载器_第3张图片

加载是类加载过程的第一步,主要完成下面 3 件事情:

  1. 通过全类名获取定义此类的二进制字节流
  2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构
  3. 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口

4. 双亲委派模型的执行流程:

  • 在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载(每个父类加载器都会走一遍这个流程)。
  • 类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 loadClass()方法来加载类)。这样的话,所有的请求最终都会传送到顶层的启动类加载器 BootstrapClassLoader 中。
  • 只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载(调用自己的 findClass() 方法来加载类)。
    JVM:双亲委派机制&类加载器_第4张图片
    JVM:双亲委派机制&类加载器_第5张图片

5. 双亲委派模型的好处

双亲委派模型保证了 Java 程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。

JVM:双亲委派机制&类加载器_第6张图片

如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现两个不同的 Object 类。双亲委派模型可以保证加载的是 JRE 里的那个 Object 类,而不是你写的 Object 类。这是因为 AppClassLoader 在加载你的 Object 类时,会委托给 ExtClassLoader 去加载,而ExtClassLoader 又会委托给 BootstrapClassLoader,BootstrapClassLoader 发现自己已经加载过了 Object 类,会直接返回,不会去加载你写的 Object 类。

你可能感兴趣的:(Java虚拟机(JVM),jvm)