Java的所有对象都是引用,类似于C和C++中的指针。Java类的方法如果包含引用类型的参数,那么当该方法被调用时,向该方法参数传递的是传值变量的引用。不同于C和C++中的指针,Java对象在调用含参数方法时,向方法中的参数传递的都是指定的值得副本,而不是向参数传值的变量本身。因此,在方法体重,如果参数的值被改变,不会影响向其传值的变量的值。
来看一个具体的实例。
class ChangeStr {
private String myStr;
ChangeStr(String str) {
myStr = str;
}
public void setMyStr(String newStr) {
myStr = newStr;
}
public String toString() {
return myStr;
}
}
public class Test {
public static void main(String[] args) {
Test t = new Test();
System.out.println("==== Test 1 ====");
ChangeStr changeStr1 = new ChangeStr("Hello");
System.out.println(changeStr1);
t.change1(changeStr1);
System.out.println(changeStr1);
System.out.println();
System.out.println("==== Test 2 ====");
ChangeStr changeStr2 = new ChangeStr("Hello");
System.out.println(changeStr2);
t.change2(changeStr2);
System.out.println(changeStr2);
System.out.println();
}
// Method 1
public void change1(ChangeStr cs) {
cs.setMyStr("Hi");
cs = new ChangeStr("HaHa");
}
// Method 2
public void change2(ChangeStr cs) {
cs = new ChangeStr("HaHa");
cs.setMyStr("Hi");
}
}
类Test有两个含参方法change1()和change2(),这两个方法的不同之处在于,方法体两个语句的顺序不同。
程序输出如下:
==== Test 1 ==== Hello Hi
==== Test 2 ==== Hello Hello |
从输出结果可以看出,方法change1()改变了changeStr1的成员变量myStr的值,而change2()并没有改变changeStr2的成员变量myStr的值。
针对test1,程序执行到第22行时,创建了一个ChangeStr实例changeStr1,并将其成员变量myStr赋值为”Hello”,如图所示。
当程序执行到第24行时,changeStr1的副本被传递给方法参数cs,这个副本的名字仍为cs,这时cs与changeStr1指向同一个实体,见下图:
在change1()方法体内,程序执行第38行时,cs调用方法setMyStr()改变了它所指向的实体的成员变量myStr的值,由于changeStr1与cs指向相同的实体,因此changteStr1的成员变量myStr的值便被更改为”Hi”。
在change1()方法体内,程序执行第39行时,cs指向了一个新的实体,该实体的成员变量myStr的值为”HaHa”,这对changeStr1无影响。
针对test2,程序执行到第29行时,与test1一样,创建了一个ChangeStr实例changeStr2,并将其成员变量myStr赋值为”Hello”,如图所示。
同样,当程序执行到第31行时,changeStr2的副本被传递给方法参数cs,这个副本的名字仍为cs,这时cs与changeStr2指向同一个实体,见下图:
在change2()方法体内,程序执行第44行时,与test1不同的是,这时cs指向了一个新的实体,该实体的成员变量myStr的值为”HaHa”,而这对changeStr2无影响。
此后,当程序执行第45行时,cs调用方法setMyStr()改变了它所指向的实体的成员变量myStr的值,由于changeStr2与cs指向不同的实体,因此这对changteStr2仍然无影响。