JVM之类加载过程(二)

来源:互联网 发布:手机掌上贵金属软件 编辑:程序博客网 时间:2024/05/29 19:41

上篇介绍了类的加载过程第一个阶段,加载阶段。下面将对后面几个阶段一 一分析。

验证阶段

验证阶段主要验证下几点:
1. 类文件结构的检查
2. 语义的检查
3. 字节码的验证
4. 二进制兼容性的验证
类文件结构的检查:确保类文件遵循Java类文件的格式规范,不能是
语义的检查:确保类本身符合java语言的语法固定, 比如验证final类型的类是否有子类,以及final类型的方法没有被覆盖
字节码的验证:确保字节码流可以被虚拟机安全的执行。字节码流代表Java方法(静态方法和实例方法),主要是看看逻辑上有没有错误,比如有一个跳转指令跳到了方法的外部这种。
二进制兼容性的验证:确保相互引用的类协调一致,例如在Work类的gotoWork()方法中会调用Car类的run()方法。JAVA虚拟机在验证Work类会检查方法区内是否存在Car类的run方法。假如不存在,则会抛出NoSuchMethodError错误。

准备阶段

准备阶段,Java虚拟机为类的静态变量分配内存,并设置为默认的初始值,假如对于下面的Demo类,在准备阶段,将int类型的静态变量a分配4个字节的内存空间,并且赋予默认值0,为long类型的静态变量将其分配为8个字节的内存空间,并且赋值默认为0.

public class Demo {    public  static  int a=1;//准备阶段赋值为0,主动调用->初始化赋值为1    public static long b;//准备阶段赋值为0    static {        b=2;    }}

解析阶段

在解析阶段,Java虚拟机会把二进制数据中的符号引用替换为直接引用,例如在Work中的gotoWork()方法中会引用Car类的run方法:

public void gotoWork(){car.run();//这段代码在Work类的二进制数据中表示为符号引用}

在Work类的二进制数据中,包含了一个队Car类的run方法的符号引用,它由run方法的全名和相关描述组成。在解析阶段,Java虚拟机会把这个符号引用替换为一个指针,该指针指向Car类的run方法在方法区的内存地址,这个指针就是直接引用。

初始化阶段

在初始化阶段,首先了解一下Java程序对类的使用方式可以分为两种:


  • 主动使用
  • 被动使用
    主动使用情况有如下几种:
    1.创建类的实例
    2.访问某个类或者接口的静态变量,或者对该静态变量进行赋值
    3.访问类的静态方法
    4.反射(Class.forName(“com.qianyi.Demo”))
    5.初始化一个类的子类
    6.java虚拟机启动时被表明为启动类如常见的main启动
    所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用才初始化他们。也就是符合以上6种情况之后才去初始化类。

除了以上6种情况,都算是被动使用

public class Demo {    public  static  int a=1;//准备阶段赋值为0,主动调用->初始化赋值为1    public static long b;//准备阶段赋值为0    static {        b=2;    }}

对于这个Demo类,如果调用Demo.a,属于主动使用,这个时候类才开始进行进行初始化,初始化时将b=2的值赋值给b,将a的值由默认值0变为1.
后面的文章找几个例子进行演示类的加载工程

原创粉丝点击