當前位置:才華齋>計算機>java語言>

Think in Java之構造器的真正呼叫順

java語言 閱讀(2.06W)

構造器是OOP的重要組成部分,很多人認為它很容易。只不過是new了一個物件而已。而think in java的作者卻告訴我們,其實這並不容易。下面一起學習一下吧!

Think in Java之構造器的真正呼叫順

先看下面這個例子。在你沒看結果之前,你覺得你的答案是對的麼。

package u.t1;

class Meal {

Meal() {

tln("meal");

}

}

class Bread {

Bread() {

tln("Bread");

}

}

class Cheese {

Cheese() {

tln("Cheese");

}

}

class Lettuce {

Lettuce() {

tln("Lettuce");

}

}

class Lunch extends Meal{

Lunch() {

tln("Lunch");

}

}

class PortableLunch extends Lunch{

PortableLunch() {

tln("PortableLunch");

}

}

public class Sandwich extends PortableLunch {

private Bread b = new Bread();

private Cheese c = new Cheese();

private Lettuce l = new Lettuce();

public Sandwich() {

tln("Sandwich");

}

public static void main(String[] args) {

new Sandwich();

}

}

控制檯的列印結果為:

meal

Lunch

PortableLunch

Bread

Cheese

Lettuce

Sandwich

複雜物件呼叫構造器的順序應該遵循下面的原則:

1、呼叫基類[即父類]構造器。這個步驟會不斷反覆遞迴下去,首先是構造器這種層次結構的根,然後是下一層匯出類[即子類],等等。直到最底層的匯出類。[從最上層的meal一直遞迴到PortableLunch]

2、按宣告順序呼叫成員的初始化方法。[即上面的Bread,Cheese,Lettuce]

3、呼叫匯出類構造器的主體[即Sandwich]

可見,呼叫類本身是最後完成初始化的,最先完成初始化的是最頂級的基類,所謂沒有父親,哪來的兒子。處於它們中間的是呼叫類本身擁有的子物件。因為你不可能在子物件初始化之前用本類呼叫它,所以它一定在本類呼叫之前,父類呼叫之後完成初始化的。

那麼這個說法是不是一定成立呢。結果是否定的。你必須知道JVM的編繹原理才可能知道,它究竟是如何工作的`。

我們來看下面這個例子,來解釋為什麼它不一定。因為在繼承和重寫的時候,這種情況變得有點詭異。

深入探究:

package u.t1;

public class ConstrcutorTest2 {

public static void main(String[] args) {

new RoundGlyph(5);

}

}

class Glyph {

void draw() {

tln("Glyph draw()");

}

Glyph() {

tln("Glyph before draw();");

draw();

tln("Glyph after draw();");

}

}

class RoundGlyph extends Glyph {

private int radius = 1;

RoundGlyph(int r) {

radius = r;

tln("RoundGlyph(),radius:" + radius);

}

void draw() {

tln("(),radius:" + radius);//此處列印是0,而不是1

}

}

控制檯列印結果:

Glyph before draw();

(),radius:0

Glyph after draw();

RoundGlyph(),radius:5

為什麼(),radius:0這裡會是0呢。

預設的1哪去了?值自己會變麼。其實上面的講述並不完整。,而這正是解決謎題的關鍵所在。初始化的實際過程之前,實際在還有一步。

0:在其他任何事物發生之前,將分配物件的存捨得空間初始化為二進位制的零。

而它後面的初始化順序就是上面的3步。

呼叫基類[即父類]構造器。這個步驟會不斷反覆遞迴下去,首先是構造器這種層次結構的根,然後是下一層匯出類[即子類],等等。直到最底層的匯出類。

按宣告順序呼叫成員的初始化方法。

呼叫匯出類構造器的主體

也就是說,實際上有4步,知道這些你對物件初始化構造器才可能有個清楚的認識。

JAVA有更多的精髓等著人們去挖掘,而不僅僅是知道如何去使用它。

因為你不知道什麼時候它會出現意想不到的後果,而這個錯誤,可能你根本就想不出來。

編寫構造器時有一條準則:

用盡可能簡單的方法使物件進入正常狀態,如果可以的話,避免呼叫其它方法。

在構造器內唯一能夠安全呼叫的那些方法是基類中的final或者private方法,這些方法不能被覆蓋,因此也就不會出現令人驚訝的問題。

你可能無法總是遵循這條準則,但是應該朝著它努力。

學任何語言,請打好基礎,它是你以後擴充套件的人生基石。