转载自AJAVA:http://ajava.org/readbook/java/bcys/17186.html
方法绑定(method binding)指产生调用方法的内存地址、相关参数和本地变量的处理过程。在执行调用时,JVM根据这些信息,能够执行内存地址中代表该方法的代码。因为构造器是一种特殊方法,方法绑定当然包括构造器绑定。前面提到过,Java提供两种方法绑定,即静态绑定和动态绑定。静态绑定发生在编译期间,由编译器完成;而动态绑定发生在运行期间,由JVM完成。
因为静态绑定在编译期间完成,可以提高代码的执行速度。因而在一般情况下,凡是能够在编译期间解决地址引用的方法调用,都采用静态绑定。静态绑定的方法包括:
● 静态方法。
● 构造器。
● 私有方法。
● 用关键字super调用的方法,包括使用super()调用超类构造器和super.superMethod()调用超类方法。
为了提高程序的运行速度,考虑在可能的情况下,尽量使用以上方法和方法调用。
Java 中,除了以上四种方法外,由对象调用的方法都采用动态绑定。动态绑定在JVM执行代码期间产生,会减慢程序运行速度。但由于Java语言是一种动态链接语言,即所有代码,即使是静态绑定,都或多或少涉及到动态链接和引用,如下面将要讨论的参数装载和堆栈处理,以及invokespecial。这是为什么 Java程序的运行速度比C或者C++慢的主要原因之一。
无论是静态绑定还是动态绑定,在处理调用时,都经历从符号引用(symbolic reference),转换成为直接地址引用,证实合法、装载对象和参数、使用堆栈,这样一个过程。
● 符号引用到直接引用——符号引用提供对方法的识别,包括类名、方法名和方法描述(参数、参数类型、个数,以及返回类型)。在执行绑定操作时,首先根据对方法的识别信息,搜索该方法的储存地址,产生对这个地址的直接引用。直接引用通常包括这个地址的指针,或者地址位移值(offset),使得它允许JVM在执行这个方法时迅速地找到内存位置。
● 证实合法——在绑定处理过程中,还必须验证方法的调用是否遵循Java语言的规定、请求调用指令是否可安全执行、请求调用是否合法。例如,一个私有方法必须由当前执行对象的方法才可调用。如果证实步骤没有通过,JVM将抛出非法调用异常。
● 装载对象和参数——如果是对象方法,对象引用和方法参数必须装载到堆栈;如果是静态方法,只需将参数装入堆栈。因为静态方法将不涉及任何对象。
● 使用堆栈——在调用时,JVM将为执行这个方法产生一个堆栈框(stack frame)。这个堆栈框包括储存本地变量的空间、操作堆栈,以及其他JVM在具体运行时需要的信息。本地变量和操作堆栈需要的字节数在编译期间就已确定,并且已装载到字节码文件中,所以JVM知道需要保留多少储存器空间。在调用过程中,根据不同的运算和操作,JVM对堆栈框执行入栈和出栈的操作。
invokespecial 指静态绑定后,由JVM产生调用的方法。如super(),以及super.someMethod(),都属于invokespecial。而 invokevirtual指动态绑定后由JVM产生调用的方法,如obj.someMethod(),属于invokevirtual。
正是由于这两种绑定的不同,在子类覆盖超类的方法、并向上转型引用后,才产生了多态以及其他特殊的调用结果。运行时,invokespecial选择方法基于引用的类型,而不是对象所属的类。但invokevirtual则选择当前引用的对象。让我们通过具体例子来理解它们的含义和不同:
//这个程序存在本书配套资源目录Ch8名为InvokeTest.java
//demo: invokespecial vs. invokevirtual
class SuperClass5 {
public String method() {
return "from SuperClass5...";
}
public void otherMethod() {
System.out.println("In SuperClass5 otherMethod()...");
//invokespecial例子
System.out.println("SuperClass5 otherMethod() calls method(): " +
method());
}
}
class SubClass5 extends SuperClass5{
public String method() {
return "from SubClass5...";
}
public void subMethod() {
//call SuperClass5 method()
System.out.println("SubClass5 calls super.method(): " +
super.method());
}
}
这个代码的驱动程序如下:
//invokespecial vs. invokevirtual test
public class InvokeTest {
public static void main( String args[] ) {
SubClass5 b = new SubClass5();
SuperClass5 supper = b; //向上转型引用
System.out.println(supper.method());//invokevirtual,当前引用的对象是b
b.subMethod();
b.otherMethod();
}
}
其运行结果为:
from SubClass5...
SubClass5 calls super.method(): from SuperClass5...
In SuperClass5 otherMethod()...
SuperClass5 otherMethod() calls method(): from SubClass5...