java对象引用在方法中传递
package com.cy;
public class Client {
public static void main(String[] args) {
Student std = new Student("cy", 24);
changeStudentNameAndAge(std);
System.out.println(std.toString());
}
// 改变学生姓名和年纪
// 1.直接操作对象
private static void changeStudentNameAndAge(Student std) {
std.setName("chenyin");
std.setAge(84);
}
// 2.重新new一个对象
private static void changeStudentNameAndAge(Student std) {
std = new Student("chenyin", 84);
}
}
情况1. 执行代码1 输出的语句是 Student [age=84, name=chenyin]
情况 2. 执行代码2 输出的语句是Student [age=24, name=cy] 为什么会出现两种不同点结果呢?
因为 Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。
即上述的方法中 changeStudentNameAndAge(Student std),std只是main函数中std引用的一个副本。即
局 部变量std 指向了 main方法变量std指向的地址。因为方法中的参数是形参,他只是保存了main方法中std指向内存区域的地址。不能理解 changeStudentNameAndAge(Student std)中std和mian中的std是一样的。因为你可以写changeStudentNameAndAge(Student std1) changeStudentNameAndAge(Student std2).
当情况1时 游泳changeStudentNameAndAge(Student std)中std指向的地址和main方法中std指向的是同一个地址,那么对changeStudentNameAndAge(Student std)中std操作,则也改变了mian中std指向的内容。
而情况2则不同。 changeStudentNameAndAge(Student std)std使用了new的方法,则std重新指向了一块存储区域。那么对changeStudentNameAndAge(Student std)中std操作,实际上改变了std新创建区域的值,而对mian方法std指向的内容是没有影响的。因为mian中std和 changeStudentNameAndAge(Student std)中的std指向的不是同一个内存区域。
将代码1编译后的.class文件拖放到eclipse中
public class com.cy.Client {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public Client();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.cy.Client
// Method descriptor #15 ([Ljava/lang/String;)V
// Stack: 4, Locals: 2
public static void main(java.lang.String[] args);
0 new com.cy.Student [16]
3 dup
4 ldc <String "cy"> [18]
6 bipush 24
8 invokespecial com.cy.Student(java.lang.String, int) [20]
11 astore_1 [std]
12 aload_1 [std]
13 invokestatic com.cy.Client.changeStudentNameAndAge(com.cy.Student) : void [23]
16 getstatic java.lang.System.out : java.io.PrintStream [27]
19 aload_1 [std]
20 invokevirtual com.cy.Student.toString() : java.lang.String [33]
23 invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
26 return
Line numbers:
[pc: 0, line: 11]
[pc: 12, line: 13]
[pc: 16, line: 15]
[pc: 26, line: 17]
Local variable table:
[pc: 0, pc: 27] local: args index: 0 type: java.lang.String[]
[pc: 12, pc: 27] local: std index: 1 type: com.cy.Student
// Method descriptor #26 (Lcom/cy/Student;)V
// Stack: 2, Locals: 1
private static void changeStudentNameAndAge(com.cy.Student std);
0 aload_0 [std]
1 ldc <String "chenyin"> [47]
3 invokevirtual com.cy.Student.setName(java.lang.String) : void [49]
6 aload_0 [std]
7 bipush 84
9 invokevirtual com.cy.Student.setAge(int) : void [52]
12 return
Line numbers:
[pc: 0, line: 25]
[pc: 6, line: 26]
[pc: 12, line: 28]
Local variable table:
[pc: 0, pc: 13] local: std index: 0 type: com.cy.Student
}
可以看出在mian中存储了Student对象在changeStudentNameAndAge(com.cy.Student std)中aload_0 [std]即该方法操作的地址和main中申请的地址一样。所以改变changeStudentNameAndAge方法中的name和age会引起main中的变量同步改变。
将2编译后的.class拖放到eclipse
public class com.cy.Client {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public Client();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.cy.Client
// Method descriptor #15 ([Ljava/lang/String;)V
// Stack: 4, Locals: 2
public static void main(java.lang.String[] args);
0 new com.cy.Student [16]
3 dup
4 ldc <String "cy"> [18]
6 bipush 24
8 invokespecial com.cy.Student(java.lang.String, int) [20]
11 astore_1 [std]
12 aload_1 [std]
13 invokestatic com.cy.Client.changeStudentNameAndAge(com.cy.Student) : void [23]
16 getstatic java.lang.System.out : java.io.PrintStream [27]
19 aload_1 [std]
20 invokevirtual com.cy.Student.toString() : java.lang.String [33]
23 invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
26 return
Line numbers:
[pc: 0, line: 11]
[pc: 12, line: 14]
[pc: 16, line: 16]
[pc: 26, line: 18]
Local variable table:
[pc: 0, pc: 27] local: args index: 0 type: java.lang.String[]
[pc: 12, pc: 27] local: std index: 1 type: com.cy.Student
// Method descriptor #26 (Lcom/cy/Student;)V
// Stack: 4, Locals: 1
private static void changeStudentNameAndAge(com.cy.Student std);
0 new com.cy.Student [16]
3 dup
4 ldc <String "chenyin"> [47]
6 bipush 85
8 invokespecial com.cy.Student(java.lang.String, int) [20]
11 astore_0 [std]
12 return
Line numbers:
[pc: 0, line: 23]
[pc: 12, line: 29]
Local variable table:
[pc: 0, pc: 13] local: std index: 0 type: com.cy.Student
}
可以发现main中的std使用了astore_1 [std]而changeStudentNameAndAge使用了astore_0 [std]很明显,代码2中的changeStudentNameAndAge使用了new Student()方法导致mian中std指向的地址和changeStudentNameAndAge中的std指向的地址不是用一个模块了。因此对changeStudentNameAndAge中std的改变影响不了mian中。
由 上例可见,将对象的引用传递给方法时,只是将这个引用指向的地址传给了方法。或者说只是将对象的引用复制了一个副本。是这两个引用指向了同一块地址,当在方法中直接操作这个引用副本时会改变这个引用副本和引用指向的区域。但是若在方法中将引用的副本重新指向了一个内存区域,对这个引用副本的操作不会引起引 用指向地址的内容的改变。