一、方法调用指令说明
简要介绍方法调用指令:
invokevirtual、invokeinterface、invokespecial、invokestatic、invokedynamic
简要方法调用介绍
invokevirtual指令
用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),支持多态。
这也是Java语言中最常见的方法分派方式。
invokeinterface指令
用于调用接口方法,它会在运行时搜索由特定对象所实现的这个接口方法,并找出适合的方法进行调用。
invokespecial指令
用于调用一些需要特殊处理的实例方法,包括实例初始化方法(构造器)、私有方法和父类方法
。这些方法都是静态类型绑定的,不会在调用时进行动态派发。
invokestatic指令
用于调用命名类中的类方法(static方法)
。这是静态绑定的。
invokedynamic指令
调用动态绑定的方法,这个是JDK 1.7后新加入的指令。
用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法。前面4条调用指令的分派逻辑都固化在java虚拟机内部,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。
二、通过示例代码来体会方法调用指令
接下来我们通过示例代码拉体会对应的方法指令,看看会有什么不一样?
public class MethodInvokeReturnTest {
//方法调用指令:invokespecial
public void invoke1(){
//情况1:类实例的构造器方法:<init>()
Date date = new Date();
Thread t1 = new Thread();
//情况2:父类的方法
super.toString();
//情况3:私有方法
methodPrivate();
}
private void methodPrivate(){
}
}
接下来我们把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
假如我们将当前私有方法methodPrivate改为public修饰的方法就会发生改变(可重写)
接下来我们通过示例代码拉体会下一个方法指令,看看会有什么不一样?
public class MethodInvokeReturnTest {
//方法调用指令:invokestatic
public void invoke2(){
methodstatic();
}
public static void methodStatic(){
}
}
把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
接下来我们通过示例代码拉体会下一个方法指令,看看会有什么不一样?
public class MethodInvokeReturnTest {
//方法调用指令:invokevirtual
public void invoke4(){
system.out.println( "he1lo");
Thread t1 = null;
t1.run();
}
}
把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
接下来我们通过示例代码拉体会下一个方法指令,看看会有什么不一样?
public class MethodInvokeReturnTest {
//方法调用指令:invokeinterface
public void invoke3(){
Thread t1 = new Thread();
((Runnable)t1).run();
Comparable<Integer> com = null;
com.compareTo(123);
}
}
把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
那么针对于接口里的静态方法与非静态方法,调用之后又会是什么情况呢?
interface AA{
public static void method1(){}
public default void method2(){}
}
class BB implements AA{
}
public class InterfaceMethodTest{
public static void main( string[] args){
AA aa = new BB();
aa.method2();
AA.method1();
}
}
把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
三、通过示例代码来体会方法返回指令
方法调用结束前,需要进行返回。方法返回指令是根据返回值的类型区分的。
当我们返回值是boolean、byte、char、short和int类型采用ireturn表示
当我们返回值是float类型采用freturn表示
当我们返回值是double类型采用dreturn表示
当我们返回值是引用型采用areturn表示
还有一条return指令供声明为void的方法、实例初始化方法以及类和接口的类初始化方法使用。
示例指令讲解
通过ireturn指令,将当前函数操作数栈的顶层元素弹出,并将这个元素压入调用者函数的操作数栈中〈因为调用者非常关心函数的返回值),所有在当前函数操作数栈中的其他元素都会被丢弃。
如果当前返回的是synchronized方法,那么还会执行一个隐含的monitorexit指令,退出临界区
最后,会丢弃当前方法的整个帧,恢复调用者的帧,并将控制权转交给调用者。
接下来我们通过示例代码拉体会对应的方法指令,看看是怎么样的?
public class MethodInvokeReturnTest {
//方法的返回指令
public int returnInt(){
int i = 50;
return i;
}
}
把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
接下来我们通过示例代码拉体会其他方法返回指令,看看会有什么不一样?
public class MethodInvokeReturnTest {
//方法的返回指令
public double returnDouble(){
return 0.0;
}
public string returnstring(){
return "hello,wor1d" ;
}
public int[] returnArr(){
return nu1l;
}
public float returnFloat(){
int i = 10;
return i;
}
public byte returnByte(){
return 0;
}
}
把当前的代码编译一下,看看具体的字节码是怎么描述当前方法的?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。