一、类的生命周期

  加载(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虚拟机(二)--类加载机制和双亲委派模型的更多相关文章

  1. Java类加载机制以及双亲委派模型

    一.Java类加载机制 1.概述 Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允 ...

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

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

  3. 图解JVM类加载机制和双亲委派模型

    我们都知道以 .java 结尾的 Java 源文件,经过编译之后会变成 .class 结尾的字节码文件.JVM 通过类加载器来加载字节码文件,然后再执行程序. 什么时候加载一个类 那么,什么时候类加载 ...

  4. java虚拟机类加载机制和双亲委派模型

    java虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型. 类的生命周期是从类被加载到虚拟机内存中,到卸 ...

  5. 深入理解java虚拟机(九)类加载器以及双亲委派模型

    虚拟机把类加载阶段中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为“类加载器”. 类与类加载器 任 ...

  6. java 虚拟机的类加载机制

    Java 虚拟机的类加载机制 关于类加载机制: ​ 虚拟机把描述类的数据从Class 文件加载到内存,并对数据进行效验.转换解析和初始化,最终 形成可以被虚拟机直接使用的Java 类型,就是虚拟机的类 ...

  7. 深入理解Java虚拟机(类加载机制)

    文章首发于微信公众号:BaronTalk 上一篇文章我们介绍了「类文件结构」,这一篇我们来看看虚拟机是如何加载类的. 我们的源代码经过编译器编译成字节码之后,最终都需要加载到虚拟机之后才能运行.虚拟机 ...

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

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

  9. 深入理解java虚拟机【类加载机制】

    Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...

随机推荐

  1. Nginx + FastCgi + Spawn-fcgi + C 架构的server环境搭建

    1.Nginx 1.1.安装 Nginx 的中文维基 http://wiki.codemongers.com/NginxChs 下载 Nginx 0.6.26(开发版)(请下载最新版本号) tar z ...

  2. iOS tableview cell 的展开收缩

    iOS tableview cell 的展开收缩 #import "ViewController.h" @interface ViewController ()<UITabl ...

  3. centOS的联网问题

    centOS连接了一个下午,没连上网络,隔了两天,又试了一下午才把网连上,一直查centOS的网络连接问题都搞不定,最后还是问了朋友怎么给虚拟机联网谈到虚拟网卡的问题.建议可以看看网络适配器,VMwa ...

  4. 第一章:Android系统介绍android虚拟机

    学习android,我们是要了解他的历史的,这里我也就不在累述什么大家都知道的东东了,简单的介绍下内部的相关内容: 1:android虚拟机 我们学习java知道java用的是JVM虚拟机,而开发An ...

  5. 用Swift语言和Sprite Kit复制微信飞机大战游戏

    先上GitHub链接: https://github.com/songrotek/PlaneWar.git 接下来略微解说一下! 这个程序还有点Bug,见谅! 1 说明 游戏採用了Sprite kit ...

  6. 将JSON对象转换成IList,好用linq

    JObject JToken JProperty IList<> 搞得头都大了,记而备忘: JObject json = ..... JToken[] jps = json["r ...

  7. 关于Time Series Database

    今天观察了下clojure之父datomic.com的数据库 有点类似sequence数据库的变种 不过这类数据库,感觉用在移动端会更有市场: 1. 移动端需要这种可以本地存储,无删除,联网只增加,只 ...

  8. Create schema error (unknown database schema '')

    Andrey Devyatka 4 years ago Permalink Raw Message Hi,Please tell me, can I use the static library in ...

  9. 【174】C#添加非默认字体

    参考:C# WinForm程序安装字体或直接调用非注册字体 参考:百度知道 在Debug文件夹下面新建一个font的文件夹,然后将字体的文件复制到里面,使用的时候,直接调用字体文件! private ...

  10. Rails 插入代码与注释

    醉了醉了,在原来那个表格最后加了然后更新博客,然后最后写的内容就没了.来来回回试了n次都一样.不得已新开一个    插入代码  <% ... %>  打印值  <%= ... %&g ...