《深入理解Java虚拟机》书中原文写到:
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接(Dynamic Linking)。通过第六章的讲解,我们知道Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析。另一部分将在每一次运行期间都转化为直接引用,这部分就被称为动态链接。
也就是说,当一个方法被调用的时候,例如invokestatic #2 这样的命令,需要将#2所代表的方法压入栈,通过动态链接找到运行时常量池中具体是哪个对象的该方法。
《深入理解Java虚拟机》中举了一个这样的例子:
Human man = new Man();
我们将上面代码中的“Human”称为变量的“静态类型”(Static Type),或者叫“外观类型”(Apparent Type),后面的“Man”则被称为变量的“实际类型”(Actual Type)或者叫“运行时类型”(Runtime Type)。静态类型和实际类型在程序中都可能会发生变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会改变,并且最终的静态类型是在编译期可知的;而实际类型变化的结果在运行期间才可以确定,编译器在编译程序的时候并不知道一个对象的实际类型是什么。譬如有一下的代码:
// 实际类型变化
Human human = (new Random()).nextBoolean() ? new Man : new Woman();
// 静态类型变化
sr.sayHello((Man) human);
sr.sayHello((Woman) human);
通过上述的例子,我们可以知道,虽然方法在编译的时候可以知道一些静态信息,但是具体执行的方法是什么样的需要在具体执行的时候才能够确定。推测压入栈的只是方法的静态信息,具体执行的方法需要通过动态链接握持的指针来具体的确定。