Java字节码中invokespecial与invokevirtual指令的解析
2015-08-08 14:24
232 查看
1.invokespecial只能调用三类方法:<init>方法;私有方法;super.method()。因为这三类方法的调用对象在编译时就可以确定。
2.invokevirtual是一种动态分派的调用指令:也就是引用的类型并不能决定方法属于哪个类型。
看如下代码:
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。
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。
相关文章推荐
- JavaEE入境后在做什么——公共入口疑问的答案
- 用户输入验证
- Spring MVC常用的注解
- springmvc+hibernate的一个简单实例
- java实现文件上传与下载
- java生成txt
- java中获取一天当中的毫秒数
- JAVA异常之spring 4.2.0兼容asm报.ClassVisitor as super clas
- Java自带排序方法
- 怎样修改项目jdk和web版本
- JavaStep --- 2. 变量
- Spring Mvc 4 HelloWord
- Hibernate HQL查询异常:java.lang.ClassCastException解决
- MyBatis补充
- Genymotion模拟器连接Eclipse的总结[转]
- JAVA内存区域
- JAVA实现EXCEL公式专题(三)——四则表达式解析
- springMVC静态资源访问和responsebody中文乱码问题
- NIO(JDK1.4)--通道
- JAVA实现EXCEL公式专题(二)——反射解析EXCEL函数