継承はオブジェクト指向における重要な概念です。継承は、合成に加えてコードの再利用性を向上させるもう 1 つの重要な方法です。コンポジションでは、コンポジションが繰り返し呼び出されるオブジェクトの関数インターフェイスであることが分かりました。これから説明するように、継承を使用すると、既存のクラス定義を再利用できます。
クラスの継承
以前にクラスを定義したときは、最初からクラスの各メンバーを詳細に定義しました。たとえば、次の Human クラス:
次のようにコードをコピーします。
クラス人間
{
/**
*アクセサ
*/
public int getHeight()
{
this.height を返します。
}
/**
* ミューテーター
*/
public void 成長高さ(int h)
{
この高さ = この高さ + h;
}
/**
*呼吸
*/
パブリックボイドブレス()
{
System.out.println("ふ…ふ…");
}
プライベート int 高さ;
}
上記のクラス定義から、クラスのデータ メンバー、クラスのメソッド、クラスのインターフェイスなど、クラスの詳細をすべて理解できます。
ここで、Woman クラスなどの新しいクラスを定義する必要があります。Woman クラスは Human クラスに非常に似ていると仮定します。
人間と女性
ゼロから始めて、以前と同じように Woman クラスを完全に定義できます。
次のようにコードをコピーします。
クラスの女性
{
/**
*アクセサ
*/
public int getHeight()
{
this.height を返します。
}
/**
* ミューテーター
*/
public void 成長高さ(int h)
{
この高さ = この高さ + h;
}
/**
*呼吸
*/
パブリックボイドブレス()
{
System.out.println("ふ…ふ…");
}
/**
* 新しい方法
*/
public Human giveBirth()
{
System.out.println("出産");
return (new Human(20));
}
プライベート int 高さ;
}
プログラマが上記のプログラムを書くときは非常に苦労するでしょう。 Human クラスには多くの定義が記述されていますが、それらを再度入力する必要があります。 Woman クラスは、新しい giveBirth() メソッドを追加するだけです (このメソッドは新しい Human オブジェクトを作成して返します)。
継承を使用すると、上記の重複を回避できます。 Woman クラスを Human クラスから継承すると、Woman クラスは Human クラスのすべてのパブリック メンバーの機能を自動的に持つようになります。
extends キーワードを使用して継承を示します。
次のようにコードをコピーします。
クラスの女性は人間を拡張します
{
/**
* 新しい方法
*/
public Human giveBirth()
{
System.out.println("出産");
return (new Human(20));
}
}
このようにして、入力の手間を大幅に節約できます。継承を通じて、派生クラスと呼ばれる新しいクラスを作成します。継承されたクラス(Human)を基底クラス(base class)と呼びます。派生クラスは、基本クラスを独自の定義の基礎として使用し、基本クラスで定義されていない giveBirth() メソッドを補足します。継承関係は次のように表現できます。
継承: 矢印は基本クラスを指します
次の Test クラスを使用してテストできます。
次のようにコードをコピーします。
パブリッククラステスト
{
public static void main(String[] args)
{
女性 aWoman = new Woman();
aWoman.growHeight(120);
System.out.println(aWoman.getHeight());
}
}
派生レイヤー
継承を通じて、Woman クラスを作成します。プロセス全体は、基本クラスの定義、派生クラスの定義、外部使用の 3 つのレベルに分けることができます。
基本クラス定義のレベルは、上記の Human クラス定義など、通常のクラスを定義することです。
外部ユーザー (Test クラスで作成された Woman クラス オブジェクトなど) の観点から見ると、派生クラスには統合された外部インターフェイスがあります。
外部ユーザーの場合は、上記のインターフェイスで十分です。インターフェイスの観点だけから見ると、派生クラスには特別なことは何もありません。
ただし、プログラマは、派生クラス定義のレベルで作業する場合には注意する必要があります。
まず、インターフェイスが混合されています。getHeight() メソッドと giveHeight() メソッドは基本クラスから取得されますが、giveBirth() メソッドは派生クラス内で定義されています。
さらに複雑な問題があります。これまでは、クラス内でクラスのメンバーに自由にアクセスできました (これを使用してオブジェクトを参照しました)。ただし、Woman クラスの定義スコープ内にいるときは、基本クラス Human のプライベート メンバーにアクセスできません。プライベートの意味を思い出してください。プライベート メンバーはクラスの内部でのみ使用されます。 Woman クラスは Human クラスとは異なる新しいクラスであり、Human クラスの外側に位置します。派生クラスでは、基本クラスのプライベート メンバーにアクセスできません。
しかし、興味深いのは、growHeight() メソッドと getHeight() メソッドが引き続き機能することです。これは、基本クラスのプライベート メンバーが存在することを示していますが、それらに直接アクセスできないだけです。
概念を明確にするためには、派生クラス オブジェクトの生成メカニズムを理解する必要があります。派生クラスのオブジェクトを作成するとき、Java は実際に最初に基本クラスのオブジェクト (サブオブジェクト) を作成し、派生クラスによって定義された他のメンバーを追加して派生クラス オブジェクトを構成します。外部ユーザーが参照できるのは、基本クラスと派生クラスのパブリック メンバーです。以下に示すように:
基本クラスのオブジェクトと派生クラスのオブジェクト
図の黄色は基本クラスのオブジェクトです。基本層のメンバーは相互にアクセスできます (これを Human クラス定義で使用して、基本クラス オブジェクトを参照します)。
青い部分は派生オブジェクトの新しいコンテンツです。この部分を派生レイヤーと呼びます。青と黄色の部分が一緒になって派生オブジェクトを形成します。派生レイヤーのメンバーは相互にアクセスできます (これは女性の定義にあります)。さらに、ベースレイヤーのパブリックメンバーにもアクセスできます。このため、super キーワードを使用して基本クラス オブジェクトを参照し、super.member を使用して基本 (パブリック) メンバーを表します。
派生レイヤーにいるとき (つまり、Woman クラスを定義しているとき)、赤いベースのプライベート メンバーにアクセスできません。屋外にいるときは、紫色の派生レイヤーのプライベート メンバーにも、赤色のベース レイヤのプライベート メンバーにもアクセスできません。
(派生層のプライベート メンバーにはアクセス制限があるため、スラッシュでマークされています。基本層のプライベート メンバーには最も多くのアクセス制限があるため、クロス スラッシュでマークされています)
Super もこれに似ており、暗黙的なパラメータです。クラス定義の異なるレベルにある場合、これは異なる意味を持ちます。 this キーワードと super キーワードには注意してください。
(Java は this と super の使用を強制しません。Java は多くの場合、メンバーの所有権を自動的に識別できます。しかし、これは良い習慣だと思います。)
保護された
以前に、メンバーの外部表示を制御する 2 つのアクセス許可関連キーワード、プライベートとパブリックを紹介しました。ここで、新しいアクセス キーワード protected を導入します。
protected とマークされたメンバーは、このクラスとその派生クラスに表示されます。この概念は簡単に理解できます。つまり、以下に示すように、基本クラスの保護されたメンバーには派生層からアクセスできますが、外部からはアクセスできません。
メソッドのオーバーライド
派生クラス オブジェクトの外部インターフェイスは、最終的には基本クラス オブジェクトのパブリック メンバーと派生層のパブリック メンバーで構成されます。基本クラスのパブリック メンバーと派生層のパブリック メンバーが同じ名前を持つ場合、Java インターフェイスにはどちらが表示されますか?
コンストラクターとメソッドのオーバーロードで、Java はメソッド名とパラメーター リストの両方を使用して呼び出されるメソッドを決定することをすでに説明しました。メソッドはメソッド名とパラメータ リストによって決まります。上記の問題では、メソッド名のみが同じでパラメータ リストが異なる場合、2 つのメソッドが同時にインターフェイスに提示されるため、問題は発生しません。外部呼び出しを行うとき、Java は指定されたパラメーターに基づいて、どのメソッドを使用するか (メソッドのオーバーロード) を決定します。
メソッド名とパラメータリストが両方とも同じ場合はどうなるでしょうか? レイヤーを導出するときに、super と this を使用して、それがどのメソッドであるかを決定することもできます。外部の場合は、統一されたインターフェイスのみを提供するため、2 つのメソッドを同時に提供することはできません。この場合、Java は基本層メソッドの代わりに派生層メソッドをレンダリングします。
このメカニズムはメソッドのオーバーライドと呼ばれます。メソッドのオーバーライドは、基本クラスのメンバーのメソッドを変更するために有効に使用できます。たとえば、派生レイヤーで、つまり Woman を定義するときに、基本クラスによって提供される Breath() メソッドを変更できます。
次のようにコードをコピーします。
クラスの女性は人間を拡張します
{/**
* 新しい方法
*/
public Human giveBirth()
{
System.out.println("出産");
return (new Human(20));
}
/**
* Human.breath() をオーバーライドします
*/
パブリックボイドブレス()
{
スーパーブレス();
System.out.println("su...");
}
}
現時点では派生層にいますが、スーパーを通じて基本クラス オブジェクトの Breath() メソッドを呼び出すことができることに注意してください。 Woman クラスを外部から呼び出すと、メソッドのオーバーライドにより、基本クラス オブジェクトのメソッドを呼び出すことができなくなります。
メソッドのオーバーライドは、基本クラス オブジェクトのインターフェイスを維持し、派生層の実装を使用します。
コンストラクタ
基本クラスのオブジェクトと派生層の概念を理解すると、派生クラスの構築方法を理解しやすくなります。
派生クラスの定義では、クラスと同じ名前のコンストラクターを定義する必要があります。このコンストラクターでは次のようになります。
1. 派生オブジェクトを作成するときは、最初に基本クラスのオブジェクトが作成および初期化されるため、最初に基本クラスのコンストラクターを呼び出す必要があります。 super(argument list) ステートメントを使用して、基本クラスのコンストラクターを呼び出すことができます。
2. 基本クラス オブジェクトが作成されたら、派生層の構築を開始します (派生層メンバーの初期化)。これは一般的な工法と同じです。工法とメソッドのオーバーロードを参照してください。
たとえば、次のプログラムでは、Human クラスにコンストラクターがあります。
次のようにコードをコピーします。
クラス人間
{
/**
* コンストラクター
*/
public Human(int h)
{
this.height = h;
}
/**
*アクセサ
*/
public int getHeight()
{
this.height を返します。
}
/**
* ミューテーター
*/
public void 成長高さ(int h)
{
この高さ = この高さ + h;
}
/**
*呼吸
*/
パブリックボイドブレス()
{
System.out.println("ふ…ふ…");
}
プライベート int 高さ;
}
派生クラス Woman クラスの定義とその構築方法:
次のようにコードをコピーします。
クラスの女性は人間を拡張します
{
/**
* コンストラクター
*/
パブリックウーマン(int h)
{
super(h); // 基本クラスのコンストラクター
System.out.println("こんにちは、パンドラ!");
}
/**
* 新しい方法
*/
public Human giveBirth()
{
System.out.println("出産");
return (new Human(20));
}
/**
* Human.breath() をオーバーライドします
*/
パブリックボイドブレス()
{
スーパーブレス();
System.out.println("su...");
}
}
要約する
伸びる
メソッドのオーバーライド
保護された
super.member、super()