在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有:

1、通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件)。而获取的方式,可以通过jar包、war包、网络中获取、JSP文件生成等方式。

2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。这里只是转化了数据结构,并未合并数据。(方法区就是用来存放已被加载的类信息,常量,静态变量,编译后的代码的运行时内存区域)

3、在内存中生成一个代表这个类的Java.lang.Class对象,作为方法区这个类的各种数据的访问入口。这个Class对象并没有规定是在Java堆内存中,它比较特殊,虽为对象,但存放在方法区中。

其中,实现第一个工作的代码块就被称为“类加载器”。

类加载器的作用不仅仅是实现类的加载,它还与类的的“相等”判定有关,关系着Java“相等”判定方法的返回结果,只有在满足如下三个类“相等”判定条件,才能判定两个类相等。

1、两个类来自同一个Class文件

2、两个类是由同一个虚拟机加载

3、两个类是由同一个类加载器加载

Java“相等”判定相关方法:

1、判断两个实例对象的引用是否指向内存中同一个实例对象,使用 Class对象的equals()方法,obj1.equals(obj2);
2、判断实例对象是否为某个类、接口或其子类、子接口的实例对象,使用Class对象的isInstance()方法,class.isInstance(obj);

3、判断实例对象是否为某个类、接口的实例,使用instanceof关键字,obj instanceof class;
4、判断一个类是否为另一个类本身或其子类、子接口,可以使用Class对象的isAssignableFrom()方法,class1.isAssignableFrom(class2)。

JVM类加载器分类详解:

1、Bootstrap ClassLoader:启动类加载器,也叫根类加载器,它负责加载Java的核心类库,加载如(%JAVA_HOME%/lib)目录下的rt.jar(包含System、String这样的核心类)这样的核心类库。根类加载器非常特殊,它不是java.lang.ClassLoader的子类,它是JVM自身内部由C/C++实现的,并不是Java实现的。

2、Extension ClassLoader:扩展类加载器,它负责加载扩展目录(%JAVA_HOME%/jre/lib/ext)下的jar包,用户可以把自己开发的类打包成jar包放在这个目录下即可扩展核心类以外的新功能。

3、System ClassLoader\APP ClassLoader:系统类加载器或称为应用程序类加载器,是加载CLASSPATH环境变量所指定的jar包与类路径。一般来说,用户自定义的类就是由APP ClassLoader加载的。

各种类加载器间关系:以组合关系复用父类加载器的父子关系,注意,这里的父子关系并不是以继承关系实现的。

  1. //验证类加载器与类加载器间的父子关系
  2. public static void main(String[] args) throws Exception{
  3. //获取系统/应用类加载器
  4. ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
  5. System.out.println("系统/应用类加载器:" + appClassLoader);
  6. //获取系统/应用类加载器的父类加载器,得到扩展类加载器
  7. ClassLoader extcClassLoader = appClassLoader.getParent();
  8. System.out.println("扩展类加载器" + extcClassLoader);
  9. System.out.println("扩展类加载器的加载路径:" + System.getProperty("java.ext.dirs"));
  10. //获取扩展类加载器的父加载器,但因根类加载器并不是用Java实现的所以不能获取
  11. System.out.println("扩展类的父类加载器:" + extcClassLoader.getParent());
  12. }
  13. }

类加载器的双亲委派加载机制(重点):当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。

这个过程如下图标号过程所示:

双亲委派模型的源码实现:

主要体现在ClassLoader的loadClass()方法中,思路很简单:先检查是否已经被加载过,若没有加载则调用父类加载器的loadClass()方法,若父类加载器为空则默认使用启动类加载器作为父类加载器。如果父类加载器加载失败,抛出ClassNotFoundException异常后,调用自己的findClass()方法进行加载。

  1. public Class<?> loadClass(String name) throws ClassNotFoundException {
  2. return loadClass(name, false);
  3. }
  4. protected synchronized Class<?> loadClass(String name, boolean resolve)
  5. throws ClassNotFoundException
  6. {
  7. // First, check if the class has already been loaded
  8. Class c = findLoadedClass(name);
  9. if (c == null) {
  10. try {
  11. if (parent != null) {
  12. c = parent.loadClass(name, false);
  13. } else {
  14. c = findBootstrapClassOrNull(name);
  15. }
  16. } catch (ClassNotFoundException e) {
  17. // ClassNotFoundException thrown if class not found
  18. // from the non-null parent class loader
  19. }
  20. if (c == null) {
  21. // If still not found, then invoke findClass in order
  22. // to find the class.
  23. c = findClass(name);
  24. }
  25. }
  26. if (resolve) {
  27. resolveClass(c);
  28. }
  29. return c;
  30. }

下面看一个简单的双亲委派模型代码实例验证

  1. public class ClassLoaderTest {
  2. public static void main(String[] args){
  3. //输出ClassLoaderText的类加载器名称
  4. System.out.println("ClassLoaderText类的加载器的名称:"+ClassLoaderTest.class.getClassLoader().getClass().getName());
  5. System.out.println("System类的加载器的名称:"+System.class.getClassLoader());
  6. System.out.println("List类的加载器的名称:"+List.class.getClassLoader());
  7. ClassLoader cl = ClassLoaderTest.class.getClassLoader();
  8. while(cl != null){
  9. System.out.print(cl.getClass().getName()+"->");
  10. cl = cl.getParent();
  11. }
  12. System.out.println(cl);
  13. }

输出结果为:

解释一下:

1、ClassLoaderTest类是用户定义的类,位于CLASSPATH下,由系统/应用程序类加载器加载。

2、System类与List类都属于Java核心类,由祖先类启动类加载器加载,而启动类加载器是在JVM内部通过C/C++实现的,并不是Java,自然也就不能继承ClassLoader类,自然就不能输出其名称。

3、而箭头项代表的就是类加载的流程,层级委托,从祖先类加载器开始,直到系统/应用程序类加载器处才被加载。

那么我们做个测试,把类打成jar包,拷贝入%JAVA_HOME%/jre/lib/ext目录下,再次运行ClassLoaderTest类

解释一下,因为类的Jar包放到了ExtClassLoader的加载目录下,所以在根目录找不到相应类后,在ExtClassLoader处就完成了类加载,而忽略了APPClassLoader阶段。

上一篇:JVM类加载机制详解(一)JVM类加载过程

(未完待续,下一篇:自定义的类加载器)

JVM类加载机制详解(二)类加载器与双亲委派模型的更多相关文章

  1. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  2. 类文件的结构、JVM 的类加载过程、类加载机制、类加载器、双亲委派模型

    一.类文件的结构 我们都知道,各种不同平台的虚拟机,都支持 "字节码 Byte Code" 这种程序存储格式,这构成了 Java 平台无关性的基石.甚至现在平台无关性也开始演变出 ...

  3. Java虚拟机:类加载机制详解

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 大家知道,我们的Java程序被编译器编译成class文件,在class文件中描述的各种信息,最终都需要加载到虚拟机内存才能运行和使用,那么 ...

  4. 【深入理解JVM】类加载器与双亲委派模型

    原文链接:http://blog.csdn.net/u011080472/article/details/51332866,http://www.cnblogs.com/lanxuezaipiao/p ...

  5. 【深入理解JVM】类加载器与双亲委派模型 (转)

    出处: [深入理解JVM]类加载器与双亲委派模型 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段“加载”过程中,需要通过 ...

  6. 【深入理解JVM】:类加载器与双亲委派模型

    类加载器 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段“加载”过程中,需要通过一个类的全限定名来获取定义此类的二进制字 ...

  7. 深入理解JVM(③)虚拟机的类加载器(双亲委派模型)

    前言 先解释一下什么是类加载器,通过一个类的全限定名来获取描述该类的二进制字节流,在虚拟机中实现这个动作的代码被称为"类加载器(Class Loader)". 类与类加载器 类加载 ...

  8. JVM类加载器以及双亲委派模型

    从java开发人员的角度来看,类加载器可以分为3种: 1.启动类加载器(Bootstrap ClassLoader),负责将存放在<JAVA_HOME>\lib目录中,或者被-Xbootc ...

  9. Java自定义类加载器与双亲委派模型

    其实,双亲委派模型并不复杂.自定义类加载器也不难!随便从网上搜一下就能搜出一大把结果,然后copy一下就能用.但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行.可是自定义类 ...

随机推荐

  1. Kali Linux 下安装中文版输入法

    1.更新软件源: 修改sources.list文件: vim /etc/apt/sources.list 或者 leafpad /etc/apt/sources.list 然后选择添加以下源: deb ...

  2. 初学者浅度剖析eShopOnContainers 里面用到的MediatR .

    一.介绍 简单了解下开源项目 MedatR, eShopOnContainers, MediatR作者Jimmy Bogard : Simple mediator implementation in ...

  3. pandas安装以及出现的问题

    pandas安装以及出现的问题 1.pandas 安装 pandas是Python的第三方库,所以使用前需要安装一下,直接使用pip install pandas就会自动安装,安装成功后显示的以下的信 ...

  4. CSS盒模型 flex

    用于网页布局,PC的话,兼容性不够,慎用,手机端的话,神器 整理部分通用的,可以直接复制的,省得下次再写一遍 注意,设为 Flex 布局以后,子元素的float.clear和vertical-alig ...

  5. php_package v2.7发布了 宋正河作品

    php_package 是一个面向过程的底层开发框架 http://download.csdn.net/download/songzhengdong82/4974123 欢迎大家下载

  6. Datawhale MySQL 训练营 Task2 查询语句

    目录 MySQL 管理 MySQL 用户管理 参考 数据库管理 SQ查询语句 1. 导入示例数据库,教程 MySQL导入示例数据库 2. 查询语句 SELECT 3. 筛选语句 WHERE ,过滤 4 ...

  7. UVa 10055

    说一下犯错的地方: 1)没有注意数据范围,题目中是The input numbers are not greater than balabalabala. 而这个32位的int类型恰好装不下2^32, ...

  8. iOS中使用RNCryptor对资源文件加密(先加密后拖进项目中)

    概述:IPA 在发布时,业务相关的敏感资源文件以明文的形式存储,由于没有加密保护,这些文件在应用发布后 可能被其他人获取,并结合其他漏洞和手段产生真实攻击.所以我们要 1.在设计.开发阶段,集合业务确 ...

  9. CocoaPods :为iOS程序提供依赖管理的工具(yoowei)

    修改于:2016.11.18   2017.1.10  2019.01.31 CocoaPods 源码 : https://github.com/CocoaPods/CocoaPods CocoaPo ...

  10. PHP使用Memcache来存储session 其他【转载】

    PHP使用Memcache来存储session 分类:PHP 时间:2015年3月30日 很多时候一个完整的系统可能运行在多个服务器上,如果这多个服务器之间需要共享session的话,那么PHP默认的 ...