jasmin 源代码
Compiled from "Main.java"
class Modify {
Modify();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void ModifyStr(MyString);
Code:
0: aload_1 // *把局部变量#1中的地址压栈(局部变量#1存储函数的第一个实参 #2...#254 依次类推)
1: iconst_m1 // *把常数-1压入栈
2: putfield #2 // *Field MyString.a:I (a=-1)
5: return
}
Compiled from "Main.java"
class MyString {
public int a;
MyString();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
}
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
// *在堆中实例化 MyString,并将地址存在局部#1中
0: new #2 // class MyString *在堆中创建新的对象 并把地址压栈
3: dup // *复制栈顶一个字并压入栈中
4: invokespecial #3 // Method MyString."<init>":()V *调用构造函数
7: astore_1 // *从栈顶弹出一个地址 并存储在局部变量#1中
// *在堆中实例化 Modify,并将地址存在局部#2中
8: new #4 // class Modify
11: dup
12: invokespecial #5 // Method Modify."<init>":()V
15: astore_2
16: aload_1 // *把局部变量#1中的地址压入栈(MyString实例化对象的地址)
17: bipush 10 // *将常数10压入栈
19: putfield #6 // Field MyString.a:I *从栈中弹出一个地址和值,并将值存到指定的对象域中(s.a = 10;)
22: aload_2 // *把局部变量#2中的地址压入栈(Modify实例化对象的地址)
23: aload_1 // *把局部变量#1中的地址压入栈(MyString实例化对象的地址)
/*
* invokevirtual 调用对象的实例方法按栈中如下次序调用
* argN
* ...
* arg2
* arg1
* address 对象的地址
* 在此例中 aload_2 作为对象的地址首先入栈 aload_1作为参数而后入栈
*/
24: invokevirtual #7 // Method Modify.ModifyStr:(LMyString;)V
27: return
}
/* 结论:
* 当 new 一个新的对象时,jvm会自动在堆区开辟空间用以存储对象,并且会把对象的地址自动压入栈
* 在此例中用汇编指令astore_1 astore_2 分别把对象的地址存储在局部变量 #1 #2中,然后我们使用对象时,
* 实际上是通过存储在局部变量中的对象的地址来找到堆中的对象.用invokevirtual调用方法时,传递的是
* 对象的地址(详见上面分析)
*/
Java 源代码
public class Main {
public static void main(String[] arge){
MyString s = new MyString();
Modify m = new Modify();
s.a = 10;
m.ModifyStr(s);
}
}
class MyString{
public int a;
}
class Modify{
public void ModifyStr(MyString str){
str.a = -1;
}
}