学过C/C++的人或多或少会对Java中传递参数产生一定的困惑。下面我以读书笔记的形式谈谈自己对Java中传递参数问题的一些认识。
学过C系语言的人会说:“参数传递分为传值与传地址:传值形式形参改变不影响实参;传址形式形参改变很有可能影响实参的改变“;
学过Java的人 则会说:”在Java中只有传值一种方式:如果是基本类型,传递的参数是基本类型的值,在方法中不能改变实参的值;如果是定义的对象,传递的对象的引用,你也不能在方法中修改这个引用,但可以通过该对象的方法改变对象的值。“
两者似乎有很大的区别,甚至产生冲突,且听我慢慢解释。
当传递的是基本数据类型时,二者是统一的。下面C系与Java所得结果相同。
C系:
#include<iostream> using namespace std; void Change(int tempPar) { tempPar=10; cout<<"In the function: "<<tempPar<<endl; } int main() { int par=5; cout<<"Before the function: "<<par<<endl; Change(par); cout<<"After the function: "<<par<<endl; return 0; }
Java:
package JavaLanProtocol; public class Method { public static void main(String []agr) { int par=5; System.out.println("Before the function: "+par); Change(par); System.out.println("After the function: "+par); } public static void Change(int tempPar) { tempPar=10; System.out.println("In the function: "+tempPar); } }
结果都为:
Before the function: 5
In the function: 10
After the function: 5
当传递的是对象时,C系语言中分传值与传地址两种方式,大家都知道,在此就不解释了。但Java中传递的是引用,引用可以理解为地址,最终二者指向同一内存单元。先看段代码:
package JavaLanProtocol; public class Method { public static void main(String []agr) { StringBuffer str = new StringBuffer("Hello"); System.out.println("Before the function: "+str); Change(str); System.out.println("After the function: "+str); } public static void Change(StringBuffer tempStr) { tempStr=(new StringBuffer("World!")); System.out.println("In the function: "+tempStr); } }
上面代码的输出结果为:
Before the function: Hello
In the function: World
After the function: Hello
有人可能不解,不是说Java中在此种情况下传递的是对象的引用,为什么”After the function: Hello“?应该是"After the function: World"才对啊!首先,此时传递的是确实是对象str的引用,即tempStr和str指向同一内存。但为什么最后tempStr和str结果不一样呢?原因在于在“tempStr="World";”执行后,tempStr指向“World”的地址,所以str的只并未改变。此时可以通过调用对象的方法改变原对象的值。
package JavaLanProtocol; public class Method { public static void main(String []agr) { StringBuffer str = new StringBuffer("Hello"); System.out.println("Before the function: "+str); Change(str); System.out.println("After the function: "+str); } public static void Change(StringBuffer tempStr) { tempStr.append(" World!");
System.out.println("In the function: "+tempStr); } }
上述代码执行后结果为:
Before the function: Hello
In the function: Hello World!
After the function: Hello World!
此时str的只改变了,原因在于通过对象引用调用对象的方法改变原对象的值。为什么呢?此时tempStr和str指向同一内存,执行“tempStr.append(" World!");”后,在原有对象的某位加上“ World”。
上述结果不同的区别在于前者tempStr指向了其他内存单元,而后者始终指向同一内存单元。下面看看以下代码:
package JavaLanProtocol; public class Method { public static void main(String []agr) { String str=new String("Hello"); System.out.println("Before the function: "+str); Change(str); System.out.println("After the function: "+str); } public static void Change(String tempStr) { tempStr.toUpperCase(); System.out.println("In the function: "+tempStr); } }
结果是:
Before the function: Hello
In the function: Hello
After the function: Hello
可能与有些人的想法不一样,他们可能认为应是:
Before the function: Hello
In the function: HELLO
After the function: HELLO
其实不然,String是不可变的,是const变量。
下面再看一个例子:
package JavaLanProtocol; public class Method { public static void main(String []agr) { StringBuffer str = new StringBuffer("Hello"); System.out.println("Before the function: "+str); Change(str); System.out.println("After the function: "+str); } public static void Change(StringBuffer tempStr) { tempStr.append(" World"); StringBuffer temp=new StringBuffer("World"); tempStr=temp; temp.append(" Hello"); System.out.println("In the function: "+tempStr); } }
如果一眼就能看出结果是:
Before the function: Hello
In the function: World Hello
After the function: Hello World
那就OK。