2016-08-02 150 views
2

我看过这段代码,我不明白为什么这个程序会打印1为什么这个程序输出1?

首先,在foo(myObject)我们正在分配一些东西到最后,这怎么可能?

而第二件事,foo()完成后,我们会得到myObject为空,那么我们怎么能打印它呢?

public class MyClass { 
    private int myInt; 
    public static void foo(MyClass myObject) { 
     myObject.myInt = 1; 
     myObject = null; 
    } 
    public static void main(String[] args) { 
     final MyClass myObject = new MyClass(); 
     myObject.myInt = 2; 
     foo(myObject); 
     System.out.println(myObject.myInt); 
    } 
} 
+3

因为'myObject.myInt = 1'。你期望它是什么? – bradimus

+2

@bradimus它不那么简单......在打印语句之前将对象设置为null,这可能会导致不熟悉Java的人员感到困惑。 –

+0

你知道java如何将对象传递给另一个方法吗? –

回答

10

首先,在foo(myObject)我们正在给final分配一些东西,它是如何可能的?

对象final,在main可变final。因此,在main中,如果您在设置其值的初始行之后添加了myObject = somethingElse;,它将无法编译,因为您无法在变量中输入新值。这对变量引用的对象是否可变是没有影响的。

第二件事,foo()已完成后,我们会得到myObject是空的,所以我们怎么能打印呢?

有两个独立的东西在你的代码中调用myObject

  1. 中的变量main

  2. 在中foo

代码中的参数将参数设置为null,但这对main中的变量没有任何影响。 (实际上,foo不可能对main中的变量产生任何影响; Java是一种纯粹按值传递的语言,正如您所演示的,所有foo都可以修改对象的状态,变量和参数引用,使用传入它的对象引用作为参数。)

我们只是这一行foo前停止代码:

myObject.myInt = 1; 

下面是我们在内存(留下了一些细节和不相干):

 
         +−−−−−−−−−−−−−−−−−−−−−−+ 
         | variable "myObject" |   foo can change the 
         +−−−−−−−−−−−−−−−−−−−−−−+   *state* of this 
foo can't change this−−>| Ref22458    |−−−+     | 
         +−−−−−−−−−−−−−−−−−−−−−−+ |     v 
                | +−−−−−−−−−−−−−−−−−−−−−−−−+ 
         +−−−−−−−−−−−−−−−−−−−−−−+ +−−−>| object of type MyClass | 
         | parameter "myObject" | | +−−−−−−−−−−−−−−−−−−−−−−−−+ 
         +−−−−−−−−−−−−−−−−−−−−−−+ | | myInt: 2    | 
foo can change this−−−−>| Ref22458    |−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−+ 
         +−−−−−−−−−−−−−−−−−−−−−−+ 

...其中“ Ref22458“只是指向您在main中创建的对象的对象引用值的名称。

一旦我们执行在foo两条线:

myObject.myInt = 1; 
myObject = null; 

我们有这样的记忆:

 
         +−−−−−−−−−−−−−−−−−−−−−−+ 
         | variable "myObject" |   foo can change the 
         +−−−−−−−−−−−−−−−−−−−−−−+   *state* of this 
foo can't change this−−>| Ref22458    |−−−+     | 
         +−−−−−−−−−−−−−−−−−−−−−−+ |     v 
                | +−−−−−−−−−−−−−−−−−−−−−−−−+ 
         +−−−−−−−−−−−−−−−−−−−−−−+ +−−−>| object of type MyClass | 
         | parameter "myObject" | | +−−−−−−−−−−−−−−−−−−−−−−−−+ 
         +−−−−−−−−−−−−−−−−−−−−−−+ | | myInt: 1    | 
foo can change this−−−−>| null     |−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−+ 
         +−−−−−−−−−−−−−−−−−−−−−−+ 

注意如何foo可以改变对象的状态(myInt现在1)并且可以更改参数myObject(现在的null)中的值,但不能更改变量myObject(有两个原因:它无法访问变量[Java是按值传递],变量为final)。

0

Java未能按引用传递(引用是按值传递),分配给myObjectnull不会有所作为。这两个都不是final,因为它不是在你的foo()方法中最终确定的。它打印1,因为您将myObject的引用传递给foo()并设置其字段。它仍然是一个可变对象,所以它的值被更新。

0

final只是指定该对象本身不应该改变 - 当与像你的代码这样的类一起使用时,它只会阻止某人做出myObject = ...。除非你标记为MyClass.myInt final,否则即使在赋值之后,你也可以将任何值分配给所需的int。

解决这个问题的方法是使myInt私人并为它提供了一个公共的吸气剂代替,从而防止其被修改(除了由反射)

+0

但是,myObject = null在foo()里面很有趣,是不是最后一个助手? – limitless

+4

@limitless号这些是在不同范围内的独特参考。 – bradimus

+0

@limitless这只适用于'foo()'的范围内。你没有设置在'main'中声明为final的'myObject',你为'foo'方法设置了参数'myObject'。 – apemanzilla