您的位置:首页 > 编程语言 > Java开发

Java字节码中invokespecial与invokevirtual指令的解析

2015-08-08 14:24 232 查看
1.invokespecial只能调用三类方法:<init>方法;私有方法;super.method()。因为这三类方法的调用对象在编译时就可以确定。

2.invokevirtual是一种动态分派的调用指令:也就是引用的类型并不能决定方法属于哪个类型。

看如下代码:

public class SubClass1 extends SuperClass{
public static void main(String[] args){
SubClass1 sb = new SubClass1();
sb.commMethod();
}
}


SubClass1的引用sb调用了commMethod方法,这个方法实际来自于SuperClass,我们将这段代码编译成字节码后是

Compiled from "SubClass1.java"

public class com.csii.parent.SubClass1 extends com.csii.parent.SuperClass

SourceFile: "SubClass1.java"

minor version: 0

major version: 50

Constant pool:

const #1 = class #2;// com/csii/parent/SubClass1

const #2 = Asciz com/csii/parent/SubClass1;

const #3 = class #4;// com/csii/parent/SuperClass

const #4 = Asciz com/csii/parent/SuperClass;

const #5 = Asciz <init>;

const #6 = Asciz ()V;

const #7 = Asciz Code;

const #8 = Method #3.#9;// com/csii/parent/SuperClass."<init>":()V

const #9 = NameAndType #5:#6;// "<init>":()V

const #10 = Asciz LineNumberTable;

const #11 = Asciz LocalVariableTable;

const #12 = Asciz this;

const #13 = Asciz Lcom/csii/parent/SubClass1;;

const #14 = Asciz main;

const #15 = Asciz ([Ljava/lang/String;)V;

const #16 = Method #1.#9;// com/csii/parent/SubClass1."<init>":()V

const #17 = Method#1.#18;
// com/csii/parent/SubClass1.commMethod:()V

const #18 = NameAndType #19:#6;// commMethod:()V

const #19 = Asciz commMethod;

const #20 = Asciz args;

const #21 = Asciz [Ljava/lang/String;;

const #22 = Asciz sb;

const #23 = Asciz SourceFile;

const #24 = Asciz SubClass1.java;

{

public com.csii.parent.SubClass1();

Code:

Stack=1, Locals=1, Args_size=1

0: aload_0

1: invokespecial#8; //Method com/csii/parent/SuperClass."<init>":()V

4: return

LineNumberTable:

line 3: 0

LocalVariableTable:

Start Length Slot Name Signature

0 5 0 this Lcom/csii/parent/SubClass1;

public static void main(java.lang.String[]);

Code:

Stack=2, Locals=2, Args_size=1

0: new
#1; //class com/csii/parent/SubClass1

3: dup

4: invokespecial#16; //Method "<init>":()V

7: astore_1

8: aload_1

9: invokevirtual#17; //Method commMethod:()V

12: return

LineNumberTable:

line 9: 0

line 10: 8

line 11: 12

LocalVariableTable:

Start Length Slot Name Signature

0 13 0 args [Ljava/lang/String;

8 5 1 sb Lcom/csii/parent/SubClass1;

}

可以看到引用sb.commMethod()编译后的字节码命令是invokevirtual,而字节码中调用方法也是com/csii/parent/SubClass1.commMethod:()V。没错,编译后字节码中显示它调用了子类的commMethod()方法,虚拟机运行这段代码时会动态绑定到SuperClass的commMethod方法上。

以上是子类继承并直接调用父类方法时编译的结果。若采用super.method()调用父类方法编译后将会采用invokespecial,这样执行的效率将会高一点。

另外,通过接口的引用调用方法时也会使用invokevirtual。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: