类加载器和双亲委派模型
一、类加载器 ClassLoader 概述
类加载器主要负责加载 class
文件,class 文件在文件开头有特定的文件标识,将 class
文件字节码内容加载到内存中,并将这些内容转换成方法区中运行时数据结构并且 ClassLoader
只负责 class 文件加载,至于它是否可以运行,则由 Execution Engine
决定。
解释一下上图:
首先我们开发好一个类叫 Car.java
,类写好之后经过 javac
编译之后变成 Car.class
。这个时候我们需要把这个 class
文件加载到内存中,这个文件才能起作用。
怎么加载?谁来加载?
这个就是 ClassLoader
要做的事情,类加载器 ClassLoader
会把 Car.class
文件加载到内存中并且初始化,初始化好了之后,你就相当于有了一个 Car 的模板,就可以通过这个初始化好的模板去 new 一个一个的 Car
实例。
因此这一个一个 Car
的实例,我通过 getClass()
方法,就可以知道它的模板是什么,即:知道这个实例对象具体是什么类型的。
同样,我知道了这个 Car
的模板,然后我通过 getClassLoader()
方法,就可以知道它的类加载器是什么。它是通过什么类加载器完成加载的。
综上,这个类加载器的主要作用就是把 class
文件加载进 JVM
内存中。加载完成之后,至于怎么运行,由Execution Engine
决定。
二、类加载器的种类
虚拟机自带加载器
启动类加载器(
Bootstrap
)C++
编写去加载
rt.jar
包下jdk
出厂就带的类扩展类加载器(
Extension
)Java 编写Java 1995 年诞生,不可能把所有东西都想全,后面添加新功能就在扩展包下添加,然后由扩展类加载器来进行加载
应用程序类加载器(
AppClassLoader
):也叫系统类加载器,加载当前应用的classpath
的所有类
用户自定义加载器: java.lang.classLoader
的子类,用户可以定制类的加载方式,只要继承 ClassLoader
这个类就可以了
三、双亲委派模型
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求,都应该传送到启动类中加载,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的 Class
)子类加载器才会尝试自己去加载。
采用双亲委派的一个好处就是,比如加载 rt.jar
包中的类 java.lang.Object
,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同一个 Object
对象。
解释一下上面这幅图:
JDK 自带的三个类加载器,分别有他们自己的作用(加载范围)。
Bootstrap ClassLoader
:主要负责加载$JavaHome/jre/lib/rt.jar
这个目录下的jar
包,他是根加载器,rt.jar
也是 java 运行时必须要的jar
包。比如java.lang.Object
这个类就是在rt.jar
包中的。Extension ClassLoader
:主要负责加载$JavaHome/jre/lib/ext/*.jar
这个目录下的jar
包,JDK 在设计之初不可能把所有需要内置的一些类都想要,后面版本迭代过程中,需要新增的一些东西就放在这个扩展包目录下。这个扩展类加载器就负责把扩展目录下的所有 jar 包加载到 JVM 内存中。System ClassLoader
:主要负责加载classpath
下的所有类。
双亲委派模型的主要意思就是,比如我写一个 Hello.java
类,这个类应该由系统类加载器来进行加载,但是一开始并不会由系统类加载器来加载,当收到加载请求的时候,它会把加载请求往上跑,看父类能不能加载,父类能加载就由父类去加载,父类不能加载就再继续往上跑,如果最终反馈都不能加载的时候,才由子类加载器进行加载。
好处就是不会破坏 JDK 设计的沙箱安全机制。
除了写文章还会更新视频,每天在视频号给你分享一个提升效率的小工具,感兴趣的可以关注一下哦
👇 👇 👇 👇
版权声明: 本文为 InfoQ 作者【hepingfly】的原创文章。
原文链接:【http://xie.infoq.cn/article/4f18b59b379743e515bae73a4】。文章转载请联系作者。
评论 (2 条评论)