类加载完整流程
1.加载
“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一一个阶段,希望读者没有混淆这两个看起来很相似的名词。在加载阶段,Java虛拟机需要完成以下三件事情:
- 1)通过一个类的全限定名来获取定义此类的二进制字节流。
- 2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
类被加载到方法区中后主要包含运行时常量池、类型信息、字段信息、方法信息、类加载器的 引用、对应class实例的引用等信息。 类加载器的引用:这个类到类加载器实例的引用对应class实例的引用:类加载器在加载类信息放到方法区中后,会创建一个对应的Class 类型的 对象实例放到堆(Heap)中, 作为开发人员访问方法区中类定义的入口和切入点。
Java类的加载过程_Java类-IT乾坤技术博客 (itqiankun.com)
- 简洁来说
- 一个Java文件从编码完成到最终执行,一般主要包括两个过程:编译和运行,其中编译就是把我们写好的java文件,通过javac命令编译成字节码,也就是我们常说的.class文件,然后运行则是把编译声称的.class文件交给Java虚拟机(JVM)执行。而我们所说的类加载过程即是JVM虚拟机把.class文件中类信息加载进内存,并将数据转换成方法区中的运行时数据(静态变量、静态代码块、常量池等),类加载器在加载类信息放到方法区中后,会创建一个对应的Class 类型的 对象实例放到堆(Heap)中, 作为开发人员访问方法区中类定义的入口和切入点。
- 举个通俗点的例子来说,JVM在执行某段代码时,遇到了Class A, 然而此时内存中并没有Class A的相关信息,于是JVM就会到相应的Class文件中去寻找class A的类信息,并加载进内存中,这就是我们所说的类加载过程。由此可见,JVM不是一开始就把所有的类都加载进内存中,而是只有第一次遇到某个需要运行的类时才会加载,且只加载一次。
2.连接
2.1验证
验证的目的
主要是为了保证加载进来的字节流符合虚拟机规范,不会造成安全错误。 |
验证做的具体内容
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:
1.文件格式验证:验证字节流是否符合Class文件格式的规范; |
2.2准备
在准备阶段,为静态变量的初值为jvm默认的初值,而不是我们在程序中设定的初值。jvm默认为静态变量的初值是这样的
1.静态变量是基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0 |
2.3解析
这一阶段的任务就是把常量池中的符号引用转换为直接引用
什么是符号引用,什么是直接引用?
1.符号引用:即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。 |
3.初始化阶段
类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:
– 创建类的实例,也就是new的方式 |
初始化顺序
1)如果这个类还没有被加载和链接,那先进行加载和链接
2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
3)加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。
4)总的来说,初始化顺序依次是:(静态变量、静态初始化块)–>(变量、初始化块)–> 构造器;
如果有父类,则顺序是:父类static方法 –> 子类static方法 –> 父类构造方法- -> 子类构造方法
详细过程: