参考如下三篇并整理。

1.Java类加载机制详解

2.深入理解Java:类加载机制及反射

3.jvm系列(一):java类的加载机制

类的生命周期是从被加载到虚拟机内存中开始,到卸载出内存结束。过程共有七个阶段。

1.加载---2.验证---3.准备---3.解析---5.初始化---6.使用---7.卸载

     |________连接________| 

|______________类的加载过程_____________|

|______________________类的生命周期_______________________|

其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。

在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。

另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。


【1.加载(装载)】

在装载阶段,虚拟机需要完成以下3件事情
(1) 通过一个类的全限定名来获取定义此类的二进制字节流。
(2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
(3) 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。
虚拟机规范中并没有准确说明二进制字节流应该从哪里获取以及怎样获取,这里可以通过定义自己的类加载器去控制字节流的获取方式。

这里第1条中的二进制字节流并不只是单纯地从Class文件中获取,比如它还可以从Jar包中获取、从网络中获取(最典型的应用便Applet)、由其他文件生成(JSP应用)等。

相对于类加载的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。

【2.验证(校验、检查)】

  虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有害的字节流而导致系统奔溃。

  1.文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
  2.元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
  3.字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  4.符号引用验证:确保解析动作能正确执行。
  验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,

  那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

【3.准备】————为类的静态变量分配内存,并将其初始化为默认值

这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。

1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中。

2、这里设置的初始值,通常是指数据类型的‘“零”值。

  public static int value = 123;

  value在准备阶段过后的初始值为0而不是123,而把value赋值的putstatic指令将在初始化阶段才会被执行。

  注意:

  (1)对基本数据类型来说,对于类变量(static)和全局变量,如果不显式地对其赋值而直接使用,则系统会为其赋予默认的零值。

  (2)对基本数据类型来说,对于局部变量来说,在使用前必须显式地为其赋值,否则编译时不通过。

  (3)对于同时被static和final修饰的常量,必须在声明的时候就为其显式地赋值,否则编译时不通过;

  (4)只被final修饰的常量则既可以在声明时显式地赋值,也可以在类初始化时显式地为其赋值,总之,在使用前必须为其显式地赋值,系统不会为其赋予默认零值。

  (5)对于引用数据类型reference来说,如数组引用、对象引用等,如果没有对其进行显式地赋值而直接使用,系统都会为其赋予默认的零值,即null。

  (6)如果在数组初始化时没有对数组中的各元素赋值,那么其中的元素将根据对应的数据类型而被赋予默认的零值。

3、static final常量在准备阶段变量value就会被初始化为ConstValue属性所指定的值,将其结果放入了调用它的类的常量池中。

  public static final int value = 3;

  编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。

下表列出了Java中所有基本数据类型以及reference类型的默认零值:

【4.解析】————把类中的符号引用转换为直接引用

  解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

  符号引用就是一组符号来描述目标,可以是任何字面量。

  直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

   1、类或接口的解析:判断所要转化成的直接引用是对数组类型,还是普通的对象类型的引用,从而进行不同的解析。
    2、字段解析:对字段进行解析时,会先在本类中查找是否包含有简单名称和字段描述符都与目标相匹配的字段,如果有,则查找结束;
如果没有,则会按照继承关系从上往下递归搜索该类所实现的各个接口和它们的父接口,还没有,则按照继承关系从上往下递归搜索其父类,直至查找结束,查找流程如下图所示:
  3、类方法解析:对类方法的解析与对字段解析的搜索步骤差不多,只是多了判断该方法所处的是类还是接口的步骤,而且对类方法的匹配搜索,是先搜索父类,再搜索接口。
     4、接口方法解析:与类方法解析步骤类似,知识接口不会有父类,因此,只递归向上搜索父接口就行了。

【5.初始化】

  详细见此

   类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下(四大种)六小种:

  【1】在如下三个场景(能生成四个字节码指令的场景),如果类还未初始化,则初始化。

        (4个指令【new、getstatic、putstatic、invokestatic】)

   A.new

      new Test();

   B.读取或设置类的静态变量      

      int b=Test.a;Test.a=b;

   C.调用静态函数

      Test.doSomething();

  【2】反射调用。

      Class.forName(“com.mengdd.Test”);

  【3】子类初始化,要先初始化父类(所有父类)。

  【4】虚拟机启动时,要初始化主类。直接使用java.exe命令来运行某个主类。

   只有上述四种情况会触发初始化,也称为对一个类进行主动引用。

   除此以外,有其他方式都不会触发初始化,称为被动引用。

注意:

(1)子类引用父类的静态变量,不会导致子类初始化。

(2)通过数组定义引用类,不会触发此类的初始化

(3)引用常量时,不会触发该类的初始化

举例:

(1)子类引用父类的静态变量,不会导致子类初始化。

public class SupClass
{public static int a = 123;static{System.out.println("supclass init");}
}public class SubClass extends SupClass
{static{System.out.println("subclass init");}
}public class Test
{public static void main(String[] args){System.out.println(SubClass.a);}
}

执行结果:

supclass init
123

(2)通过数组定义引用类,不会触发此类的初始化

public class SupClass
{public static int a = 123;static{System.out.println("supclass init");}
}public class Test
{public static void main(String[] args){SupClass[] spc = new SupClass[10];}
}

执行结果:

 

(3)引用常量时,不会触发该类的初始化

public class ConstClass
{public static final String A=  "MIGU";static{System.out.println("ConstCLass init");}
}public class TestMain
{public static void main(String[] args){System.out.println(ConstClass.A);}
}

执行结果:

MIGU

用final修饰某个类变量时,它的值在编译时就已经确定好放入常量池了,所以在访问该类变量时,等于直接从常量池中获取,并没有初始化该类。

初始化的步骤

1、如果该类还没有加载和连接,则程序先加载该类并连接。

2、如果该类的直接父类没有加载,则先初始化其直接父类。

3、如果类中有初始化语句,则系统依次执行这些初始化语句。

在第二个步骤中,如果直接父类又有直接父类,则系统会再次重复这三个步骤来初始化这个父类,

依次类推,JVM最先初始化的总是java.lang.Object类。

当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。

【6.使用】

【7.卸载】

  在如下几种情况下,Java虚拟机将结束生命周期

  1.执行了System.exit()方法

  2.程序正常执行结束

  3.程序在执行过程中遇到了异常或错误而异常终止

  4.由于操作系统出现错误而导致Java虚拟机进程终止

转载于:https://www.cnblogs.com/CESC4/p/8037858.html

【JVM】类的生命周期【转+整理】相关推荐

  1. java反射 数组类,乐字节Java反射之三:方法、数组、类加载器和类的生命周期

    继续讲述Java反射之三:方法.数组.类加载器 一.方法 获取所有方法(包括父类或接口),使用Method即可. public static void test() throwsException { ...

  2. java 内存类_Java学习——类的生命周期和内存

    常识是本能,有足够的常识便是天才.--肖伯纳 一.类的生命周期 类的生命周期:1.加载:将二进制流加载进来.class 2.连接: 验证:确保加载进来的数据不会损害虚拟机 准备:为类变量分配内存,附默 ...

  3. Java 类的生命周期详解

    一. 引 言 最近有位细心的朋友在阅读笔者的文章时,对Java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大 ...

  4. 详解java类的生命周期

    引言 最近有位细心的朋友在阅读笔者的文章时,对Java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告 ...

  5. 28 Java类的加载机制、什么是类的加载、类的生命周期、加载:查找并加载类的二进制数据、连接、初始化、类加载器、双亲委派模型、自定义类加载器

    28Java类的加载机制 28.1.什么是类的加载 28.2.类的生命周期 28.2.1.加载:查找并加载类的二进制数据 28.2.2.连接 28.2.3.初始化 28.3.类加载器 28.4.类的加 ...

  6. 详解java类的生命周期 .

    引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告 ...

  7. Android生命周期帮助类,Android Service类与生命周期详细介绍_Android_脚本之家

    Android  Service类与生命周期 Service是Android四大组件与Activity最相似的组件,都代表可执行的程序,区别在于Service一直在后台运行且没有用户界面. 1.Ser ...

  8. Java程序员从笨鸟到菜鸟之(九十四)深入java虚拟机(三)——类的生命周期(下)类的初始化...

    上接深入java虚拟机--深入java虚拟机(二)--类加载器详解(上),在上一篇文章中,我们讲解了类的生命周期的加载和连接,这一篇我们接着上面往下看. 类的初始化:在类的生命周期执行完加载和连接之后 ...

  9. 尚硅谷2020最新版宋红康JVM教程-中篇-第3章类的加载过程(类的生命周期)详解-4-过程三:Initialization(初始化)阶段

    static与final的搭配问题 初始化阶段,简言之,为类的静态变量赋予正确的初始值. 具体描述 类的初始化是类装载的最后一个阶段.如果前面的步骤都没有问题,那么表示类可以顺利装载到系统中.此时,类 ...

最新文章

  1. find name 模糊匹配_Linux的文件搜索命令(locate ,find,grep,find命令和)
  2. 最新批量***dedecms|dedecms最新0day
  3. java通过抛异常来返回提示信息
  4. SQL Server查询正在执行的存储过程并停止
  5. 「博客之星」评选,互投5星,留链必投
  6. 安装XDS110驱动时系统找不到指定文件
  7. shell脚本实现菜单操作
  8. 使用ld的wrap选项替换已有库函数
  9. Arch Linux下 让MPlayer用上CoreAVC1.7.0.0解码器
  10. window.onload和DOMContentLoaded的区别
  11. matlab实现简单图形的识别二
  12. 【iOS】指纹(面容)支付基本逻辑和适配
  13. Java实现 蓝桥杯 历届试题 波动数列
  14. 计算笔记本电脑PPI的JavaScript小工具
  15. java获取参数上的注解_java-如何获取带注释的方法参数及其注释
  16. OracleDBA精选面试题
  17. 【第1398期】一文读懂前端缓存
  18. iWebShop 电商项目实战001----测试环境搭建(上)
  19. wodot技术客服支持
  20. dockerfile制作自定义字体的java环境镜像

热门文章

  1. python调用dll函数_关于从加载的DLL调用函数的Python基本问题
  2. Spring Boot 实用开发技巧————Eclipse 远程调试
  3. 一篇搞懂HTTP协议
  4. java应用程序多态_java – 多态和n层应用程序
  5. ubuntu 中 ROS 一些报错的解决
  6. STM32-独立看门狗原理-实验
  7. php解密 eval( base64_decode,PHP之eval(gzinflate(base64_decode加密解密
  8. 前端实现图片悬浮_悬浮图片之上效果实现
  9. python惰性求值的特点_C#教程之C#函数式编程中的惰性求值详解
  10. java 数据库外键查询_oracle中查询所有外键引用到某张表的记录