2016-08-02 206 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