为什么这个程序输出1?

时间:2016-08-02 17:09:29

标签: java oop

我查看了这段代码,但我不明白为什么这个程序会打印1

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

第二件事,在完成foo()之后,我们会将myObject设为null,那么我们怎样才能打印它?

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 个答案:

答案 0 :(得分:10)

  

首先,在foo(myObject)我们正在为final分配内容,它是如何构成的?

对象不是finalmain中的变量final。因此,在main中,如果您在设置其值的初始行之后添加myObject = somethingElse;,则无法编译,因为您无法在变量<中添加新值/ strong>即可。这对变量引用的对象是否可变是没有影响的。

  

第二件事,在foo()完成后,我们会让myObject为空,那么我们怎样才能打印出来?

您的代码中有两个名为myObject单独的项:

  1. main

  2. 中的变量
  3. foo

  4. 中的参数

    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             |−−−+    +−−−−−−−−−−−−−−−−−−−−−−−−+
                            +−−−−−−−−−−−−−−−−−−−−−−+
    

    ......其中&#34; Ref22458&#34;只是指向您在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),并且可以更改参数中的值 {{1 (它现在是myObject),但无法更改变量 null中的值(原因有两个:它无法访问变量[Java是按值传递],变量是myObject)。

答案 1 :(得分:0)

Java不是通过引用传递的(引用是按值传递的),将myObject分配给null并没有什么不同。它不是final,因为它不是foo()方法中的最终版本。它打印1,因为您将myObject的引用传递给foo()并设置其字段。它仍然是一个可变对象,所以它的值会更新。

答案 2 :(得分:0)

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

解决此问题的方法是将myInt设为私有,并为其提供公共getter,防止其被修改(反射除外)