web-dev-qa-db-ja.com

Javaの抽象クラスとインターフェイス

質問がありましたが、ここで回答を確認したかったのです。

Q:インターフェイスを実装するよりも抽象クラスを拡張する方が適切なシナリオはどれですか?

A:テンプレートメソッドデザインパターンを使用している場合。

私は正しいですか?

質問を明確に述べることができなかった場合、申し訳ありません。
抽象クラスとインターフェースの基本的な違いを知っています。

1)特定の操作(メソッドを実装)のすべてのサブクラスに同じ機能を実装し、他の操作(メソッドシグネチャのみ)に異なる機能を実装する必要があるような要件の場合は、抽象クラスを使用します

2)インターフェースの実装に準拠できるように、署名を同じ(および実装が異なる)にする必要がある場合は、インターフェースを使用します

3)最大1つの抽象クラスを拡張できますが、複数のインターフェイスを実装できます

質問を繰り返します:抽象クラスを使用する必要のある上記のシナリオ以外に他のシナリオはありますか?

インターフェイスと抽象クラス

これら2つのどちらを選択するかは、実際に何をしたいかによって異なりますが、幸運なことに、Erich Gammaは少し助けてくれます。

常にトレードオフがありますが、インターフェイスは基本クラスに関して自由度を与え、抽象クラスは新しいメソッドを後で追加する自由を与えます。 –エーリッヒガンマ

他の多くのことを変更せずにインターフェイスを変更することはできませんしたがって、これを回避する唯一の方法は、まったく新しいインターフェイスを作成することです良いこと。

Abstract classesは、主に密接に関連するオブジェクトに使用する必要があります。 Interfacesは、無関係なクラスに共通の機能を提供するのに優れています。

77
Java Geek

インターフェイスを使用する場合

インターフェイスを使用すると、誰かが最初からインターフェイスを実装したり、元のまたは主な目的がインターフェイスとはまったく異なる他のコードでインターフェイスを実装したりできます。彼らにとって、インターフェースは偶発的なものであり、パッケージを使用できるようにするためにコードに追加する必要があるものです。欠点は、インターフェイスのすべてのメソッドがパブリックでなければならないことです。すべてを公開したくないかもしれません。

抽象クラ​​スを使用する場合

対照的に、抽象クラスはより多くの構造を提供します。通常、いくつかのデフォルトの実装を定義し、完全な実装に役立つツールを提供します。キャッチは、それを使用するコードは、クラスをベースとして使用する必要があるということです。あなたのパッケージを使用したい他のプログラマーが既に独自にクラス階層を開発している場合、それは非常に不便かもしれません。 Javaでは、クラスは1つの基本クラスからのみ継承できます。

両方を使用する場合

インターフェイスと抽象クラスの両方の長所を提供できます。実装者は、選択した抽象クラスを無視できます。これを行うことの唯一の欠点は、インターフェース名を介してメソッドを呼び出すことです。抽象クラス名を介してメソッドを呼び出すよりもわずかに遅くなります。

76
DivineDesert

質問を繰り返します:上記以外にも、特に抽象クラスを使用する必要のあるシナリオがあります(テンプレートメソッドの設計パターンは、これだけに概念的に基づいています)

はい、JAXBを使用する場合。インターフェースが好きではありません。抽象クラスを使用するか、ジェネリックでこの制限を回避する必要があります。

個人的なブログから post

インターフェース:

  1. クラスは複数のインターフェースを実装できます
  2. インターフェイスはコードをまったく提供できません
  3. インターフェイスは、パブリック静的最終定数のみを定義できます
  4. インターフェイスはインスタンス変数を定義できません
  5. 新しいメソッドを追加すると、クラスの実装に波及効果があります(設計のメンテナンス)
  6. JAXBはインターフェイスを処理できません
  7. インターフェイスは抽象クラスを拡張または実装できません
  8. すべてのインターフェイスメソッドはパブリックです

一般に、インターフェースを使用して契約を定義する必要があります(達成方法ではなく、達成方法)

抽象クラス:

  1. クラスは最大で1つの抽象クラスを拡張できます
  2. 抽象クラスにはコードを含めることができます
  3. 抽象クラスは、静的定数とインスタンス定数の両方を定義できます(最終)
  4. 抽象クラスはインスタンス変数を定義できます
  5. 既存の抽象クラスコードの変更は、クラスの拡張に影響を及ぼします(実装のメンテナンス)
  6. 抽象クラスに新しいメソッドを追加しても、クラスの拡張に波及効果はありません
  7. 抽象クラスはインターフェースを実装できます
  8. 抽象クラスはプライベートおよび保護されたメソッドを実装できます

(部分)実装には抽象クラスを使用する必要があります。 APIコントラクトの実装方法を制限する手段になる可能性があります。

27

インターフェイスは、すべてのクラスが同じ構造を持っているが、機能がまったく異なるシナリオがある場合に使用されます。

抽象クラスは、すべてのクラスが同じ構造であるが、同じ機能と異なる機能を持つシナリオがある場合に使用されます。

記事をご覧ください: http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

14
SMK

抽象クラスとインターフェースのどちらを使用すべきですか?

これらのステートメントのいずれかがシナリオに該当する場合は、抽象クラスの使用を検討してください:

いくつかの密接に関連するクラス間でコードを共有したい。

抽象クラスを拡張するクラスには、多くの一般的なメソッドまたはフィールドがあるか、またはpublic(protectedやprivateなど)以外のアクセス修飾子が必要であることが予想されます。

非静的または非最終フィールドを宣言します。これにより、それらが属するオブジェクトの状態にアクセスして変更できるメソッドを定義できます。

これらのステートメントのいずれかが状況に該当する場合は、インターフェースの使用を検討してください:

無関係なクラスがインターフェイスを実装することを期待します。たとえば、インターフェイスComparableおよびCloneableは、多くの無関係なクラスによって実装されます。

特定のデータ型の動作を指定したいが、その動作を誰が実装するかは気にしません。

型の多重継承を利用したい場合。

http://docs.Oracle.com/javase/tutorial/Java/IandI/abstract.html

4
Santh

過去3年間で、Java 8リリースとのインターフェイスに新しい機能が追加されたことにより、状況は大きく変わりました。

Oracleのドキュメントから ページ インターフェース:

インターフェイスは、クラスに似た参照型であり、定数、メソッドシグネチャ、デフォルトメソッド、静的メソッド、およびネストされた型のみを含むことができます。メソッド本体は、デフォルトメソッドと静的メソッドにのみ存在します。

質問で引用したように、抽象クラスはテンプレートメソッドパターンに最適です。スケルトンを作成する必要があります。ここではインターフェイスを使用できません。

インターフェイスよりも抽象クラスを好むもう1つの考慮事項:

基本クラスに実装はなく、サブクラスのみが独自の実装を定義する必要があります。サブクラスと状態を共有するため、インターフェイスではなく抽象クラスが必要です。

抽象クラスは、関連するクラス間の "is a"関係を確立し、インターフェイスは、関連しないクラス間の "has a"機能を提供します


Java-8リリース前のJavaを含むほとんどのプログラミング言語で有効な質問の2番目の部分について

常にトレードオフがありますが、インターフェイスは基本クラスに関して自由度を与え、抽象クラスは後で新しいメソッドを追加する自由度を与えます。 –エーリッヒガンマ

コードの他の多くのものを変更することなく、インターフェイスを変更することはできません

上記の2つの考慮事項を備えたインターフェースよりも抽象クラスを優先する場合、 デフォルトメソッド がインターフェースに強力な機能を追加したため、ここで再考する必要があります。

デフォルトのメソッドを使用すると、ライブラリのインターフェイスに新しい機能を追加し、それらのインターフェイスの古いバージョン用に記述されたコードとのバイナリ互換性を確保できます。

インターフェースと抽象クラスのいずれかを選択するには、Oracleのドキュメント page を引用してください:

抽象クラスはインターフェイスに似ています。それらをインスタンス化することはできません。また、実装の有無にかかわらず宣言されたメソッドが混在する場合があります。ただし、抽象クラスを使用すると、静的で最終ではないフィールドを宣言し、パブリック、プロテクト、プライベートの具象メソッドを定義できます。

インターフェイスを使用すると、すべてのフィールドは自動的にパブリック、静的、および最終になり、宣言または定義する(デフォルトメソッドとして)すべてのメソッドはパブリックになります。さらに、抽象クラスであるかどうかにかかわらず、1つのクラスのみを拡張できますが、任意の数のインターフェイスを実装できます。

詳細については、これらの関連する質問を参照してください。

インターフェイスと抽象クラス(一般的なオブジェクト指向)

インターフェイスクラスと抽象クラスの違いをどのように説明したらよいですか?

要約すると:天びんは現在インターフェースに向かって傾いています

上記以外に、抽象クラスを使用する必要がある具体的なシナリオはありますか(テンプレートメソッドのデザインパターンは、これだけに概念的に基づいていることがわかります)。

いくつかのデザインパターンは、テンプレートメソッドパターンとは別に(インターフェイス上で)抽象クラスを使用します。

作成パターン:

Abstract_factory_pattern

構造パターン:

Decorator_pattern

行動パターン:

Mediator_pattern

4
Ravindra babu

あなたは間違っています。多くのシナリオがあります。単一の8ワードルールに減らすことはできません。

3
user207421

私の意見では、基本的な違いはan interface can't contain non abstract methods while an abstract class canです。したがって、サブクラスが共通の振る舞いを共有する場合、この動作はスーパークラスで実装され、サブクラスで継承されます。

また、「Javaのソフトウェアアーキテクチャ設計ppatterns」の本から次のことを引用しました。

"Javaプログラミング言語では、多重継承はサポートされていません。つまり、クラスは1つの単一クラスからのみ継承できます。したがって、継承は、絶対に必要な場合にのみ使用してください。共通の動作は、異なる実装クラスによって実装されるJavaインターフェースの形式で宣言する必要がありますが、インターフェースにはメソッド実装を提供できないという制限があります。これらのメソッドの一部が機能の不変部分を表し、すべてのインプリメンタークラスでまったく同じ実装を持っている場合でも、インターフェイスで宣言されたすべてのメソッドこれは、冗長なコードにつながります。そのような場合、冗長なメソッド実装を必要とせずに使用できます。」

3
user2794921

最も簡単な答えは、uou seekの一部の機能が既に実装されている場合、extend抽象クラスです。

インターフェイスを実装する場合、すべてのメソッドを実装する必要があります。ただし、抽象クラスの場合、実装する必要があるメソッドの数は少なくなります。

テンプレートデザインパターン では、動作が定義されている必要があります。この動作は、抽象である他のメソッドに依存します。サブクラスを作成し、それらのメソッドを定義することにより、実際にメインの動作を定義します。インターフェースは何も定義せず、宣言するだけなので、基礎となる動作をインターフェースに含めることはできません。そのため、テンプレートデザインパターンには常に抽象クラスが付属しています。振る舞いのフローをそのままにしたい場合は、抽象クラスを拡張する必要がありますが、メインの振る舞いをオーバーライドしないでください。

3
Shiplu Mokaddim

抽象クラスは、2つの重要な側面でインターフェイスとは異なります

  • 選択したメソッドのデフォルトの実装を提供します(回答でカバーされます)
  • 抽象クラスは状態(インスタンス変数)を持つことができます-これは、インターフェースの代わりにそれらを使用したいもう1つの状況です
2

ここにはたくさんの素晴らしい答えがありますが、私はしばしば両方のインターフェースと抽象クラスを使用することが最良のルートであると感じます。 この不自然な例を検討してください:

あなたは投資銀行のソフトウェア開発者であり、市場に注文を出すシステムを構築する必要があります。インターフェースは、取引システムが何をするかの最も一般的なアイデアをキャプチャします。

1) Trading system places orders
2) Trading system receives acknowledgements

インターフェイスでキャプチャできますITradeSystem

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

これで、セールスデスクや他のビジネスラインで作業するエンジニアは、システムとinterfaceを開始して、既存のアプリに発注機能を追加できます。そして、まだ構築を開始していません!これがインターフェースの力です。

そこで、stockトレーダー向けのシステムを構築します。あなたのシステムには安価な在庫を見つける機能があり、試してみたいと非常に熱心です。 findGoodDeals()と呼ばれるメソッドでこの動作をキャプチャしますが、市場への接続に関与する厄介なものがたくさんあることも認識しています。たとえば、SocketChannelを開く必要があります。

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

具体的な実装には、connectToMarket()のようなこれらの厄介なメソッドがたくさんありますが、findGoodDeals()はトレーダーが実際に気にするすべてです。

ここで、抽象クラスの出番です。上司は、通貨トレーダーもシステムを使用したいことを通知します。通貨市場を見ると、配管は株式市場とほぼ同じであることがわかります。実際、connectToMarket()は逐語的に再利用して外国為替市場に接続できます。ただし、findGoodDeals()は通貨の分野では非常に異なる概念です。したがって、コードベースを海を渡る外国為替ウィズキッドに渡す前に、最初にabstractクラスにリファクタリングし、findGoodDeals()を実装したままにします。

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

株式取引システムは、既に定義したようにfindGoodDeals()を実装します。

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

しかし今では、FXウィズキッドは通貨にfindGoodDeals()の実装を提供するだけでシステムを構築できます。彼女はソケット接続やインターフェースメソッドを再実装する必要はありません!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

インターフェースへのプログラミングは強力ですが、同様のアプリケーションは多くの場合、ほぼ同じ方法でメソッドを再実装します。抽象クラスを使用すると、インターフェースの能力を維持しながら、繰り返しを回避できます。

注:findGreatDeals()がインターフェイスの一部ではない理由を疑問に思うかもしれません。インターフェースは、取引システムの最も一般的なコンポーネントを定義することを忘れないでください。別のエンジニアが完全に異なる取引システムを開発する場合があります。そこでは、彼らは良い取引を見つけることを気にしません。このインターフェースは、セールスデスクがシステムにもインターフェースできることを保証するため、「お得」などのアプリケーションコンセプトにインターフェースを絡ませないことが望ましいです。

2
Adam Hughes

これは良い質問です。これらの2つは類似していませんが、書き換えのような同じ理由で使用できます。作成するときは、インターフェイスを使用するのが最適です。クラスに分類すると、デバッグに適しています。

1
sharonda walker

これが私の理解です。これが役立つことを願っています

抽象クラ​​ス:

  1. 継承されたメンバー変数を持つことができます(インターフェイスでは実行できません)
  2. コンストラクターを持つことができます(インターフェースではできません)
  3. そのメソッドは任意の可視性を持つことができます(つまり:private、protectedなど-すべてのインターフェイスメソッドはパブリックです)
  4. 定義済みのメソッド(実装を持つメソッド)を持つことができます

インターフェース:

  1. 変数を持つことができますが、それらはすべてパブリックな静的最終変数です
    • 静的スコープで決して変化しない定数値
    • 非静的変数にはインスタンスが必要であり、インターフェースをインスタンス化することはできません
  2. すべてのメソッドは抽象です(抽象メソッドにコードはありません)
    • すべてのコードは、特定のインターフェイスを実装するクラスで実際に作成する必要があります
0
zozep

Abstract classes should be extended when you want to some common behavior to get extended。抽象スーパークラスには共通の動作があり、サブクラスが実装する抽象メソッド/特定の動作を定義します。

Interfaces allows you to change the implementation anytime allowing the interface to be intact

0
Ramesh PVK

アブストラクトとインターフェースの使用:

1つは「Is-A-Relationship」であり、もう1つは「Has-A-Relationship」です。

デフォルトのプロパティは抽象的に設定されており、インターフェイスを介して追加のプロパティを表現できます。

例:->人間には、食べる、寝るなどのデフォルトのプロパティがありますが、水泳、遊びなど他のカリキュラムアクティビティがある場合は、Interfaceで表現できます。

0
user7439667

抽象クラスとインターフェイスの違い

抽象クラ​​ス

  • 抽象クラスには、抽象メソッドと非抽象メソッドを含めることができます
  • 抽象クラスには非最終変数が含まれる場合があります
  • 抽象クラスには、final、final、final、static、およびnon-static変数を含めることができます
  • 抽象クラスはインターフェイスの実装を提供できます
  • 抽象クラスは、キーワード「extends」を使用して拡張できます
  • 抽象クラスは、別のJavaクラスを拡張し、複数のJavaインターフェイスを実装できます
  • Java抽象クラスには、private、protectedなどのクラスメンバーを含めることができます

インターフェース

  • インターフェースは抽象メソッドのみを持つことができます
  • Javaインターフェースで宣言された変数は、デフォルトではfinalです
  • インターフェースには静的変数と最終変数のみがあります
  • インターフェイスは抽象クラスの実装を提供できません
  • Javaインターフェースは、キーワード「implements」を使用して実装できます
  • インターフェイスは、別のJavaインターフェイスのみを拡張できます
  • Javaインターフェースのメンバーはデフォルトでパブリックです
0