Java传值与传引用。对基本数据类型传递值,对象则传引用。传递对象时,若在被调函数体内改变了对象的值,那么在调用函数内对象的值也会改变。试试下面一段代码。
... {
i=100;
}
void testInteger(Integer i)
... {
i=new Integer(200);
}
void testStr1(StringBuffer str)
... {
str.append("---add--");
}
void testStr2(StringBuffer str)
... {
str=new StringBuffer("@new@");
}
public static void main(String[] args)
... {
new TestDerived().test();
}
void test()
... {
int i=7;
System.out.println("i:"+i);
testValue(i);//传值
System.out.println("testValue(i):"+i);
Integer oi=new Integer(7);
testInteger(oi);//传引用
System.out.println("testInteger(i):"+oi);
StringBuffer str=new StringBuffer("raw");
System.out.println("str:"+str);
testStr1(str);//传引用
System.out.println("testStr1(str):"+str);
testStr2(str);//传引用
System.out.println("testStr2(str):"+str);
}
如果按照我的理解,那么结果应该是:
i:7
testValue(i):7
testInteger(i):200
str:raw
testStr1(str):raw---add--
testStr2(str):@new@
可是实际上,运行出来的结果却是:
i:7
testValue(i):7
testInteger(i):7
str:raw
testStr1(str):raw---add--
testStr2(str):raw---add--
让我很困惑。查阅了一些资料,才发现,引用和指针一样,在编译器传递参数值,都会为这个引用/指针制作一个副本。比如上面的函数void testInteger(Integer i);当调用testInteger(oi)时,编译器为引用oi制作一个副本_oi,这个副本_oi当然也指向对象oi指向的对象。 当在函数体内执行i=new Integer(200);时,创建了一个Integer对象,并将其引用赋值给_oi。而在函数main内的对象oi却并没有改变。因而输出的值仍然为7。而为社么函数testStr1会改变字符串str的值呢?那是因为testStr1的执行语句,str.append("---add--");是针对str指向的对象操作的,因此也改变了函数main内字符串str的值。
极端一点说,java里面都传的是值,即在函数调用时,都会为参数制作一个副本,然后将参数值复制过去。
只不过,对基本数据类型参数,传递的是该参数的基本数据值,在函数内创建的是相同数据类型的副本;而对对象而言,传递的是引用的值,会创建一个引用的副本,然后使其指向引用参数所指向的对象。当传递参数为对象时(即传引用),在被调函数体内,如果是针对引用所指向的对象操作,那么将会修改调用函数内对象的值;如果针对引用本身操作,那么,将不会修改调用函数内对象的值。就像上面的例子,testStr1是针对引用所指向的对象操作(改变调用者的值),而testStr2则是针对引用本身操作(不改变调用者的值)。
C++中的指针与引用也与这个是非常类似的。
void testValue( int i)
... {
i=100;
}
void testPoint1( int * pi)
... {
pi=NULL;
}
void testPoint2( int * pi)
... {
*pi=200;
}
void testReference( int * pi)
... {
pi=NULL;
}
int main( int argc, char * argv[])
... {
int* pi=new int(7);
cout<<"*pi:"<<*pi<<endl;
testValue(*pi);
cout<<"testValue(pi):"<<*pi<<endl;
testPoint1(pi);
cout<<"testPoint1(pi):"<<*pi<<endl;//correct
testPoint2(pi);
cout<<"testPoint2(pi):"<<*pi<<endl;
int *&rp=pi;
testReference(rp);
cout<<"testReference(pi):"<<*pi<<endl;//correct
return 0;
}
运行结果为:
*pi:7
testValue(pi):7
testPoint1(pi):7(由于是针对指针本身操作,即使函数体内指针被赋值为null,这里也不会出错)
testPoint2(pi):200
testReference(pi):200