2016-12-01 8 views
0

私はJavaで抽象クラスを持っています。私は彼のサブクラスの特定のメソッド(存在する場合)をリフレクションで呼び出す必要があります。だから、未知のサブクラスの呼び出しメソッド

public abstract class Parent { 
    public void doIt(String functionName) { 
     if (the caller class have method called as functionName parameter) { 
      call it 
     } 
    } 
} 

public class Child extends Parent{ 
    public void spacialMethod() { 
     System.out.println("Child special method called"); 
    } 
} 

public class Child2 extends Parent{ 
    // Empty 
} 

私は、そのコードを実行する場合:現在のサブクラスが「specialMethod」と呼ばれる方法を持っている場合

Child child = new Child(); 
child.doIt("spacialMethod"); // Will print the text 
Child2 child2 = new Child2(); 
child2.doIt("spacialMethod"); // Nothing will happened 

は、どのように私は親クラスで確認できますか?

+3

なぜですか?なぜ、抽象クラスで「何もしない」バージョンを定義して呼び出すだけで、サブクラスがそれをオーバーライドすれば、そのバージョンが呼び出されるのはなぜですか? –

答えて

5

可能あなたは尋ねたことをやり遂げることができます(答えの終わりを参照してください)。

実行時に名前を特定する必要がない場合は、何もしないでメソッドをParentに定義してから呼び出してください。サブクラスがそれをオーバーライドする場合は、素晴らしいです。

// Not recommended if you can avoid it 
public void doIt() { 
    try { 
     this.getClass().getMethod("specialMethod").invoke(this); 
    } 
    catch (/*...appropriate exception handling...*/) { 
    } 
} 
+0

親に「デフォルト」の 'spacialMethod'を作成したくないのですが、実際には何がメソッド名であるのかわからないので、実行時にしか見つけることができません...' this.getClass()。 getMethod( "specialMethod") 'は' Parent'クラスで宣言しなければ動作しますか? – nrofis

+1

@nrofisあなたは貧しいデザインを持っています。 –

+0

@nrofis:はい。これは、前のコードブロックの拡張ではなく、別の方法です。 'this.getClass()'はインスタンスのクラスを取得します。サブクラスではサブクラスです。 –

0

TJクラウダーあなたからの回答に加えて:あなたは本当に反射でそれをしたい場合は

public abstract class Parent { 
    public void doIt() { 
     this.specialMethod(); 
    } 
    public void spacialMethod() { 
     // Do nothing 
    } 
} 

public class Child extends Parent{ 
    @Override 
    public void spacialMethod() { 
     // Optionally call super.specialMethod() here 
     System.out.println("Child special method called"); 
    } 
} 

public class Child2 extends Parent{ 
    // Empty 
} 

しかし、それは難しいことではありません(例えば、あなたは、実行時に名前を定義する必要があります) getDeclaredMethodsを使用してすべてのメソッドを取得し、特別なを呼び出すことができます。

反射せずに単なる例
public void doIt() { 
     Method[] methods = getClass().getDeclaredMethods(); 
     for(Method method : methods){ 
      if(method.getName().contains("special"){ 
      method.invoke(this); 
      } 
     } 
    } 
+1

'getDeclaredMethods'は継承されたメソッドを返さないことを覚えておいてください。つまり、スーパークラスで宣言されたメソッドは返されません。 –

0

それぞれの子クラスのために特別に実装され、または実装されていない「アクセサ」のいくつかの種類を持っています。実装されると、子の望ましいメソッドに委譲されます。

以下の例とは異なり、アクセサの実装はクラス自体の外部にあることがあるので、子がアクセスする方法やその方法を知らなくてもよいことに注意してください。

public interface SpecialOpAccessor { 
    void doIt(); 
} 

public abstract class Parent { 
    protected SpecialOpAccessor accessor; 

    public void doIt() { 
     if (accessor != null) { 
     accessor.doIt(); 
     } 
    } 
} 

public class Child extends Parent{ 

    public Child() { 
     super(); 
     this.accessor = new SpecialOpAccessor() { 
     @Override 
     public void doIt() { 
      Child.this.spacialMethod(); 
     } 
     } 
    } 

    public void spacialMethod() { 
     System.out.println("Child special method called"); 
    } 
} 

public class Child2 extends Parent{ 
    public Child() { 
     super(); 
     this.accessor = null; 
    } 
} 
関連する問題