55

子クラスにスーパークラスの非抽象メソッドをオーバーライドさせる方法はありますか?

親クラスのインスタンスを作成できる必要がありますが、クラスがこのクラスを拡張する場合、いくつかのメソッドの独自の定義を提供する必要があります。

4

13 に答える 13

37

私の知る限り、これを行うための直接的なコンパイラ強制の方法はありません。

親クラスをインスタンス化できないようにすることで回避できますが、代わりに、デフォルトの実装を持つ (可能なプライベート) サブクラスのインスタンスを作成するファクトリ メソッドを提供します。

public abstract class Base {
  public static Base create() {
    return new DefaultBase();
  }

  public abstract void frobnicate();

  static class DefaultBase extends Base {
    public void frobnicate() {
      // default frobnication implementation
    }
  }
}

今は書くことはできませんが、デフォルトの実装を取得するnew Base()ことはできます。Base.create()

于 2011-10-20T07:25:16.957 に答える
24

他の人が指摘したように、これを直接行うことはできません。

しかし、これを行う 1 つの方法は、次のようにStrategy パターンを使用することです。

public class Base {
    private final Strategy impl;

    // Public factory method uses DefaultStrategy
    // You could also use a public constructor here, but then subclasses would
    // be able to use that public constructor instead of the protected one
    public static Base newInstance() {
        return new Base(new DefaultStrategy());
    }

    // Subclasses must provide a Strategy implementation
    protected Base(Strategy impl) {
        this.impl = impl;
    }

    // Method is final: subclasses can "override" by providing a different
    // implementation of the Strategy interface
    public final void foo() {
        impl.foo();
    }

    // A subclass must provide an object that implements this interface
    public interface Strategy {
        void foo();
    }

    // This implementation is private, so subclasses cannot access it
    // It could also be made protected if you prefer
    private static DefaultStrategy implements Strategy {
        @Override
        public void foo() {
            // Default foo() implementation goes here
        }
    }
}
于 2011-10-20T20:42:02.240 に答える
6

このメソッドとのインターフェースを作成することを検討してください。クラスの子孫はそれを実装する必要があります。

于 2011-10-20T07:26:33.417 に答える
5

最も簡単な方法は、基本クラスから継承する抽象クラスを作成することだと思います。


public class Base {
    public void foo() {
        // original method
    }
}

abstract class BaseToInheritFrom extends Base {
    @Override
    public abstract void foo();
}

class RealBaseImpl extends BaseToInheritFrom {
    @Override
    public void foo() {
        // real impl
    }
}
于 2012-02-04T16:20:55.850 に答える
3

これはどうですか: メソッドのデフォルトの実装内で、リフレクションを使用してオブジェクトの正確なクラスを取得します。クラスが基本クラスと正確に一致しない場合は、RuntimeException または同等のものをスローします。

public class Parent {

    public void defaultImpl(){
        if(this.getClass() != Parent.class){
            throw new RuntimeException();
        }
    }

}
于 2011-10-20T07:31:54.573 に答える
3

できない理由がある!

派生クラスは、メソッドをオーバーライドするときに基本クラスの実装を呼び出すだけで済みます。

では、クラスに強制的にメソッドをオーバーライドさせる意味は何でしょう? なんのメリットもないと思います。

于 2011-10-20T17:50:27.787 に答える
3

いいえ、それが抽象メソッドの要点です。あなたのユースケースは何ですか?おそらく、根本的なニーズに基づいてそれについて考えることができます。

于 2011-10-20T07:25:05.147 に答える
2

答えはノーでしょう。テンプレートのデザインパターンを使用して再設計できます。それはあなたを助けるかもしれません。

または、子クラスにインターフェースを実装させることもできます。インターフェイスは、スーパークラスによって実装される場合と実装されない場合があります。

于 2011-10-20T07:27:58.967 に答える
1

基本クラスに例外をスローするメソッドをいつでも含めることができます。

技術的には、基本クラスでメソッドが定義されていますが、メソッドをオーバーライドしないと使用できません。このような場合、明示的なthrowsステートメントを必要としないため、ランタイム例外を使用することをお勧めします。例を次に示します

public class Parent {

  public void doStuff() {
    throw new RuntimeException("doStuff() must be overridden");
  }

}

public class Child extends Parent {

  @Override
  public void doStuff() {
    ... all is well here ...
  }

}

Base欠点は、これがオブジェクトの作成を妨げないことです。ただし、「オーバーライドする必要がある」メソッドの1つを使用しようとすると、すぐにクラスをオーバーライドする必要があることがわかります。

このソリューションはリクエストの説明を十分に満たしていますが、アプリケーションはおそらくこのようなソリューションを必要としないことでメリットがあります。abstractキーワードが提供するコンパイラチェックでランタイムクラッシュを回避する方がはるかに優れています。

于 2011-10-20T07:39:09.713 に答える
1

私は他の答えを反映して、派生クラスに非抽象メソッドをオーバーライドさせるコンパイラ強制の方法はないと言います。メソッドを抽象化することの要点は、このシグネチャを持つメソッドが存在する必要があることを定義することですが、基本レベルでは指定できないため、派生レベルで指定する必要があります。ベースレベルでメソッドの機能する自明ではない実装 (空ではなく、例外をスローしたり、メッセージを表示したりするだけではない) がある場合、これは呼び出しのために厳密には必要ありません。派生クラスのコンシューマーからのメソッドが成功します。したがって、コンパイラは、基本レベルまたは派生レベルのいずれかで正常に実行できるメソッドを強制的にオーバーライドする必要はありません。

派生クラスで作業中の実装をオーバーライドする必要がある状況では、基本実装が派生クラスのコンシューマーが望むことを実行しないことは明らかです。基本クラスに十分な実装がないか、実装が間違っています。そのような場合、あなたのクラスから派生したプログラマーが自分が何をしているかを知っていることを信頼する必要があります。したがって、新しいオブジェクトを使用するコンテキストでは正しい答えが得られないため、メソッドをオーバーライドする必要があることを知っている必要があります。

あなたにできることを一つ思いつきます。封印された(Javaheadsの最終)「デフォルト」実装を備えた抽象ベースが必要です。そうすれば、「基本」クラスであるかのようにすぐに使用できるメソッドの基本的な実装がありますが、新しいシナリオ用に別のクラスを定義するには、抽象クラスに戻る必要があります。したがって、メソッドを再実装する必要があります。このメソッドは、クラスの唯一の抽象化である可能性があるため、他のメソッドの基本的な実装を引き続き利用できます。

public abstract class BaseClass
{
   public abstract void MethodYouMustAlwaysOverride();

   public virtual void MethodWithBasicImplementation() { ... }
}

public final class DefaultClass:BaseClass
{
   public override void MethodYouMustAlwaysOverride() { ... }

   //the base implementation of MethodWithBasicImplementation 
   //doesn't have to be overridden
}

...

public class DerivedClass:BaseClass
{
   //Because DefaultClass is final, we must go back to BaseClass,
   //which means we must reimplement the abstract method
   public override void MethodYouMustAlwaysOverride() { ... }

   //again, we can still use MethodWithBasicImplementation, 
   //or we can extend/override it
   public override void MethodWithBasicImplementation() { ... }
}

ただし、これには 2 つの欠点があります。まず、継承によって DefaultClass の実装にアクセスできないため、DefaultClass の実装を拡張することはできません。つまり、DefaultClass が行うことを行うには、DRY に違反して、DefaultClass からコードを書き直す必要があります。第 2 に、DerivedClass からの継承を許可する場合、オーバーライドを強制できないため、これは 1 つのレベルの継承に対してのみ機能します。

于 2011-10-20T14:31:10.193 に答える
1

たぶんこれが役立ちます:

class SuperClass {

    void doStuff(){

        if(!this.getClass().equals(SuperClass.class)){

            throw new RuntimeException("Child class must implement doStuff Method");
        }else{
            //ok
            //default implementation
        }
    }
}

class Child extends SuperClass{

    @Override
    void doStuff() {
        //ok
    }
}

class Child2 extends SuperClass{

}


 new SuperClass().doStuff(); //ok
 new Child().doStuff();         //ok
 new Child2().doStuff();        //error
于 2011-10-20T16:02:41.947 に答える
0

よし、これで勉強しよう。私は Java スタイルのガイドラインに従い、Java 構文を使用します。そのため、多重継承と C++ テンプレートは使用できないと想定されます。

親クラスのメソッドを抽象化することは必須ではありません。OOP ではポリモーフィズムの概念を使用します。同じ方法を 2 つ以上の異なる方法で使用できます。これは、メソッドのオーバーライドと呼ばれます。

例を挙げましょう。

    public class Animal{
       public void makeSound(){
          System.out.println("Animal doesn't know how to make sound");
       }

    }

    public class PussyCat extends Animal{
        public void makeSound(){

           System.out.println("meowwww !!!");
        }

        public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
    }

これにより、「meowww !!!」が出力されます 画面上。

ただし、これはメソッド makeSound を子クラスでオーバーライドする必要があることを意味するものではありません。

子クラスでメソッドを強制的にオーバーライドする必要がある場合は、クラスによってインターフェイスを実装することをお勧めします。

      public Interface audible{
         public void makeSound();

      }

      public class pussyCat implements audible{
          // now you must implement the body of makeSound method here
          public void makeSound(){
            System.out.println("meowwww !!!"); 
          }

          public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
      }

これにより、「meowwww !!!」も出力されます。画面上

于 2011-10-20T09:20:41.333 に答える
0

推奨されない場合がありますが、メソッドの実装で例外 (MethodeMustBeOverRiddenExp のようなもの) をスローできます。もちろん、これは実行時の強制ですが、nuthing よりも優れている場合があります。

于 2018-07-31T19:01:11.313 に答える