关于JAVA的值传递和引用传递,翻看了很多资料和博客,感觉大多数讲的很乱,都是自己明白了之后就不讲了的样子,终于算是比较理解这几个概念了,下面做一个总结。
1、简单类型的参数传递
Java方法的参数是简单类型的时候,是按值传递的 (pass by value)。下面举一个经典的swap函数:
无法交换值的方法:
package TestTransferPack;
public class TestTransfer {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
int b = 5;
swap(a, b);
System.out.println(a+" "+ b);
}
public static void swap(int a,int b){
int temp=0;
temp = b;
b=a;
a=temp;
}
}result:1 5以参数形式传递简单类型的变量时,实际上是将参数的值作了一个拷贝传进方法函数的,那么在方法函数里再怎么改变其值,其结果都是只改变了拷贝的值,而不是源值。
交换值的方法:
(1)数组
package TestTransferPack;
public class TestTransfer1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
int b = 5;
int[] test = new int[2];
test[0]=a;
test[1]=b;
swap(test,0, 1);
a = test[0];
b = test[1];
System.out.println(a+" "+ b);
}
public static void swap(int[] data,int index1,int index2){
int tmp = data[index1];
data[index1] = data[index2];
data[index2] = tmp;
}
}result:5 1
这种利用数组的方式可以改变两个简单类型的值。
C++中有指针,简单类型的传递方式和1中的一样,都是值传递,但是却可以通过传递指针的方式交换两个简单类型的值,但是JAVA中没指针,所以简单类型的值交换要特殊处理。
2、普通对象的参数传递
普通对象一般是按照引用传递的,姑且先这样说,也就是大家说的按地址传递, 地址传递传递的就是原来的对象地址,这样修改内容就会改变原值,后面会对这种传递方式做详细分析解释。
package TestTransferPack;
public class TestTransfer2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
int b = 5;
Test tt1 = new Test(a);
Test tt2 = new Test(b);
swap1(tt1,tt2);
System.out.println(tt1.a+" "+ tt2.a);
}
public static void swap1(Test index1,Test index2){
int tmp = index1.a;
index1.a = index2.a;
index2.a = tmp;
}
public static class Test{
int a=0;
public Test(int b){
a = b;
}
}
}
result: 5 1
可以看出,在函数中两个对象的数据是可以修改的。
然而这样却不能改变对象的值:
package TestTransferPack;
public class TestTransfer3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
int b = 5;
Test tt1 = new Test(a);
Test tt2 = new Test(b);
swap1(tt1,tt2);
System.out.println(tt1.a+" "+ tt2.a);
}
public static void swap1(Test index1,Test index2){
/*int tmp = index1.a;
index1.a = index2.a;
index2.a = tmp;*/
Test tmp = new Test();
tmp = index1;
index1 = index2;
index2 = tmp;
}
public static class Test{
int a=0;
public Test(int b){
a = b;
}
public Test(){}
}
}
result: 1 5究其原因,我们可以将去推及C++的参数传递,C++中如果参数传递的是一个指针,那么这个指针指向的对象内容可以改变,但是指针本身确是一个复制,因此不能改变指针的值;JAVA中对象的参数传递是一个地址,这个地址指向的内容是可以改变的,就像上面TestTransfer2中的例子,但是这个地址却是按值传递的,改变这个地址完全没有用,就像TestTransfer3中一样。
3、String及相关对象的参数传递
通俗来说,String是按照值传递的。
package TestTransferPack;
public class TestTransfer4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String tt1 = new String("hello ");
String tt2 = new String("world ");
swap1(tt1,tt2);
System.out.println(tt1 + tt2);
}
public static void swap1(String index1,String index2){
String tmp = index1;
index1 = index2;
index2 = tmp;
}
}
result:hello world
这和TestTransfer3是一样的,当然不能改变String的值,有人说用StringBuffer,当然也不能。
package TestTransferPack;
public class TestTransfer5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuffer tt1 = new StringBuffer ("hello ");
StringBuffer tt2 = new StringBuffer ("world ");
swap1(tt1,tt2);
System.out.println(tt1.toString()+ tt2.toString());
}
public static void swap1(StringBuffer index1,StringBuffer index2){
StringBuffer tmp = index1;
index1 = index2;
index2 = tmp;
}
}
<pre name="code" class="java">result:hello world可能会想到在函数中改变index1的值,比如index1=index2,但是String和StringBuffer都不行,改变的值并不能带出函数。
但是这样却可以:
package TestTransferPack;
public class TestTransfer6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuffer tt1 = new StringBuffer ("hello ");
StringBuffer tt2 = new StringBuffer ("world ");
append(tt1,tt2);
System.out.println(tt1.toString()+ tt2.toString());
}
public static void append(StringBuffer index1,StringBuffer index2){
index1.append(index2);
}
}result:hello world world下面看一下append的实现,一路追踪下去,我们会找到这句话:
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);使用这个方法之前先扩展了StringBuffer的数组大小,然后copy数据。这样,就会改变index1指向的空间的内容。
都说String在赋值操作的过程中产生新的对象,这样的话,TestTransfer4和TestTransfer5中的问题就迎刃而解了,因为都不是一个对象,怎么可能改变这个值。
下面探讨一下。
我们知道,hashCode是object的唯一标识。我们可以用 hashCode来确定String在赋值或者其他操作中的对象变化。
package TestTransferPack;
public class TestTransfer7 {
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuffer tt1 = new StringBuffer ("hello ");
StringBuffer tt2 = new StringBuffer ("world ");
append(tt1,tt2);
System.out.println(tt1.toString()+ tt2.toString());
System.out.println(tt1.hashCode());
}
public static void append(StringBuffer index1,StringBuffer index2){
index1.append(index2);
System.out.println(index1.hashCode());
index1 = index2;
System.out.println(index1.hashCode());
}
}result:1167165921 1442002549 hello world world 1167165921可以看出,index1在第二次赋值之后就不再是原对象。String也是一样。
版权声明:本文为博主原创文章,未经博主允许不得转载。
JAVA随笔篇二(深入分析JAVA简单类型、String和对象的值传递和引用传递)
原文:http://blog.csdn.net/feiyangtianyao/article/details/47662979