2014-03-26 248 views
3

我正在收集個人備忘單的設計模板,並且我發現了一個至少對我而言奇怪的代碼Head First Design Patterns(Eric Freeman,Elisabeth Robson,Bert Bates,Kathy Sierra)屬性初始化Java

我不認爲我確切地允許在這裏發表的一段代碼在寫這本書,但我將重現讓我震驚的代碼:

假設我們先前deffined類A用公共方法runSomeCode(),然後我們B類如下:

public class B { 

    A a; 
    A b; 
    A x = a; 

    public B() { 
     a = new A(); 
     b = new A(); 
    } 

    public void testB() 
    { 
     x.runSomeCode(); 
    }  
} 

我的第一印象看這個代碼是進行B實例任何呼叫TESTB方法應該拋出一個NullPointerException但我無法想象他們會發表了這樣一個錯誤。

如果這本書是正確的話,我明白,

x = a; 

必須在B處的構造函數執行結束時進行,但我仍然這樣sintaxis感到驚訝,我的問題是:

  • 上午我錯了?
  • Java總是表現得像這樣嗎?
  • 在這種情況下(我個人認爲這有點令人困惑):它可能會在未來的Java版本中被刪除嗎?
  • 你會盡量避免它嗎?

編輯這是本書例如:

enter image description here

我關心的是這樣,當numberGumballs = 0;

編輯II

我想我知道用的例子發生了什麼事。

在書中,被引用的類是不是聲明爲靜態,但幾分鐘前,我認爲它可以編譯,如果A是靜態的。所以,也許,這本書的作者從一個更大的項目中得到了使用靜態類的代碼。所以我嘗試了這一點,這一次,它確實有效,但是這個例子似乎仍然是錯誤的,下面的代碼對State pattern沒有任何意義。

public class B { 

    public static class Base { 
     public static void runSomeCode() { System.out.println("Base!"); } 
    } 

    public static class A extends Base { 
     public static void runSomeCode() { System.out.println("A!"); } 
    }; 

    A a; 
    A b; 
    A x = a; 

    public B() { 
     a = new A(); 
     b = new A(); 
    } 

    public void testB() 
    { 
     x.runSomeCode(); 
    }  
} 

然而,另一個編輯

看來我還沒有注意到書中例如這個問題的第一個, 在O'Reilly site errata section, under unconfirmed erratas sub-section你可以找到:

enter image description here

+0

它確實會拋出一個NPE,你可以(實際上)嘗試它。 – m0skit0

+1

@ m0skit0你是對的我在深夜測試了這個案例,我可能做了一些不同的事情。然而,這本書的例子就是這樣,所以書本錯了,或者我是盲人/白癡 –

+1

書中的例子是錯誤的,有時會發生;) – m0skit0

回答

1

回答您的問題:

  1. 我相信你是錯的,根據構造函數體前Java 8 Specification字段初始執行
  2. 我相信它有,但不想每個版本都通過規範。我不知道有任何變化。
  3. 我對此表示懷疑,看看它是如何成爲規範的一部分,並且如果他們改變了它,會破壞兼容性。但是
  4. 在這種情況下,通過將賦值移動到構造函數x中,可以輕鬆地將代碼更改爲明確指出初始化的順序。將它作爲字段初始值設定器沒有任何好處,這對我來說是顯而易見的。

什麼應該是這個「模式」的重點?你只需要兩個引用,其中一個會完成......爲什麼不使用a呢?

1

我錯了嗎?

就地變量初始化在構造函數初始化之前工作,其順序與代碼中定義的變量順序相同。

Java總是表現得像這樣嗎?

是的。

在這種情況下(我個人認爲這有點令人困惑): 它可能在未來的Java版本中被刪除?

不,Java是向後兼容的語言,這是基本的,不會被改變。

你會盡量避免它嗎?

如果要進行就地初始化,請確保它獨立於其他變量的初始化。否則,在構造函數中初始化它。不要進行復雜的就地初始化。

+0

我已經在這個問題中說過,據我所知,這是沒有意義的。另一方面,我在深夜對它進行了測試,我想我可能做了一些不同的事情,但我會盡力重現它。 –

1

當您首次創建類型B的對象時,首先初始化具有任何初始化的字段。因此,即使在構造函數中的代碼被執行之前,A x = a;被執行,它將x的值設置爲null,因爲a沒有被實例化並且僅僅是類型A的空引用。之後,執行下面的代碼創建兩個對象。

public B() { 
    a = new A(); 
    b = new A(); 
} 

此時x仍爲空。所以當你嘗試在使用x的A類中執行一個方法時,它會拋出一個空指針異常。

+0

我已經在這個問題中說過,據我所知,這是沒有意義的。另一方面,我在深夜對它進行了測試,我想我可能做了一些不同的事情,但我會盡力重現它。 –