当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
答案基本上是:值传递
说明:得出这种结论的前提必须是“参数的值就是对该对象的引用,而不是对象的内容”
----------------------------------------------------
值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法中执行形式参数值的改变不影响实际参数的值。
引用传递:也称为传地址。方法调用时,实际参数的引用(即地址,而不是参数的值)被传递给方法中相对应的形式参数,
在方法中执行对形式参数的操作实际上就是对实际参数的操作(地址操作),这样方法执行中形式参数值的改变将会影响实际参数的值。
1. 基本类型传递
基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的, 值都存在栈中。
public class Other {
public static void main(String[] args) {
int a = 1;
method(a);
System.out.println(a);
}
public static void method( int a){
a = 2;
}
}
输出: a = 1;
2. 类传递
Case 1:
public class Other {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("abc");
method(s);
System.out.println(s);
}
public static void method(StringBuffer s){
s = new StringBuffer("abc");
s.append("d");
}
}
输出:abc
解析:这时传递的是对象的地址,方法中的s又重新创建了对象“abc”,这时他们引用两个不同堆内存。s.append是在method创建出的“abc”上加“d”,所以会main中不会变。
Case 2:
public class Other {
public static void main(String[] args) {
StringBuffer a = new StringBuffer(“abc”);
method(a);
System.out.println(a);
}
public static void method( StringBuffer a){
a.append(“d”);
}
}
输出:abcd
解析:这时传递的是对象的地址,方法中的s同样指向 main中s的指向“abc”, s.append是将“abc”加上“d”,method直接修改这个值,所以会main中也跟着变。
Case 3:
public class Other {
public static void main(String[] args) {
String s = new String("abc");
method(s);
System.out.println(s);
}
public static void method(String s){
s = s+"d";
}
}
输出:abc
在方法中改变String值,我画出的图如下:
因为在a的值是个地址。所以传的值也就是0x0001,然后方法中的a也指向堆内存的“aaa”。当a=“bbb”时,方法区中的a 指向0x0002。所以main中的a 还是不变的。与case2不同的是String是不可变的,s+”d”是将存有abc的字符数组的值取出再加上d. 总之一定不是在原有的“aaa”上进行操作,这牵扯到String的安全性设计。
3. 数组传递
public class Other {
public static void main(String[] args) {
int[] a = new int[] { 1, 2 };
method(a);
System.out.println(a[0]);
}
public static void method(int[] a) {
a[0] = 0;
}
}
输出:2
数值为什么会改变呢,我画了如下的堆栈图。
因为数组的地址和数组中值的地址中间又多了一道。传递到Method的b是main中b的值,也就是数组在堆中的地址0x0003,然后在这个数组中,第一个值又指向堆中的数值1,也就是0x0004 这时method 做b[0]=0,也就是把 数组中的第一位由0x0004改成0x0006,直接操作了该数组。