2013-10-21 165 views
4

假设我有一个类和构造函数TestClass传递对象给构造函数传递参考

public class TestClass { 
    Foo foo; 

    public TestClass(Foo foo) { 
     this.foo = foo; 
    } 
} 

这里,构造函数接受一个对象,它是Foo类的一个实例。假设我的static void main(String[] args)执行以下操作,与TestClass完全分开;

  • (1)实例化foo

  • (2)通实例fooTestClass构造

  • (3)变更内部状态的foo

步骤之后( 3),将foo范围内的我的TestClass的实例的状态有变化吗?

+2

你也可以自己写一个小程序,虽然我会承认*为什么*发生这种事情不一定是你可以通过尝试小例子来学习的东西。 –

+1

@ DennisMeng这是真的,但是自己做这件事不会泄露经验丰富的回答者可以覆盖的任何边缘情况。 – user2763361

+0

回答您的称号,Java不具有引用传递。它通过价值传递参考,而这正在导致您遇到的问题。 –

回答

13

它是不是通过引用。相反,它通过的参考,这是一个微妙但重要的区别。

你在main()方法的其他变异foo后,foo现场还将展示这些突变,因为你的状态,因为这两个变量指向同一个实例。但是,如果您foo重新分配给了新内容,foo字段将不会更改。如果foo确实通过引用传递,则这不会成立。总之,所有东西都是通过Java传递的;恰好碰巧通过引用来处理对象,所以这些引用的值被传递。

我会试着用一个例子来说明这一点。考虑下面的类:

class A { 
    public int n; 

    public A(int n) { 
     this.n = n; 
    } 
} 

和下面的方法:

public static void mutate(A a) { 
    a.n = 42; 
} 

现在我们可以有这样的事情:

A a = new A(0); 
A.mutate(a); 

System.out.println(a.n); 
 
42 

我们可以看出,a状态改为mutate()。现在让我们修改静态方法:

public static void mutate(A a) { 
    a = new A(42); 
} 

,然后再试一次:

A a = new A(0); 
A.mutate(a); 

System.out.println(a.n); 
 
0 

正如你所看到的,a的状态不变。如果引用已经传递给函数,我们会期望重新分配的效果在方法范围之外是明显的。尽管如此,一些参考实际上已通过,因为变异引起的变化也会导致方法外的变化。

+1

+1只是第一段 – MadProgrammer

0

经过步骤(3)后,我的TestClass实例中的foo是否也有 其状态发生了变化?

是的。

你可能想通过this

更新,以读...

现在,假设你通过构造一个原始值...

public class TestClass { 
    int foo; 

    public TestClass(int foo) { 
     this.foo = foo; 
    } 

    public String toString() { 
     return "TestClass: " + foo; 
    } 
} 

public static void main(String args[]) { 
    int myFoo = 1; 
    TestClass test = new TestClass(myFoo); 
    myFoo += 2; 
    System.out.println("myFoo = " + myFoo); 
    System.out.println("yourFoo = " + test); 
} 

这将输出...

myFoo = 3 
yourFoo = 1 

这证明了改变原语值的事实不会改变构造函数/方法维护的值。

同样的,如果你改变了对象引用之后,你通过它

public class TestClass { 
    Foo foo; 

    public TestClass(Foo foo) { 
     this.foo = foo; 
    } 

    public Foo getFoo() { 
     return foo; 
    } 
} 

public static void main(String args[]) { 
    Foo myFoo = new Foo(); 
    TestClass test = new TestClass(myFoo); 
    myFoo = new Foo(); 
    System.out.println("myFoo == yourFoo = " + myFoo.equals(test.getFoo())); 
} 

将输出

myFoo == yourFoo = false 

由于对象引用是不一样的。

+0

值得注意的是,如果你有一个原始类型,而不是一个对象类型(例如,'int'而不是'Foo'),那么答案就是_no_。 –

+0

@DavidWallace当然不会与此争论,但这与“如果在将构造函数传递给它后创建了一个新的Foo实例,不会在TestClass内改变'Foo'的内部状态'但是这不是问题,因为无论如何我读它......所有这些只是让我游泳:P – MadProgrammer

+0

当然,不是在那里争论,我只是想着OP对边缘案例的评论,并且想知道“原始人“将被包含在该类别中,如果没有这个评论,这真的是一个是/否的问题 –

3

enter image description here是的,因为您将相同的对象分配给Foo类的另一个引用,即对象相同,但由两个引用引用。

+0

而且随着讨论的进行,场景对于原始类型肯定是不同的:) – Batty