2011-12-13 73 views
1

有沒有人知道在調用超類構造函數之前,Java中是否有辦法在子類中設置實例變量的值。我有一個簡要的示意圖,下面是我要完成的工作 - 我需要根據子類的類型設置不同的超類定義的實例變量,但我仍然希望能夠共享通用的非構造函數代碼子類的不同實例。Java將子類實例數據傳遞給超類構造函數

有沒有乾淨的方式做到這一點,也許某種編碼,我很想念模式之類的東西?提前感謝任何想法。

public abstract class ConstraintSatisfactionProblem { 

    final Set<Variable> variables; 
    final Set<Constraint> constraints; 

    public Foo() { 
     this.variables = setupVariables(); 
     this.constraints = setupConstraints(); 
    } 

    public abstract Set<Variable> setupVariables(); 

    public abstract Set<Constraint> setupConstraints(); 

    public Map<Variable, Constraint> solve() { ... } 
} 

public class WordSquare extends ConstraintSatisfactionProblem { 

    final int size; 
    final static Set<Character> domain = ...; 

    public WordSquare() { 
     super();   // can I simulate calling super() after setting this.value = 4? 
     this.value = 4; 
    } 

    public Set<Variable> setupVariables() { 
     this.variables = new HashSet<Variable>(); 
     for(int row = 0; row < size; ++row) { 
      for(int col = 0; col < size; ++col) { 
       variables.add(new Variable<Pair, Character>(new Pair(row, col), domain); 
      } 
     } 
     return this.variables; 
    } 

    public Set<Constraint> setupConstraints() { 
     // setup code specific to this problem 
    } 
} 

public class Cryptarithmetic extends ConstraintSatisfactionProblem { 

    final String problem; 

    public Cryptarithmetic(String problem) { 
     super(); 
     this.problem = problem; 
    } 

    public Set<Variable> setupVariables() { 
     this.variables = new HashSet<Variable>(); 
     for(char c : problem.toCharArray()) { 
      variables.add(new Variable<Character, Integer>(c, getDomain()); 
      } 
     } 
     return this.variables; 
    } 

    public Set<Constraint> setupConstraints() { 
     // setup code specific to this problem 
    } 
} 
+1

是編碼模式被稱爲'不要做it` - 您違反了最基本的安全保障爲OOP這裏的一個:不要叫從構造一個非最終方法。是的,有些極其罕見的情況下,有些人告訴我說這是有道理的(喬恩在野田時間iirc中這樣做),但我沒有遇到過檢查對象層次結構並不是正確的做法。一種情況。 – Voo 2011-12-13 17:35:50

+0

也許探索抽象工廠或生成器來構造有效狀態的對象,而不是讓基礎在構造函數中調用虛擬方法。我相信這些模式中已經存在一些問題。 – 2011-12-13 17:39:15

+0

如果我將`WordSquare.setupVariables`(和類似方法)的簽名更改爲`public final Set setupVariables()`,那麼它會好嗎? – jay 2011-12-13 18:11:57

回答

1

首先,請不要。其次,真的是一個非常糟糕的主意。別。想想你想在更廣泛的背景下做什麼。

如果你絕對必須做的,你可以在一個ThreadLocal藏匿它。您可以通過評估的結果是被傳遞到爲什麼你需要一個第二一個super()this()(也可能是唯一的原因,私人的構造函數,可能需要一個Void(大寫「V」)參數表達式調用(非實例)方法)。這是非常邪惡的,我甚至不會寫代碼。

在您編輯的示例代碼中,只需將這些集合傳遞給受保護的構造函數即可。如果你有許多參數可能有些參數是特殊的,那麼你可能想把所有的參數包裝到一個參數對象中。

還有一個真正哈克的方式,只要你有-target 1.4或更高版本(你應該做的!)。使子類成爲內部類(可能是匿名的)。在調用超級構造函數之前,可以使用對這個和其他捕獲變量的引用。

public class Outer { 
    // What a hack! 
    private static abstract class Base { 
     Base() { 
      hello(); // Calling a virtual method in a constructor - poor form. 
     } 
     abstract void hello(); 
    } 
    public static void main(String[] args) { 
     // Do not do this. 
     final String hi = "Hi!"; 
     new Base() { 
      void hello() { 
       // Really, don't do it. 
       System.err.println(hi); 
      } 
     }; 
    } 
} 
0

將您想運行的通用代碼放在受保護的方法中而不是構造函數中。當你需要時調用該方法。

0

在Java中,如果你想調用基類的構造函數,你必須做你的子類的構造函數的第一行。所以答案是否定的,在調用超類的構造函數之前不能設置this.value

但你的子類的setup()方法已經被稱爲超級的構造。你爲什麼不在那裏設定你的價值?

更新: 對不起,我沒有注意你的'setup()'方法返回一個值。你可以做的是在你的超類中創建一個抽象的init()方法,然後在調用setup()方法之前在你的超級構造函數中調用它。這樣子類都將被迫實施init(),並且你會知道這是初始化任何子類的成員,他們在你的超一流的使用之前的地方。

話雖這麼說,這種做法並不強迫你的安全。當你從你的子構造函數調用超級構造函數時,子類實例剛剛開始創建。在安全地創建對象之前,仍然需要在子構造器中運行代碼的其餘部分。

而在這種情況下,超級構造函數會在剛剛創建過程的子類中調用init()方法。這意味着如果你採取的做法,你必須格外小心你在init()課堂上做了什麼。

0

您不應該在構造函數中調用任何「外來」方法(即該類的可重寫方法,或任何其他類的任何方法)。只要對象沒有完全初始化,你可能會有像你看到的那樣的副作用。

在你的情況下,在子類的構造函數中,甚至在「value」設置爲4之前調用super()。這意味着調用超類構造函數,然後調用「setup」方法,而「value 「仍然爲0.

只有超類構造函數返回時,」值「纔會設置爲4,並且這太晚了。

我會推薦的是將「o1」變量設置爲protected,以便子類可以自己設置它的值。

0

像其他人一樣,不要這樣做。如果您想在這些類之間共享一些代碼,請嘗試使用包含/封裝而不是繼承。

public class Foo { 

    private final Object o1; 

    public Foo(Object o) { 
     o1 = o; 
    } 

    public void complexMethodCommonToAllSubclassesOfFoo() { ... } 
    } 

public class Bar { 

    private final int value; 
    private final Foo foo; 

    public Bar() { 
     super(); 
     this.value = 4; 
     this.foo = new Foo(new Object()); // or whatever 
    } 

    // If you need to expose complexMethodCommonToAllSubclassesOfFoo to clients of this class, just add the method and delegate to foo like this 
    public void complexMethodCommonToAllSubclassesOfFoo() { 
     foo.complexMethodCommonToAllSubclassesOfFoo(); 
    } 
} 
0

我需要建立在不同取決於子類型的超類定義的實例變量,但我還是希望能夠分享子類的不同實例中常見的非構造函數代碼。

在這種情況下,在超類中創建受保護的構造函數,並在構造子類時將所有自定義值傳遞給它。

相關問題