前言
语雀地址:https://www.yuque.com/yangxiaofei-vquku/wmp1zm/dmz2gd验证(Verify)
目的:验证的目的是保证.class文件的字节流中信息符合当前虚拟机的要求,保证加载类的正起行,不会危害虚拟机的自身安全。
验证大体分为四步格式检查、语义检查、字节码验证、符号引用验证,验证阶段并不是单独存在的模块,验证阶段穿插在加载和解析阶段之中完成。
- 其中格式检查会在加载阶段穿插执行,只有通过格式认证的字节码才会被加载到方法区
- 格式验证之外的其他验证都在方法区完成,验证阶段虽然拖慢了加载速度,但是避免了字节码在运行时还需要各种检查,磨刀不误砍柴工。
- 符号引用验证是在解析步骤时完成,如果验证时发现符号引用不存在直接引用,会出现NoClassDefFoundError或者NoSuchMethodError异常。
准备(Prepare)
- 为类变量分配内存,并设置其默认值,即零值
- 为static final修饰的且在常量池中有字面量引用的静态常量赋初始值即常量池中的字面量恒定值
- 此过程不会为实例变量赋值,实例变量是在实例创建时通过构造方法赋值的,和实例一起保存在堆栈。(当然类变量也在堆里,报存在Class里)
- 在整个准备阶段都不会设计代码的运行(初始化就会运行方法)。
解析(Resolve)
- 将类常量池中部分类、接口、方法、字段的符号引用转换成直接引用
静态链接和动态链接
上面这句突出了"部分"二字,是因为解析过程并不会将全部符合引用都替换成直接引用。解析又成静态链接,与其相对是动态链接作用都是将常量池中的符号引用替换为直接引用,动态链接是栈桢的一部分,"栈管运行,堆管存储"既然是栈桢的一部分那动态链接生效的时机就是在方法运行的时候。
- 静态链接(解析):编译期能确定的符号引用会被转换为直接引用,如果符号引用对应的直接引用不存在在类加载时就会包错。
- 动态链接:由于java支持多态子类可以实现和重写接口或父类中的方法,而为了降低代码的耦合性面向接口编程是必不可少的,所以很多方法在编译期无法确定其真正的直接引用,所以才有了动态链接,在运行时动态获取其方法的直接引用。所以如果一行代码采用动态链接方式获取直接引用,只要这行代码不执行即便此行代码对应的常量池符号引用无直接引用也不会抛出错误。
在java中有字节码中的常量池、运行时常量池、字符串常量池好三种常量池,这里的常量池指的又是什么呢?可以看下java的常量池。