码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA随笔篇二(深入分析JAVA简单类型、String和对象的值传递和引用传递)

时间:2015-08-17 17:21:02      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:java   值传递   引用传递   

关于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中一样。
大家通常举String做为特殊的对象来说明对象是按值或者按引用传递,却往往说的乱七八糟,通常是自己明白之后就乱写,下面一节再讨论String的问题。本人也不甚精通,如果写的有什么不对的,欢迎指正。

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和对象的值传递和引用传递)

标签:java   值传递   引用传递   

原文地址:http://blog.csdn.net/feiyangtianyao/article/details/47662979

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!