Java 类加载器及其双亲委派机制

目录

 

一、类加载器是什么

二、类的加载过程(双亲委派机制)

为什么要设计这种模式?


一、类加载器是什么

Java是运行在Java的虚拟机(JVM)中的,但是它是怎么就运行在JVM中了呢?我们在IDE中编写的Java源代码被编译器编译成.class的字节码文件。然后由我们得ClassLoader(类加载器)负责将这些class文件加载到JVM中去执行。  

JVM中提供了三层的ClassLoader:

每种类加载器负责加载的类都不同

  • Bootstrap classLoader(引导类加载器):主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。

  • ExtClassLoader(扩展类加载器):主要负责加载Java的扩展库,如jre/lib/ext目录下的一些扩展的jar。

  • AppClassLoader(应用类加载器):主要负责加载应用程序的主函数类或者自己写的类

通过一个小小的例子来看看,主函数类的是否真的通过AppClassLoader加载

public class HelloWorld{
    public static void main(String[] args){
            HelloWorld h = new HelloWorld();
            Class<?> c = h.getClass(); //获取HelloWorld的类文件
            /*下面语句输出://jdk.internal.loader.ClassLoaders$AppClassLoader@2f0e140b,看到AppClassLoader了没有~*/
            System.out.println(c.getClassLoader());
        }
}

除了JVM提供的ClassLoader(类加载器),用户还能自己创建加载器(例如叫CustomClassLoader)。

注意:一个类加载器只要加载过一个类,类加载器在成功加载某个类之后,会把得到的 java.lang.Class 类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。

 

二、类的加载过程(双亲委派机制)

当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

例如现在要加载一个 Car.class 类,具体过程如下图:

先检查在CustomClassLoader有没有加载过,如果有,就不需要再加载了,如果没有就往上到ExtClassLoader(扩展类加载器)处检测,同样的流程,到BootStrapClassLoader如果还是没发现加载过这个Car.class,就从BootStrapClassLoader看看是否可以找到这个类并加载,若没有就到ExtClassLoader处找,如果到CustomerClassLoader(这表示用户自己写的类加载器,平时不一定存在)都没找到Car.class可以加载,就抛出classNotFound异常。

为什么要设计这种模式?

这种设计有个好处是,如果有人想替换系统级别的类:String.java。篡改它的实现,但是在这种机制下这些系统的类已经被Bootstrap classLoader加载过了,所以并不会再去加载,从一定程度上防止了危险代码的植入。

在JVM中,辨别两个类是否属于是同一个类并非仅仅通过类的全名,而是通过类的全名+加载这个类的类加载器  来确定的。如果不是这种双亲委派的模式,所有类都可以通过不同的加载器加载,那么就算两个类的字节码完全相同,也会被JVM标识成不同的两个类,那么这两个类就不能进行互相赋值等操作,会抛出运行时异常 ClassCastException 。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值