保证任何时候操作数栈的数据类型和指令代码序列都能配合工作(例如在操作栈上有一个int类型的数据,保证不会在使用的时候按照long类型来加载到本地变量表中)
跳转指令不会条状到方法体以外的字节码指令上
保证方法体中的数据转换是有效的,例如可以把一个子类对象赋值给父类数据类型,但是不能把父类赋值给子类数据类型
符号引用验证: 针对符号引用转换直接引用的时候,这个装换工作会在第三阶段(字节码验证)解析阶段中发生。主要是保证引用一定会被访问到,不会出现类无法访问的问题。
1.2 准备为类变量 分配内存并设置类变量初始值的阶段,这些变量所使用的内存都会在方法区进行分配,在准备阶段是把class文件静态变量赋默认值,注意:不是赋初始值,比如我们 public static int i = 8 ,在这个步骤 并不是把 i 赋值成8 ,而是先赋值为0
基本类型的默认值:
数据类型 默认值int 0
long 0L
short (short)0
char '\u0000'
byte (byte)0
boolean false
float 0.0f
double 0.0d
reference null
在通常情况下初始值是0,但是如果我们把上面的常量加一个final 类修饰的话,那么这个时候初始值就会编程我们指定的值 public static final int i = 8
编译的时候Javac会把i的初始值变为8,
把class文件常量池里面用到的符号引用转换为直接内存地址,直接可以访问到的内容
符号引用:以一组符号来描述所引用的目标,符号可以是任何字面形式的字面量,只要不会出现冲突能够定位到就可以
直接引用:可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄,如果有了直接引用,那引用的目标必定已经在内存中存在了
初始化是给类的静态变量赋正确的初始值,刚才我们有讲到准备阶段是复制默认值,而初始化是给静态变量赋值初始值,看下面的语句:
public static int i = 8
首先字节码文件被加载到内存后,先进行连接验证,通过准备阶段,给i分配内存,因为是static,所以这个时候i 等于int类型的默认初始值是0,所以i 现在是 0,到了初始化的时候,才会真正把i 赋值为8
类加载器类加载器负责加载所有的类,并且为载入内存中的类生成一个 java.lang.Class实例对象,如果一个类被加载到JVM中后,同一个类不会再次被载入,就像对象有一个唯一的标识,同样载入的JVM的类也有一个唯一的标识。JVM本身有一个类加载器的层次,这个类加载器本身就是一个普通的Class,所有的Class都是被类加载器加载到内存中,我们可以称之为ClassLoader,一个顶级的父类,也是一个abstract抽象类。
Bootstrap: 类加载器的加载过程,分成不同的层次来进行加载,不同的类加载器加载不同的Class,作为最顶层的Bootstrap,它加载lib里JDK最核心的内容,比如说rt.jar charset.jar等核心类,当我们调用getClassLoader()拿到这个加载器结果是一个Null的时候,代表我们已经达到了最顶层的加载器
Extension: Extension加载器扩展类,加载扩展包里的各种各样的文件,这些扩展包在JDK安装目录 jre/lib/ext下的jar
App: 就是我们平时用到的application ,用来加载classpath指定的内容
Custom ClassLoader: 自定义ClassLoader,加载自己自定义的加载器 Custom ClassLoader 的父类加载器是 application 的父类加载器是 Extension的父类加载器是Bootstrap
注意:他们不是继承关系,而是委托关系
public class ClassLoaderTest { public static void main(String[] args) { // 查看是谁Load到内存的,执行结果是null,因为Bootstrap使用C++实现的 // 在Java里面没有class和它对应 System.out.println(String.class.getClassLoader()); //这个是核心类库某个包里的类执行,执行结果是Null,因为该类也是被Bootstrap加载的 System.out.println(sun.awt.HKSCS.class.getClassLoader()); //这个类是位于ext目录下某个jar文件里面,当我们调用他执行结果就是sun.misc.Launcher$ExtClassLoader@a09ee92 System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader()); // 这个是我们自己写的ClassLoad加载器,由sun.misc.Launcher$AppClassLoader@18b4aac2加载 System.out.println(ClassLoaderTest.class.getClassLoader()); // 是Exe的ClassLoader 调用它的getclass(),它本身也是一个class,调用它的getClassLoader,他的ClassLoader的ClassLoader就是我们的Bootstrap所以结果为Null System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader().getClass().getClassLoader()); } }