Java抽象クラスとインタフェースを分析する

8813 ワード

この例では、Java抽象クラスとインタフェースについて説明します.皆さんの参考にしてください.具体的には以下の通りです.
OOPプログラミングにとって、抽象はその大きな特徴の一つである.Javaでは、抽象クラスとインタフェースの2つの形式でOOPの抽象を表すことができます.
この二つには似ているところもあれば、大きな違いもあります.
一、抽象類
抽象クラスを理解する前に、抽象メソッドを理解します.抽象的な方法は特殊な方法です.宣言だけで、具体的な実現はありません.抽象メソッドの宣言形式は次のとおりです.

abstract void fun();


抽象メソッドはabstractキーワードで修飾する必要があります.クラスに抽象メソッドが含まれている場合、このクラスを抽象クラスと呼びます.このクラスはクラスの前にabstractで修飾する必要があります.そうしないと、IDEでコンパイルするときにエラーが表示されます.抽象クラスには具体的な実装方法がないため、抽象クラスでオブジェクトを作成することはできません.
もう1つの問題は、abstractで修飾された抽象クラスが抽象メソッドを含まなくてもよいことに注意する必要があります.個人的には、抽象クラスに抽象的な方法が含まれていない場合、なぜ抽象クラスとして設計されるのかという問題だと思います.だから、この概念をしばらく覚えておきましょう.なぜか深く考える必要はありません.

[public] abstract class ClassName(){
abstract void fun();
}


ここから,抽象クラスはクラス継承のために存在し,抽象クラスでオブジェクトを作成することはできず,この抽象クラスでは何もできないことがわかる.親クラスの場合、そのメソッドが親クラスで実装されても意味がなく、サブクラスの実際のニーズに応じて異なる実装が必要である場合、このメソッドをabstractメソッドとして宣言することができます.このクラスはabstract抽象クラスです.
抽象メソッドを含むクラスを抽象クラスと呼びますが、抽象クラスに抽象メソッドしかないという意味ではありません.これは一般クラスと同様に、メンバー変数と一般メンバーメソッドを持つことができます.抽象クラスと一般クラスのアイデアの違いは3つあります.
1、抽象メソッドはpublicまたはprotectedでなければならない(privateの場合、クラスに継承されず、サブクラスに実装されないため)、デフォルトではpublic 2、抽象クラスはオブジェクト3の作成に使用できない、1つのクラスが抽象クラスに継承されている場合、サブクラスは親クラスの抽象メソッドを実装する必要がある.サブクラスが親クラスの抽象メソッドを実装していない場合は、サブクラスもabstract抽象クラスとして定義する必要があります.
他の抽象クラスと普通のクラスには違いはありません.
二、インタフェース
インタフェース、すなわちinterfaceは、ソフトウェアエンジニアリングにおいて、インタフェースは一般的に他の人に呼び出される方法または関数を指す.ここからjava言語設計者の初志を体得することができ,それは行為に対する抽象である.
JAvaにおけるインタフェースの定義形式

[public] interface InterfaceName{}


インタフェースには変数とメソッドが含まれます.ただし、インタフェースの変数はpublic static final変数として暗黙的に指定されます(publicのみでprivate修飾でエラーが発生します).メソッドはpublic abstractメソッドとして暗黙的に指定され、private、protected、static、finalなどの他のキーワードでコンパイルエラーを報告することはできません.また、インタフェース内のすべてのメソッドは具体的に実現できません.つまり、インタフェース内のメソッドは抽象的なメソッドでなければなりません.ここからインタフェースと抽象クラスの違いが暗黙的にわかります.インタフェースは抽象クラスよりも「抽象」であり、一般的にインタフェースに変数を定義しません.
クラスにインタフェースをimplements、フォーマットで実装させる

class ClassName implements Interface1,Interface2{}


1つのクラスが複数の特定のインタフェースに従うことを許可し、1つの非抽象クラスがインタフェースを実現した場合、インタフェース内のすべての方法を実現する必要があることがわかります.あるインタフェースを実装した抽象クラスでは,そのインタフェースにおける抽象メソッドを実装しなくてもよい.
例えばAndroidのソースコードにあるAdapterクラスはインタフェースクラスです

/**
 * An Adapter object acts as a bridge between an {@link AdapterView} and the
 * underlying data for that view. The Adapter provides access to the data items.
 * The Adapter is also responsible for making a {@link android.view.View} for
 * each item in the data set.
 *
 * @see android.widget.ArrayAdapter
 * @see android.widget.CursorAdapter
 * @see android.widget.SimpleCursorAdapter
 */
public interface Adapter {
  void registerDataSetObserver(DataSetObserver observer);
  void unregisterDataSetObserver(DataSetObserver observer);
  int getCount();
  Object getItem(int position);
  long getItemId(int position);
  boolean hasStableIds();
  View getView(int position, View convertView, ViewGroup parent);
  static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;
  int getItemViewType(int position);
  int getViewTypeCount();
  static final int NO_SELECTION = Integer.MIN_VALUE;
   boolean isEmpty();
}


このインタフェースにはいくつかのメソッドが宣言されており、これらのメソッドは抽象的なメソッドです.そしてListAdapterというインタフェースはまたこのAdapterインタフェースを実現しました

public interface ListAdapter extends Adapter {
  public boolean areAllItemsEnabled();
  boolean isEnabled(int position);
}


そう、このListAdapterもインタフェースであり、別のインタフェースを実現するインタフェースであり、つまりこのインタフェースはAdapterというインタフェース宣言の抽象的な方法を継承し、自分で2つの抽象的な方法を宣言している.
最後にBaseAdapterという抽象クラスです.

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
  private final DataSetObservable mDataSetObservable = new DataSetObservable();
  public boolean hasStableIds() {
    return false;
  }
  public void registerDataSetObserver(DataSetObserver observer) {
    mDataSetObservable.registerObserver(observer);
  }
  public void unregisterDataSetObserver(DataSetObserver observer) {
    mDataSetObservable.unregisterObserver(observer);
  }
  public void notifyDataSetChanged() {
    mDataSetObservable.notifyChanged();
  }
  public void notifyDataSetInvalidated() {
    mDataSetObservable.notifyInvalidated();
  }
  public boolean areAllItemsEnabled() {
    return true;
  }
  public boolean isEnabled(int position) {
    return true;
  }
  public View getDropDownView(int position, View convertView, ViewGroup parent) {
    return getView(position, convertView, parent);
  }
  public int getItemViewType(int position) {
    return 0;
  }
  public int getViewTypeCount() {
    return 1;
  }
  public boolean isEmpty() {
    return getCount() == 0;
  }
}


このBaseAdapterは抽象クラスであり、2つのインタフェースを実現している.1つはListAdapterインタフェースであるが、このBaseAdapter抽象クラスには抽象的な方法がなく、唯一のメンバー変数はprivateであり、クラスに継承されない.これらの方法は,ListAdapterとAdapterの2つのインタフェースから実装されていることを注意深く観察した.
これにより、カスタムクラスがBaseAdapterから継承される場合、AdapterとListAdapterのすべてのメソッドを実装する必要はなく、BaseAdapterの親クラスに実装されていないAdapterとListAdapterのすべてのメソッドを実装する必要があります.
カスタムクラスにAdapterというインタフェースを直接実装させない理由を考えてみましょう.ここではandroidのいくつかの設計ニーズに関連しています.個人的には、Adapterインタフェースで定義されている方法が足りない可能性があります.最も主要な方法を定義してすべてのニーズを満たす方法を定義し、ListViewのようなコントロールには特殊な行為が必要です.その後、ListAdapterにAdapterを実現させ、2つの特殊な行為方法を追加します.そして、BaseAdapterで実現する方法は、自分が定義したBaseAdapterの親を継承する子クラスが具体的に実現していない場合に、自分がデフォルトで実現する方法です.子クラスは、親クラスBaseAdapterのメソッドを書き換えることもできます.
要するに,この実装継承関係はandroidソースコードフレームワーク設計のニーズに関係する.プロジェクト開発では参考にすることができます.
三、抽象クラスとインタフェースの違い
1.文法的な違い
1)抽象クラスはメンバーメソッドの実装の詳細を提供することができ、インタフェースにはpublic abstractメソッドしか存在しない.2)抽象クラスのメンバー変数は様々なタイプであってもよく、インタフェースのメンバー変数はpublic static finalタイプのみである.3)インタフェースに静的コードブロックおよび静的メソッドを含めることはできないが、抽象クラスには静的コードブロックおよび静的メソッドがあることができる.4)1つのクラスは1つの抽象クラスしか継承できないが,1つのクラスは複数のインタフェースを実現できる.
2.設計上の違い
1)抽象クラスは一つの事物に対する抽象,すなわちクラスに対する抽象であり,インタフェースは行為に対する抽象である.抽象クラスは、属性、動作を含むクラス全体を抽象化しますが、インタフェースはクラスのローカル(動作)を抽象化します.簡単な例を挙げると、飛行機と鳥は同類ではありませんが、共通性があり、飛ぶことができます.では、設計する時、飛行機を1つのクラスAirplaneに設計することができて、鳥を1つのクラスBirdに設計することができて、しかし飛行のこの特性もクラスに設計することができなくて、そのためそれはただ1つの行為の特性で、1種類の事物に対する抽象的な説明ではありません.このとき,飛行を方法fly()を含むインタフェースFlyとして設計し,AirplaneとBirdはそれぞれ自分のニーズに応じてFlyというインタフェースを実現することができる.そして、戦闘機や民間機など、さまざまな種類の飛行機がAirplaneを直接継承すればよく、鳥にも似ていて、異なる種類の鳥がBird類を直接継承すればよい.ここから,継承は「是非」の関係であり,インタフェース実装は「有無」の関係であることが分かる.あるクラスがある抽象クラスを継承している場合、サブクラスは必ず抽象クラスの種類であり、インタフェース実装は鳥が飛べるかどうか(あるいは飛行という特徴を備えているかどうか)、飛べるかどうかはこのインタフェースを実現することができ、飛べないかはこのインタフェースを実現しない.
2)設計面が異なり,抽象クラスは多くのサブクラスの親としてテンプレート式設計である.インタフェースは放射式設計である挙動規範である.テンプレートデザインとは?最も簡単な例、みんなはすべてpptの中のテンプレートを使ったことがあって、もしテンプレートAでppt Bとppt Cを設計したら、ppt Bとppt Cの共通の部分はテンプレートAで、もしそれらの共通の部分が変更する必要があるならば、テンプレートAを変えるだけでいいので、ppt Bとppt Cを再び変更する必要はありません.放射線式の設計、例えばあるエレベーターには警報器が設置されており、警報器を更新するには、すべて更新しなければならない.すなわち、抽象クラスに対して、新しい方法を追加する必要がある場合は、抽象クラスに具体的な実装を直接追加することができ、サブクラスは変更しなくてもよい.インタフェースについてはだめで,インタフェースが変更された場合,このインタフェースを実現するすべてのクラスは相応の変更を行わなければならない.
次に、ドアとアラートの例を見てみましょう.ドアにはopen()とclose()の2つのアクションがあります.この場合、抽象クラスとインタフェースを通じてこの抽象概念を定義することができます.

abstract class Door {
  public abstract void open();
  public abstract void close();
}


または、

interface Door {
  public abstract void open();
  public abstract void close();
}


しかし、ドアにアラームalarm()の機能が必要な場合は、どのように実現すればいいですか?次の2つのアイデアを提供します.
1)この3つの機能を抽象クラスに入れるが,この抽象クラスに継承されたすべてのサブクラスはアラーム機能を備えているが,必ずしもアラーム機能を備えていないドアがある.2)この3つの機能をインタフェースに入れて、アラーム機能を必要とするクラスはこのインタフェースのopen()とclose()を実現する必要があります.このクラスはopen()とclose()の2つの機能を備えていないかもしれません.例えば、火災警報器です.
ここから,Doorのopen(),close()およびalarm()は根本的に2つの異なるカテゴリ内の挙動に属し,open()およびclose()はゲート自体固有の挙動特性に属し,alarm()は拡張された付加的挙動に属することが分かる.したがって、最良の解決策は、アラームを単独でインタフェースとして設計し、alarm()動作を含み、Doorはopenとcloseの2つの動作を含む単独の抽象クラスとして設計することである.アラームゲートがDoorクラスを継承し、Alarmインタフェースを実現するように設計した.

interface Alram {
  void alarm();
}
abstract class Door {
  void open();
  void close();
}
class AlarmDoor extends Door implements Alarm {
  void oepn() {
   //....
  }
  void close() {
   //....
  }
  void alarm() {
   //....
  }
}


Javaアルゴリズムに関する詳細に興味のある読者は、「Javaオブジェクト向けプログラム設計入門と進級チュートリアル」、「Javaデータ構造とアルゴリズムチュートリアル」、「Java操作DOMノードテクニック総括」、「Javaファイルとディレクトリ操作テクニック要約」、「Javaキャッシュ操作テクニック要約」のトピックを参照してください.
本文で述べたjavaプログラム設計に役立つことを願っています.