invokevirtual,invokespecial,invokestatic,invokeinterface
invokevirtual 调用类实例方法,方法引用
栈:
前:。。。,objectref,[arg1,[arg2......]]
后:。。。
invlkestatic 调用类方法,不需要建新建类实例,此时操作数栈只要保存留参数即可
栈:
前:。。。,[arg1,[arg2.....]]
后:。。。
invokespecial 使用对私有方法,超类方法和实例初始化方法的特殊处理来调用实例方法。
栈:
前:。。。,objectref,[arg1,[arg2......]]
后:。。。
invokeinterface 调用接口方法
栈:
前:。。。,objectref,[arg1,[arg2......]]
后:。。。
程序如下:
package yhs.test; public interface Iface { public void test(); } package yhs.test; public class Impl implements Iface { public void test() { } public static void testStatic() { } private void testPrivate() { } //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- public static void main(String[] args) { Impl impl = new Impl(); Iface iface = impl; //热身 int count = 10000000; for (int i = 0; i < count; i++) { impl.test(); impl.testPrivate(); Impl.testStatic(); iface.test(); } //开始测试 count = 100000000; long t1 = System.currentTimeMillis(); for (int i = 0; i < count; i++) { impl.test(); } System.out.println("invokevirtual: " + (System.currentTimeMillis() - t1)); t1 = System.currentTimeMillis(); for (int i = 0; i < count; i++) { impl.testPrivate(); } System.out.println("invokespecial: " + (System.currentTimeMillis() - t1)); t1 = System.currentTimeMillis(); for (int i = 0; i < count; i++) { Impl.testStatic(); } System.out.println("invokestatic: " + (System.currentTimeMillis() - t1)); t1 = System.currentTimeMillis(); for (int i = 0; i < count; i++) { iface.test(); } System.out.println("invokeinterface: " + (System.currentTimeMillis() - t1)); } }
反汇编Impl.class产生的字节码如下:
public class yhs.test.Impl extends java.lang.Object implements yhs.test.Iface{
public yhs.test.Impl();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public void test();
Code:
0: return
public static void testStatic();
Code:
0: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class Impl
3: dup
4: invokespecial #3; //Method "":()V
7: astore_1
8: aload_1
9: astore_2
//---------------------------------------------------------------------------------------------
10: ldc #4; //int 10000000
12: istore_3
13: iconst_0
14: istore 4
16: goto 39
19: aload_1
20: invokevirtual #5; //Method test:()V
23: aload_1
24: invokespecial #6; //Method testPrivate:()V
27: invokestatic #7; //Method testStatic:()V
30: aload_2
31: invokeinterface #8, 1; //InterfaceMethod yhs/test/Iface.test:()V
36: iinc 4, 1
39: iload 4
41: iload_3
42: if_icmplt 19
//---------------------------------------------------------------------------------------------
45: ldc #9; //int 100000000
47: istore_3
48: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
51: lstore 5
53: iconst_0
54: istore 7
56: goto 66
59: aload_1
60: invokevirtual #5; //Method test:()V
63: iinc 7, 1
66: iload 7
68: iload_3
69: if_icmplt 59
72: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
75: new #12; //class StringBuffer
78: dup
79: invokespecial #13; //Method java/lang/StringBuffer."":()V
82: ldc #14; //String invokevirtual:
84: invokevirtual #15; //Method java/lang/StringBuffer.append:(Ljava/lang/
String;)Ljava/lang/StringBuffer;
87: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
90: lload 5
92: lsub
93: invokevirtual #16; //Method java/lang/StringBuffer.append:(J)Ljava/lan
g/StringBuffer;
96: invokevirtual #17; //Method java/lang/StringBuffer.toString:()Ljava/la
ng/String;
99: invokevirtual #18; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
//---------------------------------------------------------------------------------------------
102: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
105: lstore 5
107: iconst_0
108: istore 8
110: goto 120
113: aload_1
114: invokespecial #6; //Method testPrivate:()V
117: iinc 8, 1
120: iload 8
122: iload_3
123: if_icmplt 113
126: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
129: new #12; //class StringBuffer
132: dup
133: invokespecial #13; //Method java/lang/StringBuffer."":()V
136: ldc #19; //String invokespecial:
138: invokevirtual #15; //Method java/lang/StringBuffer.append:(Ljava/lang/
String;)Ljava/lang/StringBuffer;
141: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
144: lload 5
146: lsub
147: invokevirtual #16; //Method java/lang/StringBuffer.append:(J)Ljava/lan
g/StringBuffer;
150: invokevirtual #17; //Method java/lang/StringBuffer.toString:()Ljava/la
ng/String;
153: invokevirtual #18; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
//---------------------------------------------------------------------------------------------
156: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
159: lstore 5
161: iconst_0
162: istore 9
164: goto 173
167: invokestatic #7; //Method testStatic:()V
170: iinc 9, 1
173: iload 9
175: iload_3
176: if_icmplt 167
179: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
182: new #12; //class StringBuffer
185: dup
186: invokespecial #13; //Method java/lang/StringBuffer."":()V
189: ldc #20; //String invokestatic:
191: invokevirtual #15; //Method java/lang/StringBuffer.append:(Ljava/lang/
String;)Ljava/lang/StringBuffer;
194: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
197: lload 5
199: lsub
200: invokevirtual #16; //Method java/lang/StringBuffer.append:(J)Ljava/lan
g/StringBuffer;
203: invokevirtual #17; //Method java/lang/StringBuffer.toString:()Ljava/la
ng/String;
206: invokevirtual #18; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
//---------------------------------------------------------------------------------------------
209: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
212: lstore 5
214: iconst_0
215: istore 10
217: goto 229
220: aload_2
221: invokeinterface #8, 1; //InterfaceMethod yhs/test/Iface.test:()V
226: iinc 10, 1
229: iload 10
231: iload_3
232: if_icmplt 220
235: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
238: new #12; //class StringBuffer
241: dup
242: invokespecial #13; //Method java/lang/StringBuffer."":()V
245: ldc #21; //String invokeinterface:
247: invokevirtual #15; //Method java/lang/StringBuffer.append:(Ljava/lang/
String;)Ljava/lang/StringBuffer;
250: invokestatic #10; //Method java/lang/System.currentTimeMillis:()J
253: lload 5
255: lsub
256: invokevirtual #16; //Method java/lang/StringBuffer.append:(J)Ljava/lan
g/StringBuffer;
259: invokevirtual #17; //Method java/lang/StringBuffer.toString:()Ljava/la
ng/String;
262: invokevirtual #18; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
//---------------------------------------------------------------------------------------------
265: return
}
测试得到类似如下的一组结果:
#1
invokevirtual: 250
invokespecial: 219
invokestatic: 125
invokeinterface: 1062
#2
invokevirtual: 281
invokespecial: 250
invokestatic: 141
invokeinterface: 1078
...
可以看出,静态方法调用最快,而通过接口调用方法最慢(比invokevirtual慢了3-4倍),调用private的方法比调用一般的方法稍快。
调用超类(在现在的jvm spec中与以前的有所不同,不是通过invokespecial来调用)的方法不是很好测试,再想想看。