java代码
package com.test;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.test;
public class TestMain {
public static void main(String[] args) {
User user = new User();
user.setName("abc");
test(user);
System.out.println(user.getName());
}
public static void test(User user){
user = new User();
user.setName("efsdf");
}
}
输出结果:
abc
package com.test;
public class TestMain {
public static void main(String[] args) {
User user = new User();
user.setName("abc");
test(user);
System.out.println(user.getName());
}
public static void test(User user){
user.setName("efsdf");
}
}
输出结果:
dfsdf
反汇编代码
Compiled from "TestMain.java"
public class com.test.TestMain {
public com.test.TestMain();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
// new创建对象,将对象引用地址放到棧顶
0: new #2 // class com/test/User
// 复制一份压棧
3: dup
4: invokespecial #3 // Method com/test/User."<init>":()V
// 棧顶元素放到局部变量表中索引为1,即存的是user地址,出棧
7: astore_1
// 将1号局部变量及user地址,压棧
8: aload_1
// 压棧
9: ldc #4 // String abc
// 调用实例方法
11: invokevirtual #5 // Method com/test/User.setName:(Ljava/lang/String;)V
// 将1号局部变量及user地址,压棧
14: aload_1
// 调用静态方法,将棧顶元素传入user地址
15: invokestatic #6 // Method test:(Lcom/test/User;)V
18: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
// 此时局部变量表未进行任何改变,指向老user
21: aload_1
22: invokevirtual #8 // Method com/test/User.getName:()Ljava/lang/String;
25: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
public static void test(com.test.User);
Code:
// 创建user
0: new #2 // class com/test/User
// 复制新地址入棧
3: dup
4: invokespecial #3 // Method com/test/User."<init>":()V
// 新user地址存入局部变量表
7: astore_0
8: aload_0
9: ldc #10 // String efsdf
// 此时棧顶为新的对象地址,所以改变的是新地址指向对象的空间
11: invokevirtual #5 // Method com/test/User.setName:(Ljava/lang/String;)V
14: return
}
去掉newUser()步骤反汇编代码为
public class com.test.TestMain {
public com.test.TestMain();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class com/test/User
3: dup
4: invokespecial #3 // Method com/test/User."<init>":()V
7: astore_1
8: aload_1
9: ldc #4 // String abc
11: invokevirtual #5 // Method com/test/User.setName:(Ljava/lang/String;)V
14: aload_1
15: invokestatic #6 // Method test:(Lcom/test/User;)V
18: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
21: aload_1
22: invokevirtual #8 // Method com/test/User.getName:()Ljava/lang/String;
25: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
public static void test(com.test.User);
Code:
0: aload_0
1: ldc #10 // String efsdf
3: invokevirtual #5 // Method com/test/User.setName:(Ljava/lang/String;)V
6: return
}
发现只是差了test方法中的new的操作,即
0: new #2 // class com/test/User
3: dup
4: invokespecial #3 // Method com/test/User."<init>":()V
7: astore_0
结论:new User()的test方法棧顶部的为新的user对象的地址,而astore_0将局部变量表中的地址也就是user的地址在局部变量表中进行更改,实际对原对象的内容没有进行更改,而外部输出采用的是外部函数棧帧的局部变量表,并未进行更改,指向还是原对象的堆内存(即,user= new User()就是对内部函数局部变量表进行赋值,对外部没啥影响)