JAVA中的参数传递

其实JAVA里对参数的传递在国际上都是一直有争论的。包括《Thinking in java》里都提到了,Bruce Eckel 也没给出定论。我觉得这很大程度上是由于规范不严格造成的。因为大家都知道参数传递的本质是什么,但描述方式不一样,以致造成答案不一致。

现给一些参考:

第一,JAVA 里的参数传递只有值传递,没有所谓的引用传递。(说白了,是因为大家的说法
不统一)
第二,引用一个强人的观点:

“1. 首先明白参数的传递实质是压栈和出栈的过程。即在调用一个方法(或说子程序)之前,先将需要传入的参数压栈,然后执行代码的指针跳转到方法的起始位置,进行出栈操作,原来压入栈中的参数取出置入方法中的局部变量(这里即参数变量)。

2. 对于基本类型,传递的参数都是对原变量值的拷贝。每一个基本类型的数据都是以字节形式保存在内存中的(如整型是4个字节,长整型是8个字节等),压栈时会将内存中的变量值按字节存入栈中,而原变量的值(即保存在原位置的内容)并不改变??内存中的数据是保存在堆中的,参数是保存在栈中的,总不可能把内存块搬过来是吧……所以一定是拷贝的!

3. 先搞明白引用的实质。当一个对象创建后,它的内容(N个字节)被保存在内存中。它的位置,即一个地址,被返回,保存在一个引用变量中??所以实际上一个引用变量保存的只是某个类的地址,而引用的类型,并不会改变引用变量的大小,它只是说明一个对象的数据大小。这样,就可以从引用变量找到对象的起始地址,再通过类型,获取对象数据。而通过引用调用的方法,属性这些东西,就是通过在这块内存地址中的位置偏移来寻址的。(当然,实际的操作会比我说的复杂得多,因为还涉及向上向下传型等问题)

4. 引用参数的传递,实际上就是传递的引用变量的值,这和传递基本类型的值原理是一样的。但由于引用变量其值的特殊性(只是一个地址,这个地址上保存的才是对象的实际数据),所以,引用变量的值传入参数变量后,通过参数变量对对象的修改(在实际地址上的操作)自然就会影响到同一个对象。??这里,外面的引用变量和参数变量,本身是不同的,但是它们的值相同,都是对象的地址。”


写个小例子证实一下:

/*
* TestClass.java

* Created on 2005-9-15
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package myutil;

public class TestClass {
int i;
String s;
public TestClass(){

}
public void change(){
this.s+=”||hello”;
this.i+=1000;
}
}


/*
* TestParameter.java

* Created on 2005-9-15
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
**package **myutil;

**public **class TestParameter {
**private **void changeBaseType(int i,char c,long l){
i++; c++; l++;
}

**private **void changeObject(String s,TestClass ic){
s=s.substring(2);
ic.change();
}
**public **static void main(String[] args) {
TestParameter tp=new TestParameter();
TestClass tc=new TestClass();
tc.i=1000;
tc.s=”KongChen”;
int i=0;
char c=’a’;
long l=32;
String ss=new String(“It is too late now”);
System.out.println(“Before–i,c,a:”+i+”,”+c+”,”+l);
System.out.println(“Before–ss,tc.i,tc.s:”+ss+”,”+tc.i+”,”+tc.s);
tp.changeBaseType(i,c,l);
tp.changeObject(ss,tc);
System.out.println(“After–i,c,a:”+i+”,”+c+”,”+l);
System.out.println(“After–ss,tc.i,tc.s:”+ss+”,”+tc.i+”,”+tc.s);
}
}


运行结果

Before–i,c,a:0,a,32
Before–ss,tc.i,tc.s:It is too late now,1000,KongChen
After–i,c,a:0,a,32
After–ss,tc.i,tc.s:It is too late now,2000,KongChen||hello

Written on September 15, 2005