2011-12-06 117 views
0

我在超類的構造函數中有抽象方法調用。我遇到了錯誤「構造函數調用必須是構造函數中的第一個語句」。因爲我需要在調用super的構造函數之前在我的子類中初始化一些狀態。在超類的構造函數中調用抽象方法

我明白,構造函數調用必須先..但它使我有一些問題。

我在我的超類中有一個抽象方法,所有的子類都實現它們。 但是,子類構造函數需要在運行抽象方法之前必須處理的參數。

在我的代碼,我在父類的構造抽象方法,這樣你就會明白課程的問題: 超類做:

  1. 獲取Info1和使用超(I1,I2)INFO2
  2. 通過子類

執行抽象方法,但沒想到,父類的構造知道它也需要INFO3和信息4,這是宣佈對線下 超() - 線。

我一直在想辦法讓超類的構造函數必須返回並從之前收集子類中的信息,但是我沒有想到任何東西。

此外,該方法不需要參數,因爲所有子類的抽象方法的參數都不相同。

那些有經驗的人,我該如何解決這個問題?

一些谷歌搜索後,它似乎與此有關: http://webcache.googleusercontent.co...s-constructor/

但仍然是一個新手,所以很難掛到.. 我覺得我可能已經避免了這一切如果我可以在處理完子類構造函數之後使用super(),那就麻煩了。根據要求

代碼:

abstract public class Prylar { 
     abstract public Integer value(); 

     private String itemName; 
     private Person owner; 


     public Prylar(Person thisOwner, String iN){ 
     owner = thisOwner; 
     itemName = iN; 
      value = value(); 
} 



    public class Smycken extends Prylar{ 
    private int antalStenar; 
    private boolean guldEllerSilver; 
    private int value; 

    public Smycken (Person who, String n, int aS, boolean material){ 
    super(who,n); 

    antalStenar = aS; 
    guldEllerSilver = material; 
} 




public Integer value() { 

    if (guldEllerSilver){ 
     value = 2000; 
    } 
    else{ 
     value= 700;} 
    value += (500*antalStenar); 

    return value; 
} 

}

我只想說,以結束這種感謝大家抽出寶貴時間來閱讀和幫助傢伙。對此,我真的非常感激。希望當別人有類似的問題時,他們會偶然發現這一點。

謝謝你們!

+4

我認爲你需要發佈您的代碼 –

+0

我能想到的2個選項 - 1.不要調用從方法在構造函數內部並明確地調用外部。 2.創建另一個抽象方法,捕獲附加信息並在抽象方法之前調用它。順便說一句,爲什麼你不能改變你的方法的簽名? – aishwarya

+0

我不明白你爲什麼在構造函數中調用value()並忽略結果。我猜猜這是一個錯字,真正的代碼是this.value = value(); ??? – user949300

回答

2

您面臨的問題是,當您從基類調用抽象(或任何overriden)方法時,子類實例未完全構造。確保對象實例完全構造的唯一方法是完成其構造函數。

解決您的問題的一種方法是使用構造函數僅用於構建實例並將(動態)初始化留給方法。在這樣的情況下,你可以用這樣的方法:

private boolean initialized = false; 

public synchronized boolean init() { 
    if (!initialized) { 
     // allocate resources, call abstract method(s) 
     initialized = true; 
    } 
    return initialized; 
} 

public synchronized void cleanup() { 
    if (initialized) { 
     // free resources, call abstract method(s) 
     initialized = false; 
    } 
} 

調用代碼可以在顯式調用init()cleanup()方法或離開呼叫init()一個模式:

public void doSomething() { 

    if (init()) { 
     // go! 
    } 
} 

內,您的init方法您可以調用抽象方法並確保完整的對象實例構造正確。

+0

所以你的意思是,而不是在構造函數中有抽象方法,我把它放在另一種方法 - 初始化方法,如你所建議的? 我將如何檢查初始化?甚至,我會如何初始化? –

+0

@丹尼斯,是的,這就是我的意思。假設從構造函數調用抽象方法是爲了初始化實例,可以在創建新實例之後直接調用init方法,或者在初次公開調用該對象時完成初始化。 – rsp

+0

謝謝,這是我做的,它似乎工作。 –

1

@rsp建議的顯式init()方法的替代方法是懶惰地計算其他結果。例如

public int getValue() { 
    if (value == 0) { // some constant or value that means not-computed yet 
     value = blah*foo*bar; 
    } 
    return value; 
} 

另外,它不像你的value()計算需要很多時間。只是總是重新計算它。 30年前,你會緩存所有這些東西。緩存創建對象爲空或陳舊的錯誤。或子類。 :-)現在處理器的速度更快,通常只需重新計算就簡單一些,偶爾甚至更快。

0

查看提交的代碼示例,沒有跡象表明抽象方法在基類中使用。我希望這是爲了簡化。否則,將該方法定義爲抽象是沒有意義的。

要在由子類計算的基類中緩存值,您不應該使用構造函數。在子類的構造函數有機會爲其傳遞數據之前調用該方法,導致您觀察到的效果。

相反,我會爲抽象的方法定義一個伴隨方法,它會檢查值是否被緩存,如果沒有緩存。 考慮這個例子:

public abstract class Base { 
    private final String name; 
    private BigInteger cachedValue; 

    public Base(String name) { 
    this.name = name; 
    } 

    public BigInteger calculate() { 
    final BigInteger one = BigInteger.ONE; 
    //do the calculation involving `value` call 
    return value().multiply(one); 
    } 

    protected abstract BigInteger doComplexCalculation(); 

    protected BigInteger value() { 
    if (cachedValue == null) { 
     this.cachedValue = doComplexCalculation(); 
    } 
    return this.cachedValue; 
    } 
} 

這種情況下的子類的實例:

public class SubClass extends Base { 
    private int number; 

    public SubClass(String name, int number) { 
    super(name); 
    this.number = number; 
    } 

    @Override 
    protected BigInteger doComplexCalculation() { 
    //do calculations and return a result which will be cached by the base class 
    return BigInteger.valueOf(number); 
    } 
    //The cached value can then be accessed by other methods 
    //through the use of protected `value` method call. 
}