- 1、invokeinterface:调用接口中的方法,实际上是在运行期决定的,决定到底调用实现该接口的那个对象的特定方法。4
- 2、invokestatic : 调用静态方法
- 3、invokespecial: 调用自己的私有方法,构造方法()以及父类的方法。
- 4、invokevirtual: 调用虚方法,运行期动态查找的过程。
- 5、invokedynamic: 动态调用方法。
invokestatic
写一段调用invokestatic 的代码:
1 2 3 4 5 6 7 8 9
| public class MyTest4 { public static void test(){ System.out.println("test invoked"); }
public static void main(String[] args) { test(); } }
|
打开jclasslib可以看到main方法会有invokestatic 的调用:
方法的静态分派(invokevirtual )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class MyTest5 { //方法的重载是一种静态的行为,在编译期就可以完全确定。 public void test(GrandPa grandPa){ System.out.println("grandpa"); }
public void test(Father father){ System.out.println("father"); }
public void test(Son son){ System.out.println("son"); }
public static void main(String[] args) { GrandPa grandPa1 = new Father(); GrandPa grandPa2 = new Son(); MyTest5 myTest5 = new MyTest5(); myTest5.test(grandPa1); myTest5.test(grandPa2); }
}
class GrandPa{
}
class Father extends GrandPa{
}
class Son extends Father{
}
|
运行结果:
- GrandPa g1 = new Father();
- 以上代码,g1的静态类型是Gandpa,而g1的实际类型(真正指向的类型)是Father。调用test方法的时候会根据g1的静态类型(Gandpa)去寻找重载的具体的方法。
- 我们可以得出这样的结论:变量的静态类型是不会发生变化的,而变量的实际类型则是可以发生变化的(多态的一种体现),实际类型是在运行期方可确定。
看一下main方法的字节码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 0 new #7 <com/twodragonlake/jvm/bytecode/Father> 3 dup 4 invokespecial #8 <com/twodragonlake/jvm/bytecode/Father.<init>> 7 astore_1 8 new #9 <com/twodragonlake/jvm/bytecode/Son> 11 dup 12 invokespecial #10 <com/twodragonlake/jvm/bytecode/Son.<init>> 15 astore_2 16 new #11 <com/twodragonlake/jvm/bytecode/MyTest5> 19 dup 20 invokespecial #12 <com/twodragonlake/jvm/bytecode/MyTest5.<init>> 23 astore_3 24 aload_3 25 aload_1 26 invokevirtual #13 <com/twodragonlake/jvm/bytecode/MyTest5.test> 29 aload_3 30 aload_2 31 invokevirtual #13 <com/twodragonlake/jvm/bytecode/MyTest5.test> 34 return
|
可以看到2个 test方法的调用使用的是invokevirtual 指令。