深入理解JVM(学习过程) (20)

image-20200214064208939

image-20200214064251773

image-20200214064341107

LineNumberTable 是 字节码和源代码对应的行号

image-20200214070640848

LocalVariableTabel 是 对于局部变量的存储信息

image-20200214070737725

StackMapTable 是针对于安全的。

image-20200214064803780

ByteCode内容:

image-20200214065328559

goto 语句是发生异常的时候进行跳转到catch的位置。

Exception table 信息:

image-20200214065509512

最后的一个any来说,是处理所有上边不可能处理的异常。是字节码生成的时候帮助我们生成的。

字节码的运行机制 字节码基础概念 栈帧(stack frame)

栈帧是由栈和帧组合而成的概念。

栈帧一种用于帮助虚拟机执行方法调用与方法执行的数据结构。他是独立于线程的,一个线程有自己的一个栈帧。不存在并发的情况。

栈帧本是一种数据结构,封装了方法的局部变量表、动态链接信息、方法的返回地址以及操作数栈等信息。

java中的引入的概念:符号引用:直接引用。

有些符号引用是在类加载阶段或是第一次使用时就会转换成直接引用,这种转换叫做静态解析;

另外一些符号引用则是在每次运行期转换为直接引用,这种转换叫做动态链接,这种体检为Java的多态性。

如: Animal a = new Cat();

a.sleep(); //实际上应该调用Cat()的sleep();

a = new Dog();

a.sleep(); //实际上应该调用Dog()的sleep();

a = new Tiger();

a.sleep(); //实际上应该调用Tiger()的sleep();

但是在程序编译的时候,字节码能看到的是 a调用的都是Animal的sleep();

应用了invokevirtual的概念。

入栈,出栈

image-20200214072043992

结合上图,我用文字描述一下两个概念。看自己能否理解。

首先将2和3压入栈中。现在要做一个减法,3-2 。 需要先把2从栈中取出,3也从栈中取出,做完减法后,把1压入栈中。

局部变量表的概念(slot) //slot 为栈帧中的一个个小格,上图中的一个三角区域。 public void test(){ int a = 3; if (a<4){ int b = 4; int c = 5; } int d = 7; } // slot是可以复用的。方法体中声明的局部变量。 // 因为方法体本身又可以存在更小的作用域。 // 所以一个方法中有10个变量,可能使用7个8个slot,也可能使用10个slot。 invoke 的概念(调用)

invokeinterface : 调用接口中的方法,实际上是在运行期决定的,决定到底调用实现该接口的哪个对象的特定方法。

invokestatic : 调用静态方法。

invokespecial : 调用自己的私有方法、构造方法()以及父类的方法。

invokevirtual : 调用虚方法、运行期动态查找的过程。

Invokedynamic: 动态调用方法。

/** 静态解析的4种情形: (字节码还没有运行的时候,就已经能够确定调用哪个方法) 1. 静态方法 2. 父类方法 3. 构造方法 4. 私有方法(无法被重写) 以上4类方法称为非虚方法,他们是在类加载阶段就可以将符号引用转换成直接引用。 */ public class MyTest4{ public static void test(){ sout(); } public static void main(String[] args){ test(); } } 方法重载(方法的静态分派机制) /** 方法的静态分派 Grandpa g1 = new Father(); G1的静态类型是Grandpa,而g1的实际类型(真正指向的类型)是Father。 我们可以得到这样一个结论:变量的静态类型是不会发生变化的,而变量的实例类型是可以发生变化的(多态的一种实现),实例类型是在运行期方可确定。 */ public class MyTest5{ // 方法重载,是一种静态的行为,编译器就可以完全确定。 public void test(Grandpa grandpa){ System.out.println("Grandpa"); } public void test(Father father){ System.out.println("Father"); } public void test(Son son){ System.out.println("Son"); } public static void main(String[] args){ Grandpa g1 = new Father(); Grandpa g2 = new Son(); MyTest5 mytest5 = new MyTest5(); mytest5.test(g1); // 实例调用的时候,获取到的参数的类型是获取到实例的静态类型。所有都是Grandpa mytest5.test(g2); } } class Grandpa{} class Father extends Grandpa{} class Son extends Father{} > Task :MyTest5.main() Grandpa Grandpa

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfdfy.html