2011-07-20 9 views
6

基本的に、私がしたいのは、サブクラスが抽象スーパークラスメソッド(サブクラスで実装されている)を呼び出すようにすることです。私は新しいサブクラスを作成します。抽象実装のメソッドを呼び出すようにサブクラスを強制する方法

スーパークラスのコンストラクタに一度書きました。なぜなら、すべての実装でそれを強制したいからです。

public abstract class SupahClass { 
    public SupahClass() { 
     doStuff(); // It IS executed when the subclass constructor is called 
     init(); // NOT executed, even though it's implemented 
    } 

    private void doStuff() { ... }   

    protected abstract void init(); 
} 

public class SomeSubClass extends SupahClass { 

    // The problem lies HERE: this is executed AFTER init() ... so it gets NULL again 
    private TextBox myTextBox = null; 

    public SomeSubClass() { 
     super(); // invokes the super constructor, so init() should be called 
     // I could call init(); here EACH time i create a new subclass... but no :) 
    } 

    @Override 
    public void init() { 
     this.myTextBox = new TextBox(); // Executed BEFORE its declared as null above 
    } 
} 

もちろん、スーパークラスは本当に、その抽象的(そう未定義)メソッドので、それを呼び出すことはできませんが、それはインスタンス化することはできませんので、その抽象クラスは、そのサブクラスにタスクを委任する必要があり、なぜ彼らは抽象と呼ばれることはできませんが、今は実装されたメソッドですか?

EDIT は、サブクラスのプロパティmyTextBoxinit()実装あなたは私がやるべきだと思いますアプローチ

を参照してください?プロパティの宣言(duhhh)

= nullを削除するか、スーパークラスのinit()を削除し、明示的にサブクラスのコンストラクタで呼び出す(これは私が避けたかったので、100%の時間を書きます..)

+1

それは動作します。これは明らかにあなたの実際のコードではありません - 実際のコードはいくつかの重要な点でこれと異なる必要があります。実際のコードを投稿して見てみましょう。 –

+0

確かに!Jon Skeetの答えと私の更新された質問に私のコメントを参照してください:) – dominicbri7

答えて

2

あなたは、あなたに宣言を変更することで、この問題を解決することができますnullに

private TextBox myTextBox; 

割り当ては、有用な目的を果たしていません。スーパークラスがなければ、何もしません。なぜなら、フィールドはいずれにせよnullに初期化されるからです。スーパークラスがあるので、それは足の銃声として機能します。だから、それを取り除く。

+0

これは私がこれを修正するために瞬間したものですが、それはまったく役に立たないことを実感して、実際には悪い習慣です。 私は役に立つと思うことさえできません...私は、私がそれらを使用したどこでもこれらの課題を削除すると思います。しかしそれ以外に、(コンストラクタでこのようなメソッドを呼び出す)私の現在の実装についてどう思いますか? – dominicbri7

+0

誰もがあなたに言うように、危険な練習です。いくつかの非常に扱いにくいバグ(部分的に構築されたオブジェクト、安全でないオブジェクトの公開などに対して実行されるメソッド)への扉を開きます。しかし、バグを避けられないものにしているわけではありません。コンストラクタからサブクラスメソッドを呼び出す利点がない場合は、私はあなたにそれを行うことをお勧めしたいと思います。しかし、しばしば、それは簡単な選択肢ではなく、あなたが望む振る舞いを得るためのシンプルで明確な方法です。したがって、コールの価値がバグのリスクを上回るかどうかについての判断が必要です。 –

+0

これは、コンテキストに依存する判断の呼び出しです。つまり、クラスの周囲のインバリアントがどれほど複雑か、コードベースで作業するプログラマーがどれほど熟練しているか、クラスが広く拡張されるか、システムの小さな部分に限定されるか、私はあなたに一般的な答えを与えることができない特定の質問です。 Jon Skeetはもちろんです:) –

8

私はこれを再現できません。 init()が呼び出されます。例外は最初にスローされないものとします。短いが完全な例:

abstract class Superclass { 
    public Superclass() { 
     init(); 
    } 

    protected abstract void init(); 
} 

class Subclass extends Superclass { 
    public Subclass() { 
     super(); 
    } 

    @Override 
    public void init() { 
     System.out.println("Subclass.init called"); 
    } 
} 

public class Test {  
    public static void main(String[] args) throws Exception { 
     new Subclass(); 
    } 
} 

これは、期待どおりに "Subclass.init called"を表示します。私はあなたが私たちに示していないコードで何か他のものが間違っていると思う。

コンストラクタ内で仮想メソッドを呼び出すことは危険なビジネスです。サブクラスはまだ初期化されていません。たとえば、すべての変数はデフォルト値を持ちます。それは一般的に避けるべきパターンです。

+1

はこれについて忠告しようとしていましたが、Jon Skeetによって殴られています。 – Leon

+0

あなたは絶対に正しいです。サブクラスのプロパティは、初期化されるはずだったときはnullでした。 サブクラスが初期化されていないため、それが危険なビジネスだと言ったときは2倍です。それはまさに私の問題でした。詳細については最後に私の更新された質問を参照してください、私はあなたが私が使用すべきだと思うアプローチについてのあなたのフィードバックを本当にお待ちしています.. :) – dominicbri7

2

抽象クラスは、を抽象メソッドと呼びます。

0

コードが何をしているのかを理解するためにデバッガーを使用しましたか?

1.基本クラスのコンストラクタ 2.派生クラスのすべてのメンバーを初期化します。 3.派生クラスのコンストラクタ。

あなたのケースでは、ステップ1はメンバを初期化します(派生クラスの初期化で - 多態性呼び出しによって呼び出されます)が、ステップ2ではnullに設定されます。

関連する問題