web-dev-qa-db-ja.com

抽象的ではないがオーバーライドしなければならないメソッドを作成する方法はありますか?

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

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

54
user517491

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

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

_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()を実行してデフォルトの実装を取得することができます。

37
Joachim Sauer

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

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

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
        }
    }
}
24
Daniel Pryden

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

6
Ivan Nikitin

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


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
    }
}
5
s106mo

理由それは不可能です!

派生クラスは、メソッドをオーバーライドするときに、単純にcall基本クラスの実装である可能性があります。

では、クラスにメソッドをオーバーライドさせることのポイントは何ですか?何のメリットもないと思います。

3
Mehrdad

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

3
mjaggard

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

public class Parent {

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

}
3
curioustechizen

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

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

2
Ravi Bhatt

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

技術的には、基本クラスがメソッドを定義していますが、メソッドをオーバーライドしないと使用できません。このような場合、明示的な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キーワードが提供するコンパイラチェックでランタイムクラッシュを回避する方がはるかに優れています。

1
Edwin Buck

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

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

私はあなたができることを一つ考えることができます。封印された(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からコードを書き直す必要があります。次に、DerivedClassからの継承を許可している場合はオーバーライドを強制できないため、これは1レベルの継承に対してのみ機能します。

1
KeithS

多分これは役立ちます:

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
1
Rodrigo

わかりました、この方法でそれを学びましょう。 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 !!!」も出力します画面上

0
Tharindu Rusira

推奨されない場合もありますが、methode実装で例外(MethodeMustBeOverRiddenExpなど)をスローできます。もちろん、これはランタイム強制ですが、何もしないよりはましかもしれません。

0
Itay wazana