java虚拟机(二)--类加载机制和双亲委派模型
一、类的生命周期
加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)
七个阶段,加载(装载)、验证、准备、初始化和卸载这五个阶段顺序是固定的,类的加载过程必须按照这种顺序开始
验证、准备、解析统称为连接阶段。连接阶段主要的目的是确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟
机自身安全。
1.1、加载:
1、通过类的全限定名获取定义此类的二进制流
2、将二进制流中的静态存储结构转化为方法区的运行时数据结构
3、内存中生成一个代表此类的java.lang.class对象,作为方法区这个类的各种数据的访问入口
内存中实例化一个java.lang.Class对象(并没有明确规定是在java堆中,对于HotSpot,Class对象比较特殊,虽然是对象,但是存放在方法区中)
1.2、验证:
主要是四个检验过程:文件格式验证、元数据验证、字节码验证和符号引用验证。
1.3、准备:
为类变量分配内存并设置类变量初始值(零值),这些变量所使用的内存都在方法区中进行分配
假如一个类变量的定义为:public static int value = 123;
这时候初始值时0而不是123,把value赋值123是在执行putstatic指令后,在初始化阶段进行的,这个指令放到<clinit>方法中。
如果是常量,javac会生成Constantvalue属性,在准备阶段会根据Constantvalue的设置将value赋值为123
1.4、解析:
解析阶段是虚拟机常量池内的符号引用替换为直接引用的过程。
符号引用:
1.类和方法的全限定名
2.字段的名称和描述符
3.方法的名称和描述符。
以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要能定位到目标。和jvm实现的内存布局无关
直接引用:
直接指向目标的指针、相对偏移量或者是间接定位到目标的句柄,和jvm实现的内存布局相关
1.5、初始化:
类的初始化阶段是类加载过程的最后一步,在准备阶段,类变量已赋过一次系统要求的零值,而在初始化阶段,则是根据程序员自定义去初始化
类变量和其他资源,初始化阶段是执行类构造器<clinit>()的过程。
有且只有以下五种情况下初始化过程会被触发执行:
1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需先触发其初始化。生成这4条指令的最
常见的java代码场景是:使用new关键字实例化对象、读取或设置一个类的静态变量(被final修饰、已在编译器把结果放入常量池的静态字段除外)
的时候,以及调用类的静态方法的时候。
2.使用java.lang.reflect包的方法对类进行反射调用的时候
3.当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化
4.jvm启动时,用户指定一个执行的主类(包含main方法的那个类),虚拟机会先初始化这个类
在上面准备阶段 public static int value = 12; 在准备阶段完成后 value的值为0,而在初始化阶调用了类构造器<clinit>()方法,这个阶段完
成后value的值为12。
5.使用JDK1.7动态语言支持的时候,如果一个java.lang.invoke.MethodHandler实例最后的解析结果PEF_getStatic,PEF_putStatic,
PEF_invokeStatic的方法句柄,这个方法句柄对应的类的没有初始化,要出发初始化
二、类加载器:
JVM设计者把类加载的加载阶段中的“通过'类全名'来获取定义此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自
己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。
2.1、双亲委派模型:
从虚拟机的角度来说,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),该类加载器使用C++语言实现,属于虚
拟机自身的一部分。另外一种就是所有其它的类加载器,这些类加载器是由Java语言实现,独立于JVM外部,并且全部继承自抽象类java.lang.
ClassLoader。

2.2、类和类加载器:
对于任何一个类,都需要由加载它的类加载器和这个类来确立其在JVM中的唯一性。也就是说,两个类来源于同一个Class文件,并且被同一个
类加载器加载,这两个类才相等。
从Java开发人员的角度来看,大部分Java程序一般会使用到以下三种系统提供的类加载器:
1)启动类加载器Bootstrap ClassLoader:
负责加载JAVA_HOME\lib目录中并且能被虚拟机识别的类库到JVM内存中,如果名称不符合的类库即使放在lib目录中也不会被加载。该类加载器
无法被Java程序直接引用。
2)扩展类加载器Extension ClassLoader:
该加载器主要是负责加载JAVA_HOME\lib\ext,该加载器可以被开发者直接使用。
3)应用程序类加载器Application ClassLoader:
该类加载器也称为系统类加载器,它负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中
没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
我们的应用程序都是由这三类加载器互相配合进行加载的,我们也可以加入自己定义的类加载器。这些类加载器之间的关系如下图所示:
如上图所示的类加载器之间的这种层次关系,就称为类加载器的双亲委派模型(Parent Delegation Model)。该模型要求除了顶层的启动
类加载器外,其余的类加载器都应当有自己的父类加载器。子类加载器和父类加载器不是以继承(Inheritance)的关系来实现,而是通过组合
(Composition)关系来复用父加载器的代码。
双亲委派模型的工作过程为:
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的加载
器都是如此,因此所有的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有
找到对应的类)时,子加载器才会尝试自己去加载。
2.3、自定义类加载器:
若要实现自定义类加载器,只需要继承java.lang.ClassLoader 类,并且重写其findClass()方法即可。java.lang.ClassLoader 类的基本
职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java类,即java.lang.Class类的一个
实例。除此之外,ClassLoader还负责加载Java应用所需的资源,如图像文件和配置文件等,ClassLoader中与加载类相关的方法如下:
方法 说明
getParent() 返回该类加载器的父类加载器。
loadClass(String name) 加载名称为 二进制名称为name 的类,返回的结果是 java.lang.Class 类的例。
findClass(String name) 查找名称为 name 的类,返回的结果是 java.lang.Class 类的实例。
findLoadedClass(String name) 查找名称为 name 的已经被加载过的类,返回的结果是 java.lang.Class 类的实例。
resolveClass(Class<?> c) 链接指定的 Java 类。
PS:
1、如果不想打破双亲委派模型,那么只需要重写findClass()即可
2、如果想打破双亲委派模型,那么就重写loadClass()
2.5、被动引用:
1、对于静态字段,只有直接定义这个字段的类才会被加载,所以通过子类SubClass.value调用父类SuperClass的value属性,子类不会被加载,
除非在SubClass内部去调用
2、通过数组定义引用类,不会出发这个类的初始化
3、常量在编译的时候就会保存到调用类的常量池中,本质上没有引用定义常量的类,因此不会出发定义常量类的初始化
而接口在初始化的时候,不会要求其父接口的全部init,只有在真正使用父接口的时候(例如引用接口中定义的常量)才会init
加载和连接阶段是交叉进行的
java虚拟机(二)--类加载机制和双亲委派模型的更多相关文章
- Java类加载机制以及双亲委派模型
一.Java类加载机制 1.概述 Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允 ...
- 深入理解JVM(③)虚拟机的类加载器(双亲委派模型)
前言 先解释一下什么是类加载器,通过一个类的全限定名来获取描述该类的二进制字节流,在虚拟机中实现这个动作的代码被称为"类加载器(Class Loader)". 类与类加载器 类加载 ...
- 图解JVM类加载机制和双亲委派模型
我们都知道以 .java 结尾的 Java 源文件,经过编译之后会变成 .class 结尾的字节码文件.JVM 通过类加载器来加载字节码文件,然后再执行程序. 什么时候加载一个类 那么,什么时候类加载 ...
- java虚拟机类加载机制和双亲委派模型
java虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型. 类的生命周期是从类被加载到虚拟机内存中,到卸 ...
- 深入理解java虚拟机(九)类加载器以及双亲委派模型
虚拟机把类加载阶段中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为“类加载器”. 类与类加载器 任 ...
- java 虚拟机的类加载机制
Java 虚拟机的类加载机制 关于类加载机制: 虚拟机把描述类的数据从Class 文件加载到内存,并对数据进行效验.转换解析和初始化,最终 形成可以被虚拟机直接使用的Java 类型,就是虚拟机的类 ...
- 深入理解Java虚拟机(类加载机制)
文章首发于微信公众号:BaronTalk 上一篇文章我们介绍了「类文件结构」,这一篇我们来看看虚拟机是如何加载类的. 我们的源代码经过编译器编译成字节码之后,最终都需要加载到虚拟机之后才能运行.虚拟机 ...
- 类文件的结构、JVM 的类加载过程、类加载机制、类加载器、双亲委派模型
一.类文件的结构 我们都知道,各种不同平台的虚拟机,都支持 "字节码 Byte Code" 这种程序存储格式,这构成了 Java 平台无关性的基石.甚至现在平台无关性也开始演变出 ...
- 深入理解java虚拟机【类加载机制】
Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...
随机推荐
- 怎样在win8系统下建立wifi热点
2012年10月26日,微软正式推出Windows 8操作系统,不少用户也都升级到了最新的Win8.大家知道.在Win7系统下,我们非常方便的就在命令提示符下建立了WIFI热点.那么Win8上是 ...
- kafka 生产者消费者 api接口
生产者 import java.util.Properties; import kafka.javaapi.producer.Producer; import kafka.producer.Keyed ...
- java多线程之 ---- 线程死锁
java多线程之线程死锁 产生死锁的主要原因: 由于系统资源不足. 进程执行推进的顺序不合适. 资源分配不当等. 假设系统资源充足.进程的资源请求都可以得到满足,死锁出现的可能性就非常低.否则就会因争 ...
- java 开发webservice
这几天用java开发一个webservice,搞死了.java果然很难侍候! 传说java搞webservice,有好几种途径(为什么不是一种?要搞这么多种,让人一听,头都大了.当然啦,生物多样性总是 ...
- c#生成AVI自动设置压缩格式,不调用AVISaveOptions
工作中遇到生成AVI视频的项目,代码中会调用AVISaveOptions来设置压缩格式,针对单个文件还好说,但是批量生成视频的时候,每一个都要设置格式, 体验不是很好,经过查询资料问题得到解决 最开始 ...
- jboss相关的术语
1 jboss eap java ee application server.red hat官方版本. 2 jboss as/wildfly java ee application server的社区 ...
- 解决jQuery uploadify在非IE核心浏览器下无法上传
之前上传了一个通过Flash实现多文件上传,但是在IE正常运行,FireFox 不能正常上传.经过反复研究学习,之所以firefox和360浏览器无法正常运行,是因为FireFox.chrome.36 ...
- TI BLE:读本机地址
uint8 ownAddress[B_ADDR_LEN]; //B_ADDR_LEN=6GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress); #def ...
- 给网站添加免费Https SSL证书
基于阿里云的云盾证书服务,系统是centos6.8,web服务器是nginx1.8.0,简单记录下踩坑情况. 申请证书 登录阿里云控制台→安全(云盾)→证书服务→购买证书(https://common ...
- E20170527-ts
asset n. 资产,财产; 有价值的人或物; 有用的东西; 优点; serializer [词典] 串行(化)器(把并行数据变成串行数据的寄存器); 编程语言中,可被序列化的; inflec ...