怎么理解java参数传递只是传值方式

| Comments

Java参数传递只是传值

一开始学java,就有人告诉你,Java参数传递,只有传值,没有传引用。但是我在平时仍然发现,在面试时有不少人搞混, 也见过有人写出问题代码,特别是许多习惯c++编程习惯的童鞋。为了让大家都能理解,我们还是再来复习一遍。

什么是传引用

首先我们来看看什么是传引用方式? 这个概念在C++里边很常用,例如下面的代码:

void handle(const char* filename, int left, Callback& cb);

使用引用(第三个参数),就相当于直接使用实参一样,可以直接改变对象的内容,甚至可以让它指向另外一个对象。 相对于传值(第二个参数)来说,可以减少拷贝对象带来消耗,相对于传递指针方式(第一个参数),无需担心空指针问题,还能够改变对象的引用。

看上去,传递引用好像是集大成的功能,但实际使用上并不是每个参数都会这么搞。为什么? 因为它赋予子函数的权利太大, 对参数的任何修改都会受影响,特别是改变引用这种极端操作。

于是,Java大大减少了语法的灵活性,只保留了传值方式(因为没有指针,所以也没有所谓的指针传递)。

从内存布局看传值

因为没有指针,而且有基本类型和类类型的区别,所以有些童鞋对传值的理解有偏差。下面在从内存布局上看看。 在Java中,new出来的对象都是在heap里边生成,但是本地变量是在方法栈里边的。考虑下面的代码:

A a = new A();
a = call(a);

A call(A a){
   a.setName("a");
   a = new A();
   a.setName("b");
   return a;
}

看图,从左到右,从上到下,其中左边的是本地变量列表,右边的是堆空间,每行一个小图,其他不解释。 test

传的是什么值?

上面列举的情况是类类型的情况,实际上传值做的是本地变量的拷贝,而不是堆对象的拷贝。有些人会产生疑惑, 主要是因为java在语法上隐藏了指针,其实,对于类类型的参数传递,和c++中传指针方式是一个道理的,只有基本类型才是实实在在的传值方式。

Comments