02.连接:包括验证、准备和解析类的二进制数据;
001.验证:确保被加载类的正确性
当类被加载后,就进入验证阶段。连接就是把已经读入到内存中的类的二进制数据合并到JVM运行时环境中去。连接的第一步是类的验证,其目的是保证被加载的类由正确的内部结构,并且与其他类协调一致。如果JVM检查到错误,那么就会抛出相应的Error对象。
疑问:由Java编译器生成的Java类的二进制数据肯定是正确的,为什么还要进行类的验证呢?

因为JVM不知道某个特定的class文件到底是如何创建的、从哪来的,这个class文件可能是由正常的Java编译器生成的,也有可能是恶意创建的(通过恶意class文件破坏JVM运行时环境),类的验证能提高程序的健壮性,确保程序被安全的执行。
类的验证主要包括以下内容:
类文件的结构检查:确保类文件遵从Java类文件的固定格式。
语义检查:确保类本身符合Java语言的语法规定(例如final类型的类没有子类,final类型的方法没有被覆写)。
字节码验证:确保字节码流可以被JVM安全的执行。字节码流代表Java方法(包括静态方法和实例方法),它是由被称作操作码的单元字节指令组成的序列,每一个操作码后都跟着一个或多个操作数。字节码验证步骤会检查每个操作码是否合法,即是否有着合法的操作数。
二进制兼容的检查:确保相互引用的类之间协调一致。例如在A类的的a方法中调用B类的b方法。JVM在验证A类时,会检查在方法区是否存在B类的b方法,如果不存在(当A类和B类的版本不兼容,就会出现这种问题),就会抛出NoSuchMethodError错误。
002.准备:为类的静态变量分配内存,并将其初始化为默认值
在准备阶段,JVM为类的静态变量分配内存,并设置默认的初始值。例如如下情况:
在准备阶段,将为int类型的静态变量a分配4个字节的内存空间并赋予默认值为0;为long类型的静态变量b分配8个字节的内存空间并赋予默认值0。
003.解析:把类中的符号引用转换成直接引用
在解析阶段,JVM会把二进制数据中的 符号引用替换为直接引用。例如在A类的a方法中调用B
类的b方法。
在A类的二进制数据中,包含了一个对B类b()方法的符号引用,它由b()方法的全名和相关描述组成。在解析阶段,JVM将这个符号引用替换成为一个指针,该指针指向B类b()方法在方法区内的内存位置,这个指针就是直接引用。
03.初始化:给类的静态变量赋予正确的初始值;
在初始化阶段,JVM执行类初始化语句,为类的静态变量赋予初始值。在程序中,静态变量的初始化有两种途径:一是在静态变量的声明处进行初始化;二是在静态代码块中进行初始化。
如下代码,a和b都被显式的初始化,而c没有没显式的初始化,它将报纸默认值0。
在本文中,如果未加特别说明,类的静态变量都是指不能作为 编译时常量的静态变量。Java编译器和虚拟机对 编译时常量有特殊的处理方式,具体可参参考下文中 类的初始化时机。
静态变量的声明语句,以及静态代码块都被看作类初始化语句,JVM会按照初始化语句在类文件中的的书写顺序依次执行它们。
Java虚拟机初始化一个类包含以下步骤:
1.假如这个类还没有被加载和连接,那么先进行加载和连接。
2.假如类中存在直接父类,并且这个父类还没有被初始化,那么就先初始化直接父类。
3.假如类中存在初始化语句,那么就依次执行。
当初始化一个类的直接父类时,也需要重复以上步骤,这会确保当程序主动使用一个类时,这个类以及它的所有父类(包括直接父类和间接父类)都已经被初始化。下面程序的输出结果是程序中第一个被初始化的类是Object类。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-87852-2.html
但没人说淘宝卖的都是假的
该忍还是得忍