关于java中只有“值传递”的认识:如果是基本类型就传递值的拷贝(基本类型的包装类型),如果是对象类型就传递引用的拷贝(所以根据传递的引用能够改变原有对象的值,但是不能重新指向另外的对象,否则不会改变)
传递值的拷贝:基本类型(int char float double等),基本类型的包装类型(Integer,Float,Double等); 按理说,包装类型也是对象,根据传递引用应该可以该百年对象的值,但实际中确实不能改变。
package com.zgd;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
testInt(a);
System.out.println("a="+a);//
Integer b = new Integer(1);
testInteger(b);
System.out.println("b="+b);//1
Integer c= new Integer(1);
testNewInteger(c);
System.out.println("c="+c); //1
}
static void testInt(int a){
a = 2;
}
static void testInteger(Integer b){
b = 3;
}
static void testNewInteger(Integer c){
c = new Integer(4);
}
}
传递引用的拷贝:内部定义对象(如数组)和自定义对象
package com.zgd;
import java.util.Arrays;
public class A {
public static void main(String[] args) {
int[] aa = { 3, 2, 1 };
System.out.println(Arrays.toString(aa)); // [3, 2, 1]
test(aa);
System.out.println(Arrays.toString(aa)); // [3, 2, 1]
test2(aa);
System.out.println(Arrays.toString(aa)); // [4, 2, 1]
}
static void test(int[] a) {
a = new int[] { 1, 2, 3 }; // 指向了新对象
}
static void test2(int[] a) {
if (a != null && a.length > 0)
a[0]++; // 修改原来的那个对象
}
}
但是关于String类型的传递有些问题:
按前面的分析,String属于对象类型,当String作为参数传递的是引用,应该可以改变其内部类型,但实际中却并没有改变。 但换成StringBuff却可以!
package com.zgd;
public class Test2 {
public static void test(String str) {
str=str.concat("zgd");
System.out.println("inner:"+str);//Hellozgd
}
public static void main(String[] args) {
String string = "Hello";
test(string);
System.out.println(string);//Hello
}
}
http://freej.blog.51cto.com/235241/168676
关于String的问题在这篇博客中给来分析,博主分析源码认为String是char[]的包装类型,所以和Integer一样不能改变。
很可惜这样的分析是错误的,首先char[]作为数组传递(java中数组被认为是对象)是可以修改其值的。这里的根本问题是因为String中的char[]是final的,也就是不可改变的,那么当String进行修改,比如 str=str.concat("zgd"); 这里实际上等价于 str = new String(str.concat("zgd"));
这就是问题的关键:test方法中str作为对象类型传递引用,str是string(“hello”)的引用,但是当str = new String(str.concat("zgd"));之后str便有了自己新的内存,不再指向原来的的string(“hello”)。当从方法中返回的时候,这个临时复制的引用str被销毁,但是string(“hello”)中的内容仍然没有改变。为了更清楚地解释,请看下面的StringBuffer例子
换成StringBuffer
package com.zgd;
class MyDemo {
public static void operate(StringBuffer x, StringBuffer y) {
x.append(y);
y = x;
System.out.println(x + "," + y);//AB,AB
x = new StringBuffer("A"); //指向来新的空间,不再和原来的StringBuffer a有任何关系
System.out.println(x + "," + y);//A,AB
}
public static void main(String[] args) {
StringBuffer a = new StringBuffer("A");
StringBuffer b = new StringBuffer("B");
operate(a, b);
System.out.println(a + "," + b); //AB,B
}
}
这里需要特别注意的是operate方法中x.append(y)改变了a对象,但是
x = new StringBuffer("A");
却没有改变对象。这是为什么??? 因为x指向了重新分配的内存空间“A”
总结:(1)正确理解java中只有“值传递”的:如果是基本类型就传递值的拷贝(基本类型的包装类型),如果是对象类型就传递引用的拷贝(所以根据传递的引用能够改变原有对象的值,但是不能重新指向另外的对象,否则不会改变)
(2)基本类型和基本类型的包装类型是值拷贝的传递;对象类型是引用拷贝的传递
(3)引用拷贝一定不能指向重新分配的内存,因为指向来新的内存是改变不了原来对象的