昨天上午笔试一道选择题,考察到int , String 和 StringBuffer的值传递问题,贴下代码:
public class ReferenceChangeValue {
public static void change(int k1,String s1,StringBuffer
sb1){
k1 = 2;
s1 = "a";
//sb1 = new StringBuffer("C");
sb1.append("C");
}
public static void main(String[] args) {
int k = 1;
String s = "A";
StringBuffer sb = new StringBuffer("B");
change(k,s,sb);
System.out.println("k = "+k+" s = "+s+"
sb = "+sb);
}
}
程序运行结果:
k = 1 s = A sb =
BC
可以看到,int类型 和 String类型变量的值没有改变,StringBuffer类型变量的值改变了。
分析:
1. Java只有值传递,int是基本类型(PrimitiveType),传递的是值,String和StringBuffer是类,ReferenceType(引用类型),传递的是对象的引用。
2.
int类型值传递。当基本类型的变量被当作参数传递给方法时,JAVA
虚拟机所做的工作是把这个值拷贝了一 份,然后把拷贝后的值传递到了方法的内部。
在change()函数里k1变量是局部变量,change()函数执行完毕之后,k1的生命周期也就结束,k1的内存地址将被GC回收。k1的改变不会影响到k值的变化。k1和main()函数中的k仅仅只是值相等,是不同的变量,它们指向的内存地址也不一样。
3.
String和StringBuffer等引用类型( ReferenceType,有三种类型:类、接口、和数组)值传递,JAVA
虚拟机会拷
贝一份这个变量所持有的引用,然后把它传递给JAVA 虚拟机为方法创建的局部变量,从而
这两个变量指向了同一个对象。
当一个对象或引用类型变量被当作参数传递时,也是值传递,这个值就是对象的引用,因此JAVA
中只有值传递,没有引用传递。
所以,JAVA虚拟机把对象在堆中保存地址的信息传递给change()函数中的形参变量,使得main()函数中的实参变量以及change()函数中的形参变量均指向同一个地址,但是,仍旧是两个独立的变量,仅有的关联是指向同一堆中的地址。
接下来,分析下程序,String变量s和s1均指向堆中变量s的地址,在change()函数中s1
= "a"; 作用仅仅是改变了局部变量s1(存储在栈中,作用域仅限于change()函数)的指向,指向"a"的内存地址,而main()函数中s变量的指向没有改变,所以change()函数执行完毕后,s1变量被销毁,s的值并没有受到影响。
同样,如果将程序中sb1.append("C"); 这句话替换为sb1 = new
StringBuffer("C"); 运行结果则是sb =
B,StringBuffer变量sb的值也不会改变,因为局部变量sb1的指向变化不会影响到sb的指向。
那么,sb1.append("C");
这句话为什么就能够改变sb1和sb的值呢?那是因为sb1指向sb的地址,执行append()方法
会改变sb地址保存的StringBuffer对象的value属性值,不同于改变局部变量的指向,这里改变了局部变量(对象引用)指向的对象的属性值。