27

是什么这2码之间的差:爪哇通过引用传递

代码A:

Foo myFoo; 
myFoo = createfoo(); 

其中

public Foo createFoo() 
{ 
    Foo foo = new Foo(); 
    return foo; 
} 

比。代码B:

Foo myFoo; 
createFoo(myFoo); 

public void createFoo(Foo foo) 
{ 
    Foo f = new Foo(); 
    foo = f; 
} 

这两段代码有什么不同吗?

+7

那里没有“通过引用”。它通过价值传递,价值是一个参考。代码B不编译,如果它不会改变myFoo。 – harold 2012-02-22 23:05:36

回答

165

Java总是通过值传递参数而不是通过引用。


让我通过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"); 
    } 
} 

我将在步骤解释:

  1. 声明名为Foof参考并将其分配给新对象Foo,属性"f"

    Foo f = new Foo("f"); 
    

    enter image description here

  2. 从方法方面,Foo类型的具有名称a参考被声明和它的最初分配给null

    public static void changeReference(Foo a) 
    

    enter image description here

  3. 作为调用方法changeReference,参考a将被分配给其被作为参数传递的对象。

    changeReference(f); 
    

    enter image description here

  4. 声明名为Foo类型的b,并将其与一个属性"b"分配给Foo类型的新对象引用。

    Foo b = new Foo("b"); 
    

    enter image description here

  5. a = b重新分配所述参考a NOT f到其它的属性是"b"的对象。

    enter image description here


  6. 作为调用modifyReference(Foo c)方法,创建了一个参考c和分配给该对象与属性"f"

    enter image description here

  7. c.setAttribute("c");会改变引用c指向它的对象的属性,它的引用f指向它同一个对象。

    enter image description here

我希望你现在知道如何传递对象作为参数在工作方法参数作为自己的变量声明的Java :)

+15

真棒解释!我觉得开悟了! – delita 2012-02-22 23:48:53

+10

圣牛。这已被多次提出并回答,但这是我见过的最精巧和最具艺术性的解决方案。好样的! – duffymo 2012-02-23 01:13:39

+0

你能比较一下“通过参考”的样子吗?对我来说有意义的是“传递值”,它传递f所引用的对象的内存地址。在** changeReference **中,** a **是一个新的变量,指向相同的内存地址,改变** **的值(或称为内存地址)只会改变** a **指向的内容而不是** f **。如果它是“通过引用传递”** f **将被传入,所以** a = f **,更改** a **的值(或引用的内存地址)会改变** f ** – 2013-10-09 16:59:13

8

由于Java严格按照值传递,即使对象的引用是按值传递的,第二个代码也不会按预期工作。关于此,请参阅众多讨论的“相关”部分。

2

思考。如果你是用一个单一的代码块替换方法调用,它看起来像这样:

Foo myFoo; 
{      //Method call starts here 
    Foo foo; 
    foo = myFoo; 
    Foo f = new Foo(); 
    foo = f; 
}      //Method call ends here 

即使方法参数具有相同的名称作为另一个变量,方法参数仍然是它自己的,独一无二的参考只有方法知道。这与Eng.Fouad上面所说的一样。

1

您应该知道的另一个重点是您传入该方法的对象类型。无论它是可变对象还是不可变对象。如果你传递一个不可变的对象,例如String,它将创建另一个副本并进行修改。更改不会反映到您的原始副本。

+0

不,在语言中没有“可变”或“不可变”的概念。因此,他们如何通过没有区别。 “更改不会反映到您的原始副本。”根据定义,一个不可改变的对象是没有办法“改变”的,因此这个陈述没有意义。 – newacct 2013-01-16 19:18:05