2011-10-04 53 views
3

我正在查看遊戲中的一些代碼,並且遇到了以前沒有看到過的內容,而且我也不知道發生了什麼。抽象類使用它自己的抽象方法?

public abstract class Entity 
{ 

    public Entity(World world) 
    { 
     // irrelevent code 
     entityInit(); 
    } 

    protected abstract void entityInit(); 
} 

這是怎麼回事?當它呼叫entityInit()時會發生什麼?

回答

7

抽象類從未實例化。只有它的具體子類可以被實例化。所以,當調用具體子類(我們稱之爲Foo)構造函數時,它調用super(world)。實體構造函數然後調用entityInit(),已被Foo覆蓋。因此它稱爲Foo entityInit具體方法。

請注意,這是不好的做法,因爲entityInit方法將在尚未完全構建的對象上調用。因此,子類必須確保此方法不訪問它可能聲明的任何字段,因爲它們都將被單元化。

+0

哦,我明白了。這讓我感到困惑了一些(我對編程相當陌生),但是這樣做可以解決問題。謝謝! –

1

嗯,沒什麼。

除非具體類實現抽象方法entityInit,否則將無法創建將使用該方法的Entity類。

+0

確定這就是我是那種的想法,但我不確定幾件事情:編譯器是否查找實現該方法的類?如果有多個擴展'Entity'並實現'entityInt()'的類會怎麼樣?它選擇哪一個? –

+0

@Eegabooga;不,你有點不對。編譯器不會*查找實現它的類;作爲編寫該代碼的用戶,您將是實現此抽象類的用戶,然後您就是使用它的用戶。 「猜測」並不是編譯器的工作。 – darioo

1

因爲無論如何你需要創建一個具體的子類,所以你也需要實現entityInit()。該方法將被調用。

您不能創建抽象類和具體類(您可以創建實例)的實例不能有抽象方法。所以一切都很好。

注意:如果您訪問子類中定義的字段,在entityInit()中訪問它們可能會導致NullPointerException,因爲它們可能未被初始化。

例(根據您的類):

class Person extens Entity { 
    private String name = "Player"; 

    protected void entityInit() { 
    int nameLen = name.length(); //NPE here!!! 
    } 
} 

雖然這個例子沒有太大的邏輯意義,應該說明這一點。 首先調用Entity構造函數,然後調用entityInit()。但是,由於Person的初始化程序塊尚未運行,因此name仍爲空。

1

這是一種常見的做法。您在頂級方法中使用抽象方法,實現者只需要實現抽象,所以邏輯將留在基類中。

對不起都沒有注意到這是一個構造器...在這個位置很奇怪....

3

會發生什麼事是,entityInit()具體子類的實現被調用。由於Entity是抽象的,因此其構造函數只能從具體子類的構造函數中調用,該構造函數的實現必須爲entityInit()

從abstact類的代碼中調用抽象方法實際上非常普遍,幾乎是抽象方法的全部要點。另見template method pattern

但是,調用從構造抽象方法如在本情況下是problematic and should be avoided,主要是因爲抽象方法將未完全處於不一致的狀態初始化,並因此可能在物體上運行。具體來說,entityInit()的實現將在它定義的類的構造函數之前運行。

0

不要從構造函數調用抽象/虛擬方法。它會調用具體的子類實現。但具體的子類的成員變量將不會被初始化。

另一種說法是不要讓你的從構造函數體轉義。

但是在這種特殊情況下,該方法的全部目的是初始化this對象的成員。所以沒關係。但是通過這種方法,我們必須鏈接超級類的方法調用(如果它具有實現)。

2

那麼,大多數情況下,這用於Template Method patternEntity的子類,非抽象類將實現entityInit()方法。這些子類實現必須爲該類定義其entityInit()的方式。

在維基百科,它說....

在面向對象的編程中,第一類被創建,它提供一個 算法設計的基本步驟。這些步驟使用抽象方法實施 。稍後,子類將更改抽象方法 以實施實際操作。因此,一般算法在一個地方保存爲 ,但具體步驟可以由子類改變。

在你的情況,你會不會擔心要entityInit()本身的子類,作爲構造函數會做此默認:

例子:

public class StrictEntity extends Entity { 

    public StrictEntity(World world) { 
     super(world); //This will call entityInit(); 
    } 

    protected void entityInit() { 
     //Example, don't take it as genuine. 
     PropertyConfig.getInstance.setStrict(true); 
    } 
}