web-dev-qa-db-ja.com

Javaスーパークラスのパブリックメソッドの実装を強制するクラス

私は以下を持っています:

 public Class A {
 
 public void methodA(){
 .... 
} 
 
 public void methodB(){
 .... 
} 
 
} 

Class Aを制御できません。methodA()をオーバーライドする必要があるという制限付きでClass Aのサブクラスを作成したいと思います(super.methodA()呼び出しでClass Aの実装を実行する必要があります)。出来ますか?そうですか?

5
500865

ここで最初に理解することは、要件のこの部分:super.methodA()は、これがAを拡張するクラスのコードに適用されることを意味します JLS 15.12.4.4-2。superを使用したメソッド呼び出し

スーパークラスのオーバーライドされたインスタンスメソッドにアクセスするには、キーワードsuperを使用して直接のスーパークラスのメンバーにアクセスし、メソッド呼び出しを含むクラスのオーバーライド宣言をバイパスします...

たとえば、Aの特定のサブクラスを作成して、これらでsuper.methodA()が呼び出されるたびに、クラスAにあるコード(コントロール外)の代わりに、いくつかが実行されることが保証されるとしましょうAのサブクラスで定義された他のコード(私たちの制御下)。


上記を達成するために私たちが自由に使える「ツール」を見てみましょう。

  1. Asome、specificサブクラスを作成する必要があるため、従来の特殊化の方法が思い浮かびます-サブクラス化、つまり、Aのサブクラス(Bと呼びましょう)を検討して、methodAを再定義(オーバーライド)します私たちが望む方法。

  2. サブクラスにスーパークラスで実行したい場所で実行するコードを提供する必要がある場合は、抽象メソッドを定義することで満たすことができます。それをforcedImplementationInSubclass()と呼びましょう。


これで、必要なものがすべて揃いました。

  • Bを拡張するクラスAを定義し、BのすべてのサブクラスがAのサブクラスになるようにします。
  • Bでは、methodAをオーバーライドするため、クラスAでの実装をBのサブクラスで使用できなくなります。
  • Bのオーバーライドされたメソッドで、抽象メソッドforcedImplementationInSubclass()を呼び出します。これにより、Bのサブクラスが、最終的にmethodAで実行されるコードを定義する必要があります。

その結果、Bのサブクラスは、methodAクラスで提供されるA実装を呼び出すことができなくなり、代わりに、Bのサブクラスで定義されたコードを実行することが保証されます。

Bの拡張は、希望どおりに動作するAの特定のサブクラスを作成する方法です。コードは次のようになります。

public abstract class B extends A {
    // override, so that subclasses of B won't be able to get to super.methodA
    @Override public void methodA() {
        // invoke abstract method here (subclass would have to implement it)
        forcedImplementationInSubclass();
    }

    // define abstract method so that subclass would have to implement it
    protected abstract void forcedImplementationInSubclass();
}

// extending B is the way to get what we need
public class C extends B {
    // enforced implementation of the abstract method
    @Override protected void forcedImplementationInSubclass() {
        // that will be invoked when B.methodA() is called, and since B is-a A...
        System.out.print("Hello from implemented methodA");
    }

    public void testSuperMethodA() {
        // that will invoke B.methodA() which won't go to class A
        super.methodA();
    }

    public static void main(String[] args) {
        A a = new C();
        a.methodA(); // goes to B.methodA(), which in turn invokes C.forcedImplementationInSubclass()
        C c = new C();
        c.testSuperMethodA(); // won't go to class A
    }
}
6
gnat

メソッドに実装が与えられると、再び抽象化する方法はありません。したがって、いいえ、Aを変更しない限り、クラスを書く方法はありませんB extends Aそのため、Bのすべてのサブクラスは、少なくとも型システムを介さずに、別の実装を提供する必要があります。

最善の方法は、実行時に例外をスローするメソッドをBに記述することです。これにより、すべてのサブクラスがメソッドをオーバーライドして強制的に使用できるようになりますが、それを行わなくてもコンパイルされます。

4
Kilian Foth