一、JVM和Java体系结构(17)


8.2、关于指令
JVM字节码指令集一直比较稳定,一直到Java7中才增加了一个指令,这是Java为了实现「动态类型语言」支持而做的一种改进 。
但是在Java7中并没有提供直接生成指令的方法,需要借助ASM这种底层字节码工具来产生指令 。直到Java8的表达式的出现,指令的生成,在Java中才有了直接的生成方式 。
Java7中增加的动态语言类型支持的本质是对Java虚拟机规范的修改,而不是对ava语言规则的修改,这一块相对来讲比较复杂,增加了虚拟机中的方法调用,最直接的受益者就是运行在Java平台的动态语言的编译器 。
动态类型语言和静态类型语言
动态类型语言和静态类型语言两者的区别就在于对类型的检查是在编译期还是在运行期,满足前者就是静态类型语言,反之是动态类型语言 。
说的再直白一点就是,静态类型语言是判断变量自身的类型信息;动态类型语言是判断变量值的类型信息,变量没有类型信息,变量值才有类型信息,这是动态语言的一个重要特征 。
这句话的意思是,静态类型语言在编译时就会确定变量的数据类型,而且变量的类型信息是固定的,无法改变 。而动态类型语言在运行时才会确定变量的数据类型,变量的类型信息是根据变量的值来确定的,可以随时改变 。因此,静态类型语言需要在编译时进行类型检查,而动态类型语言则可以在运行时进行类型检查 。
package com.lxg.java2;/*** 体会invokedynamic指令* @author shkstart* @create 2020 下午 3:09*/@FunctionalInterfaceinterface Func {public boolean func(String str);}public class Lambda {public void lambda(Func func) {return;}public static void main(String[] args) {Lambda lambda = new Lambda();Func func = s -> {return true;};lambda.lambda(func);lambda.lambda(s -> {return true;});}}
8.3、方法重写的本质
Java语言中方法重写的本质:
1.找到操作数栈顶的第一个元素所执行的对象的实际类型,记作C 。
2.如果在类型C中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果不通过,则返回
java.1ang.异常 。
3.否则,按照继承关系从下往上依次对C的各个父类进行第2步的搜素和验证过程 。
4.如果始终没有找到合适的方法,则抛出java.lang..异常 。
介绍:
程序试图访问或修改一个属性或调用一个方法,这个属性或方法,你没有权限访问 。一般的,这个会引起编译器异常 。这个错误如果发生在运行时,就说明一个类发生了不兼容的改变 。
8.4、虚方法表
在面向对象的编程中,会很频繁的使用到动态分派,如果在每次动态分派的过程中都要重新在类的方法元数据中搜索合适的目际的话就可能影响到执行效率 。因此,为了提高性能,JVM采用在类的方法区建立一个虚方法表(table)(非虚方法不会出现在表中)来实现 。使用索引表来代替查找 。
每个类中都有一个虚方法表,表中存放着各个方法的实际入口 。
那么虚方法表什么时候被创建?
例子1:
例子2:
可卡犬
package com.lxg.java3;/*** 虚方法表的举例** @author shkstart* @create 2020 下午 1:11*/interface Friendly {void sayHello();void sayGoodbye();}class Dog {public void sayHello() {}public String toString() {return "Dog";}}class Cat implements Friendly {public void eat() {}public void sayHello() {}public void sayGoodbye() {}protected void finalize() {}public String toString(){return "Cat";}}class CockerSpaniel extends Dog implements Friendly {public void sayHello() {super.sayHello();}public void sayGoodbye() {}}public class VirtualMethodTable {}