Java字节码学习之MethodInvoke

[b][size=x-small]学习Java字节码有助于理解Java内存结构,加深对JVM的理解。[/size][/b]



首先需要知道JVM内存由堆、栈、方法区、本地方法栈组成。
堆中存放JVM生命周期里所有的类的实例。
栈中存放函数中的基础类型局部变量、函数中实例变量的引用。
方法区存放Class、Method的信息以及Static的变量。
本地方法栈存放调用本地方法时用到的变量。

JVM为每个线程都分配了一个方法栈,方法栈包含不同方法的栈帧,每个方法都有一个栈帧,当前方法的栈帧称为当前栈帧,栈帧由局部变量区和操作数栈组成,所有线程共享堆中的数据。

下面以一个简单的Java程序HelloWorld.java为例,介绍一下Java方法调用时的内存结构。

源代码
Java代码
public class HelloWorld {   
private String myWorld;

public HelloWorld(String world) {
this.myWorld = world;
}

public String getMyWorld() {
return myWorld;
}

public void setMyWorld(String myWorld) {
this.myWorld = myWorld;
}

public boolean isNull(){
if(this.myWorld==null){
return true;
}else{
return false;
}
}

public static void main(String[]args){
HelloWorld myWorld = new HelloWorld("smallWorld");
boolean isNull = false;
myWorld.setMyWorld("bigWorld");
isNull = myWorld.isNull();
}
}

public class HelloWorld {
private String myWorld;

public HelloWorld(String world) {
this.myWorld = world;
}

public String getMyWorld() {
return myWorld;
}

public void setMyWorld(String myWorld) {
this.myWorld = myWorld;
}

public boolean isNull(){
if(this.myWorld==null){
return true;
}else{
return false;
}
}

public static void main(String[]args){
HelloWorld myWorld = new HelloWorld("smallWorld");
boolean isNull = false;
myWorld.setMyWorld("bigWorld");
isNull = myWorld.isNull();
}
}


Javap -C HelloWorld

字节码:
Java代码
Compiled from "HelloWorld.java"  
public class com.sitech.core.HelloWorld extends java.lang.Object{
public com.sitech.core.HelloWorld(java.lang.String);
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #13; //Field myWorld:Ljava/lang/String;
9: return

public java.lang.String getMyWorld();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: areturn

public void setMyWorld(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #13; //Field myWorld:Ljava/lang/String;
5: return

public boolean isNull();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: ifnonnull 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn

public static void main(java.lang.String[]);
Code:
0: new #1; //class HelloWorld
3: dup
4: ldc #27; //String smallWorld
6: invokespecial #29; //Method "<init>":(Ljava/lang/String;)V
9: astore_1
10: iconst_0
11: istore_2
12: aload_1
13: ldc #31; //String bigWorld
15: invokevirtual #33; //Method setMyWorld:(Ljava/lang/String;)V
18: aload_1
19: invokevirtual #35; //Method isNull:()Z
22: istore_2
23: return

}

Compiled from "HelloWorld.java"
public class com.sitech.core.HelloWorld extends java.lang.Object{
public com.sitech.core.HelloWorld(java.lang.String);
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #13; //Field myWorld:Ljava/lang/String;
9: return

public java.lang.String getMyWorld();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: areturn

public void setMyWorld(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #13; //Field myWorld:Ljava/lang/String;
5: return

public boolean isNull();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: ifnonnull 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn

public static void main(java.lang.String[]);
Code:
0: new #1; //class HelloWorld
3: dup
4: ldc #27; //String smallWorld
6: invokespecial #29; //Method "<init>":(Ljava/lang/String;)V
9: astore_1
10: iconst_0
11: istore_2
12: aload_1
13: ldc #31; //String bigWorld
15: invokevirtual #33; //Method setMyWorld:(Ljava/lang/String;)V
18: aload_1
19: invokevirtual #35; //Method isNull:()Z
22: istore_2
23: return

}


重点看一下main方法中调用isNull方法的操作:

Java代码
public static void main(java.lang.String[]);   
Code:
0: new //在堆中分配内存,返回对象引用,压入操作数栈
3: dup //复制引用,压入栈
4: ldc //将常量池中的常量smallWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入构造函数的
//局部变量区
6: invokespecial //调用构造函数,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
9: astore_1 //将对象引用弹出,存储在main方法局部变量1的位置
10: iconst_0 //将false值压栈
11: istore_2 //弹出false并存储于main方法局部变量2的位置
12: aload_1 //将对象引用压栈
13: ldc //将将常量池中的常量bigWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入实例方法
//的局部变量区
15: invokevirtual //调用实例函数setMyWorld,弹出对象引用和参数
18: aload_1 //将对象引用存储在main方法局部变量1的位置
//JVM会将main方法操作数栈中的变量弹出放入实例方法的
//局部变量区
19: invokevirtual //调用实例函数isNull,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
22: istore_2 //弹出true并存储于main方法局部变量2的位置
23: return

public static void main(java.lang.String[]);
Code:
0: new //在堆中分配内存,返回对象引用,压入操作数栈
3: dup //复制引用,压入栈
4: ldc //将常量池中的常量smallWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入构造函数的
//局部变量区
6: invokespecial //调用构造函数,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
9: astore_1 //将对象引用弹出,存储在main方法局部变量1的位置
10: iconst_0 //将false值压栈
11: istore_2 //弹出false并存储于main方法局部变量2的位置
12: aload_1 //将对象引用压栈
13: ldc //将将常量池中的常量bigWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入实例方法
//的局部变量区
15: invokevirtual //调用实例函数setMyWorld,弹出对象引用和参数
18: aload_1 //将对象引用存储在main方法局部变量1的位置
//JVM会将main方法操作数栈中的变量弹出放入实例方法的
//局部变量区
19: invokevirtual //调用实例函数isNull,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
22: istore_2 //弹出true并存储于main方法局部变量2的位置
23: return


再来看看isNull方法:

Java代码
public boolean isNull();   
Code:
0: aload_0 //将局部变量区的对象引用参数压栈
1: getfield //访问堆区的类实例
4: ifnonnull //是否为空
7: iconst_1 //如果是true,将1压入操作数栈
8: ireturn
9: iconst_0 //如果是false,将0压入操作数栈
10: ireturn

public boolean isNull();
Code:
0: aload_0 //将局部变量区的对象引用参数压栈
1: getfield //访问堆区的类实例
4: ifnonnull //是否为空
7: iconst_1 //如果是true,将1压入操作数栈
8: ireturn
9: iconst_0 //如果是false,将0压入操作数栈
10: ireturn


方法调用结束后,JVM会将isNull操作数栈中的返回值压入main方法的操作数栈中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值