天天看点

理解JAVA的传值方式

问题: java的参数传递的是值还是引用?

我们经常会被问到这样的问题,当我调用某个方法时,通过参数传递过去的是变量本身,还是一个变量的复制品?问题的答案留到讨论后给出。

首先,你需要了解下java变量的分类:java中的变量分为

基本类型

接口类型

类类型

数组类型

其中后面三种统称为引用类型,而基本类型分为三种,

数字类型

boolean

returnaddress

数字类型又分为

浮点类型

整数类型

浮点

整数又有具体的内容,这里不再展开说明。其中,returnaddress是java虚拟机内部使用的类型,它被用来实现java程序中finally子句。这里主要看引用类型和基本类型数字类型情况(boolean类型的情况和基本类型一致).

先看参数为基本类型的情况:

<code>01</code>

<code>public</code> <code>class</code> <code>demo1 {</code>

<code>02</code>

<code>    </code><code>public</code> <code>void</code> <code>swap(</code><code>int</code> <code>a, </code><code>int</code> <code>b) {</code>

<code>03</code>

<code>        </code><code>a = a ^ b;</code>

<code>04</code>

<code>        </code><code>b = a ^ b;</code>

<code>05</code>

<code>06</code>

<code>        </code><code>system.out.println(</code><code>"swap: a="</code> <code>+ a + </code><code>",b="</code> <code>+ b);</code>

<code>07</code>

<code>    </code><code>}</code>

<code>08</code>

<code>09</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>

<code>10</code>

<code>        </code><code>demo1 demo1 = </code><code>new</code> <code>demo1();</code>

<code>11</code>

<code>        </code><code>int</code> <code>a = </code><code>1</code><code>;</code>

<code>12</code>

<code>        </code><code>int</code> <code>b = </code><code>2</code><code>;</code>

<code>13</code>

<code>        </code><code>demo1.swap(a, b);</code>

<code>14</code>

<code>        </code><code>system.out.println(</code><code>"main: a="</code> <code>+ a + </code><code>",b="</code> <code>+ b);</code>

<code>15</code>

<code>16</code>

<code>}</code>

输出

<code>1</code>

<code>swap: a=2,b=1</code>

<code>2</code>

<code>main: a=1,b=2</code>

上面的代码想通过swap交互a和b的值,在swap内部,变量a和b已经交换成功了,但在main中a和b的值依然是原来的值.

再看参数为引用的情况:

<code>&lt;/pre&gt;</code>

<code>&lt;pre&gt;</code><code>public</code> <code>class</code> <code>demo2 {</code>

<code>     </code><code>public</code> <code>void</code> <code>swap(stringbuffer a,stringbuffer b){</code>

<code>            </code><code>stringbuffer c = a;</code>

<code>            </code><code>a=b;</code>

<code>            </code><code>b=c;</code>

<code>         </code><code>system.out.println(</code><code>"swap: a="</code><code>+a+</code><code>",b="</code><code>+b);</code>

<code>     </code><code>}</code>

<code>   </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>

<code>      </code><code>stringbuffer a = </code><code>new</code> <code>stringbuffer(</code><code>"a"</code><code>);</code>

<code>      </code><code>stringbuffer b = </code><code>new</code> <code>stringbuffer(</code><code>"b"</code><code>);</code>

<code>      </code><code>demo2 demo2 = </code><code>new</code> <code>demo2();</code>

<code>      </code><code>demo2.swap(a, b);</code>

<code>      </code><code>system.out.println(</code><code>"main: a="</code><code>+a+</code><code>",b="</code><code>+b);</code>

<code>   </code><code>}</code>

<code>17</code>

<code>}&lt;/pre&gt;</code>

<code>18</code>

<code>&lt;pre&gt;</code>

大家可以先思考下,上面的输出是什么?

输出:

swap: a=b,b=a

main: a=a,b=b

和参数为基本类型的情况结果是一致的.

为什么会出现这种情况呢?

我们来分析下上面的参数传递过程,以demo2为例:

图1是swap未计算前的参数值,

理解JAVA的传值方式

图2是swap计算后的参数值.

理解JAVA的传值方式

从图中可以看出,swap的计算过程只能改变swap内部变量a和b的值,不能改变main中的a和b变量的引用值,换言之,参数的传递只能传值,不存在传引用一说.

请注意,上面我说不能改变a和b变量的引用值,可没说不能改变a和b指向的对象的值.再看下面的例子:

<code>public</code> <code>class</code> <code>demo3 {</code>

<code> </code><code>public</code> <code>void</code> <code>swap(stringbuffer a,stringbuffer b){</code>

<code> </code><code>a.append(b);</code>

<code> </code><code>stringbuffer c = a;</code>

<code> </code><code>a=b;</code>

<code> </code><code>b=c;</code>

<code> </code><code>system.out.println(</code><code>"swap: a="</code><code>+a+</code><code>",b="</code><code>+b);</code>

<code> </code><code>}</code>

<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>

<code> </code><code>stringbuffer a = </code><code>new</code> <code>stringbuffer(</code><code>"a"</code><code>);</code>

<code> </code><code>stringbuffer b = </code><code>new</code> <code>stringbuffer(</code><code>"b"</code><code>);</code>

<code> </code><code>demo3 demo3 = </code><code>new</code> <code>demo3();</code>

<code> </code><code>demo3.swap(a, b);</code>

<code>这个会输出什么呢?</code>

<code>19</code>

<code>20</code>

<code>swap: a=b,b=ab</code>

<code>21</code>

<code>swap: a=ab,b=b</code>

这个就是上面所说的,在swap内部的计算过程中,改变了main.a所指向对象的值.

就像下面的图所描述的那样:

理解JAVA的传值方式

理解JAVA的传值方式

但根本上,swap不能改变main中a和b的引用值.

另外贴一句sun公司官方文档上的描述这一问题的原话:

java is always pass-by-value.when object is passed as a argument, be careful with that it is also the copy of reference

所以,现在你应该知道,java传递的只会是值,没有传递引用.