天天看点

Stackoverflow问答:Java是传值还是传引用?

原文地址 译者:叶文海([email protected]

译者注:这是一篇在stackoverflow上面的一个经典问题,也是java开发者容易混淆的一个问题,我节选了其中两个vote最高的回复进行翻译。

问题:我一直认为java的参数是按引用传递,然而我看过一些文章里说java的参数并不是按引用传递的,比如这篇,这让我很迷惑。java中的参数到底是按引用传递还是按值传递?

在java里参数是按值来传递的。比较难理解的可能是java传递的是对象的引用,但这些引用是按值传递。

比如:

在这个例子里面,执行完foo()方法之后,在main方法里再调用adog.getname()方法依然会返回”max”,在main方法中的

adog并没有因为foo()的执行而被重写,这说明了参数是按值来进行传递的。如果是按照引用来传递的话在执行完foo()

方法之后adog.getname()将会返回”fifi”。

就像这样:

我刚刚发现你引用了我的文章

Stackoverflow问答:Java是传值还是传引用?

(译者注:这位是提问者引用文章的作者)

在java的规范里说明了在java中一切参数都是按值传递的,根本就没有引用传递这一说。

理解这个概念的关键是要明白

这里声明的并不是一个dog对象,而是一个指向dog对象的指针。

这是什么意思呢,就是当你执行

本质上是你把创建好的dog对象的地址传递给foo方法。(我说的‘本质上’其实是因为java中的指针并不是直接的地址,不过可以简单的理解成这样)。

假设dog对象在内存中的地址是42。那我们就是把42这个值传递给了foo方法。

如果foo方法的定义如下:

让我们来看看执行的时候会发生些什么。

1. somedog的值设置为42。

2. 在aaa行

      a.somedog指向一个内存地址为42的dog对象。

      b.把dog(内存地址为42)对象的name属性改为max。

3. 在bbb行

      a.一个新的dog对象被创建,我们假设它的内存地址是74。

      b.把这个74的内存地址值赋给somedog。

4. 在ccc行

      a.somedog指向一个内存地址为74的dog对象。

      b.把dog(内存地址为74)对象的name属性改为rowlf。

5. 方法执行完毕。

现在让我们来想想在这个方法外面发生了什么:

mydog改变了吗?

这个问题的关键在于:

要明确mydog是一个指针,而不是一个实际的dog对象。所以答案是它没有改变,mydog的值还是42;它指向的还是最开始的那个dog对象(虽然在foo方法中的aaa行把它指向对象的name属性改成了max,但是它指向的还是那个最初的dog对象)。

这验证了改变所指对象的属性,但没有改变其指向。

java的运行机制跟c很像。你可以给一个指针赋值,然后把这个指针传递给一个方法,之后在这个方法中你可以改变这个指针指向对象的数据,但是你不能改变这个指针的指向。

在c++,ada,pascal以及其他支持引用传递的语言中你可以直接改变传递的参数。如果java是引用传递的话,那么在执行上面定义的foo方法的bbb行的时候somedog的指向就会被改变。

可以把引用参数当成被传递参数的别名,当这个别名被赋值的时候就相当于被传递的参数被赋值。

这对你有帮助吗?(我会把这个回答补充到我的文章里面去)。