Java虚拟机JVM学习05 类加载器的父委托机制

类加载器

  类加载器用来把类加载到Java虚拟机中。

类加载器的类型

  有两种类型的类加载器:

  1.JVM自带的加载器:

    根类加载器(Bootstrap)

    扩展类加载器(Extension)

    系统类加载器(System)

  2.用户自定义的类加载器:

    java.lang.ClassLoader的子类,用户可以定制类的加载方式。

JVM自带的加载器

  Java虚拟机自带了以下几种加载器。

  1.根(Bootstrap)类加载器:

  该加载器没有父加载器

  它负责加载虚拟机的核心类库,如java.lang.*等。

  根类加载器从系统属性sun.boot.class.path所指定的目录中加载类库。

  根类加载器的实现依赖于底层操作系统,属于虚拟机的实现的一部分,它并没有继承java.lang.ClassLoader类,它是用C++写的。

  2.扩展(Extension)类加载器:

  它的父加载器为根类加载器。

  它从java.ext.dirs系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre\lib\ext子目录(扩展目录)下加载类库,如果把用户创建的JAR文件放在这个目录下,也会自动由扩展类加载器加载。

  扩展类加载器是纯Java类,是java.lang.ClassLoader类的子类。

  3.系统(System)类加载器:

  也称为应用类加载器,它的父加载器为扩展类加载器

  它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,它是用户自定义的类加载器的默认父加载器

  系统类加载器是纯Java类,是java.lang.ClassLoader类的子类。

  注意:这里的父加载器概念并不是指类的继承关系,子加载器不一定继承了父加载器(其实是组合的关系)。

用户自定义类加载器

  除了以上虚拟机自带的类加载器以外,用户还可以定制自己的类加载器(User-defined Class Loader)。

  Java提供了抽象类java.lang.ClassLoader,所有用户自定义的类加载器都应该继承ClassLoader类。

类加载的父委托机制

  从JDK 1.2版本开始,类的加载过程采用父亲委托机制,这种机制能更好地保证Java平台的安全。

  在父委托机制中,除了Java虚拟机自带的根类加载器以外,其余的类加载器都有且只有一个父加载器,各个加载器按照父子关系形成了树形结构。

  当Java程序请求加载器loader1加载Sample类时,loader1首先委托自己的父加载器去加载Sample类,若父加载器能加载,则由父加载器完成加载任务,否则才由loader1本身加载Sample类。

  说明具体过程的一个例子:

  loader2首先从自己的命名空间中查找Sample类是否已经被加载,如果已经加载,就直接返回代表Sample类的Class对象的引用。

  如果Sample类还没有被加载,loader2首先请求loader1代为加载,loader1再请求系统类加载器代为加载,系统类加载器再请求扩展类加载器代为加载,扩展类加载器再请求根类加载器代为加载。

  若根类加载器和扩展类加载器都不能加载,则系统类加载器尝试加载,若能加载成功,则将Sample类所对应的Class对象的引用返回给loader1,loader1再返回给loader2,从而成功将Sample类加载进虚拟机。

  若系统加载器不能加载Sample类,则loader1尝试加载Sample类,若loader1也不能成功加载,则loader2尝试加载。

  若所有的父加载器及loader2本身都不能加载,则抛出ClassNotFoundException异常。

  总结下来就是:

  每个加载器都优先尝试用父类加载,若父类不能加载则自己尝试加载;若成功则返回Class对象给子类,若失败则告诉子类让子类自己加载。所有都失败则抛出异常。

定义类加载器和初始类加载器

  若有一个类加载器能成功加载Sample类,那么这个类加载器被称为定义类加载器。

  所有能成功返回Class对象的引用的类加载器(包括定义类加载器,即包括定义类加载器和它下面的所有子加载器)都被称为初始类加载器

  假设loader1实际加载了Sample类,则loader1为Sample类的定义类加载器,loader2和loader1为Sample类的初始类加载器。

父子关系

  需要指出的是,加载器之间的父子关系实际上指的是加载器对象之间的包装关系,而不是类之间的继承关系。

  一对父子加载器可能是同一个加载器类的两个实例,也可能不是。

  在子加载器对象中包装了一个父加载器对象。

  例如loader1和loader2都是MyClassLoader类的实例,并且loader2包装了loader1,loader1是loader2的父加载器。

  当生成一个自定义的类加载器实例时,如果没有指定它的父加载器(ClassLoader构造方法无参数),那么系统类加载器就将成为该类加载器的父加载器。

父委托机制优点

  父亲委托机制的优点是能够提高软件系统的安全性

  因为在此机制下,用户自定义的类加载器不可能加载应该由父加载器加载的可靠类,从而防止不可靠甚至恶意的代码代替由父加载器加载的可靠代码。

  例如,java.lang.Object类总是由根类加载器加载,其他任何用户自定义的类加载器都不可能加载含有恶意代码的java.lang.Object类。

命名空间

  每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成。

  在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类。

  在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类。

运行时包

  由同一类加载器加载的属于相同包的类组成了运行时包

  决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看定义类加载器是否相同。

  只有属于同一运行时包的类才能互相访问包可见(即默认访问级别)的类和类成员。

  这样的限制能避免用户自定义的类冒充核心类库的类,去访问核心类库的包可见成员。

  假设用户自己定义了一个类java.lang.Spy,并由用户自定义的类加载器加载,由于java.lang.Spy和核心类库java.lang.*由不同的类加载器加载,它们属于不同的运行时包,所以java.lang.Spy不能访问核心类库java.lang包中的包可见成员。

参考资料

  圣思园张龙老师Java SE系列视频教程。

Java虚拟机JVM学习05 类加载器的父委托机制的更多相关文章

  1. JVM中类加载器的父委托机制

    类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap) 扩展类加载器(Extension) 系统类加载器 ...

  2. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  3. Java虚拟机JVM学习07 类的卸载机制

    Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...

  4. Java虚拟机JVM学习02 类的加载概述

    Java虚拟机JVM学习02 类的加载概述 类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对 ...

  5. Java虚拟机JVM学习01 流程概述

    Java虚拟机JVM学习01 流程概述 Java虚拟机与程序的生命周期 一个运行时的Java虚拟机(JVM)负责运行一个Java程序. 当启动一个Java程序时,一个虚拟机实例诞生:当程序关闭退出,这 ...

  6. JVM学习笔记——类加载器与类加载过程

    类加载器与类加载过程 类加载器ClassLoader 类加载器 ClassLoader 用于把 class 文件装载进内存. 启动类加载器(Bootstrap ClassLoader): 这个类加载使 ...

  7. Java虚拟机JVM学习04 类的初始化

    Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始 ...

  8. Java虚拟机JVM学习03 连接过程:验证、准备、解析

    Java虚拟机JVM学习03 连接过程:验证.准备.解析 类被加载后,就进入连接阶段. 连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去. 连接阶段三个步骤:验证.准备和解析. 类 ...

  9. JVM 类加载器的双亲委托机制

    1.类加载器的层次结构 在双亲委托机制中,各个加载器按照父子关系形成了树形结构(逻辑意义),除了根加载器之外,其余的类加载器都有且只有一个父加载器. public class MyTest13 { p ...

随机推荐

  1. MySQL(Navicat)运行.sql文件时报错:[Err] 2006 - MySQL server has gone away 的解决方法

    背景: 今天导入一个数据量很大的.sql文件时,报错: 原因: 可能是sql语句过长,超过mysql通信缓存区最大长度. 解决:1. 编辑 MySQL 安装目录下的 my.ini,在最后添加以下内容: ...

  2. 使用 SQL 命令 OPTIMIZE TABLE 释放表空间

    前提: 1.删除了表的一大部分: 2.已经对含有可变长度行的表(含有VARCHAR, BLOB或TEXT列的表)进行了很多更改. ----------------------------------- ...

  3. java Class对象

    目录 1Class对象 普通的Class对象 泛化的Class对象 2类型转换前先做检查 instanceof 运算符的陷阱 Class.isInstance() 3反射 动态代理     1.Cla ...

  4. WCF实现方法重载

    一.服务契约(包括回调契约)通过指定不同的OperationContract.Name来实现重载方法,当然代码部份还是必需符合C#的重载要求,即相同方法名称,不同的参数个数或参数类型 namespac ...

  5. CentOS上安装SQL Server vNext CTP1

    今天微软正式发布上SQL Server 2016 SP1,根据以往的SP1定律,可以在生产环境上使用了.打了SP1的标准版将具有企业版几乎所有的的功能.只有RAM 超过128GB或者超过24核心或者超 ...

  6. 用Qt写软件系列五:一个安全防护软件的制作(2)

    引言 在上一篇中讲述了主窗体的创建和设计.主窗体的无边框效果.阴影效果.拖动事件处理.窗体美化等工作在前面的博客中早就涉及,因此上篇博文中并未花费过多笔墨.这一篇继续讲述工具箱(Tool Button ...

  7. 年薪10w和年薪100w的人,差在哪里?

    职场10年,为什么有人已经当上了董事总经理,而有的人还是资深销售经理? 出道10年,为什么有人已经当上了主编.出版人,而有的人还是资深编辑? 打拼10年,为什么有人已经身价数十亿美金,而有的人还在为竞 ...

  8. IBM和传统IT的沦落

    传统IT厂商沦落已经成为一种趋势.不仅仅是在中国去IOE的大背景下,在全球范围内,这些曾经盛极一时的IT大鳄也在衰落.作为一个在IBM服务了将近14年的老员工,我想浅谈一下IBM以及整个传统IT行业的 ...

  9. 根据日期查询access数据库

    获取指定日期的记录 1.select Field1 from  A  where format("yyyy-MM-dd",Field1)=#2011-10-07# 有时不能获取记录 ...

  10. 【UWP】FlipView绑定ItemsSource,Selectedindex的问题

    最近在做列表头部的Carousel展示,Carousel使用的是FlipView展示,另外使用ListBox显示当前页,如下图 我们先设置一个绑定的数据源 public class GlobalRes ...