Java参数传递是传值还是传引用?

参考:http://ifeve.com/stackoverflow-reference-or-value/
   http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

在Java的规范里说明了在Java中一切参数都是按值传递的,根本就没有引用传递这一说。
理解这个概念的关键是要明白:

Dog myDog;

这里声明的并不是一个Dog对象,而是一个指向Dog对象的指针。
这是什么意思呢,就是当你执行:

Dog myDog = new Dog("Rover");
foo(myDog);

本质上是你把创建好的Dog对象的地址传递给foo方法。(我说的‘本质上’其实是因为Java中的指针并不是直接的地址,不过可以简单的理解成这样)。
假设Dog对象在内存中的地址是42。那我们就是把42这个值传递给了foo方法。

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

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

  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的指向就会被改变。

Let me explain this through an example:

public class Main{
     public static void main(String[] args){
          Foo f = new Foo("f");
          changeReference(f); // It won't change the reference!
          modifyReference(f); // It will modify the object that the reference variable "f" refers to!
     }
     public static void changeReference(Foo a){
          Foo b = new Foo("b");
          a = b;
     }
     public static void modifyReference(Foo c){
          c.setAttribute("c");
     }
}

I will explain this in steps:
1.Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".

Foo f = new Foo("f");


2.From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.

public static void changeReference(Foo a)

3.As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.

changeReference(f);

4.Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".

Foo b = new Foo("b");

5.a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".

6.As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".

7.c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,857评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,273评论 19 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,874评论 18 399
  • “我对你动心了,这的确是一个错误。”我是这样直截了当的告诉了那个人。对方一脸诧异,然后很惊奇的看着我...
    繁华宛如一掬细沙阅读 710评论 0 0
  • 月光如水水如天,天边炊烟飘过肩 外婆菜肴美又鲜,碗中月儿圆又圆 今夜好梦来敲门,梦中溜进广寒宫 身上满是桂花香,嘴...
    为独行找个借口阅读 111评论 0 0