Java基礎 第11回ではカプセル化のことを学んでいきました。
本記事では、オブジェクト指向プログラミングの主要な概念である「継承」について詳しく解説します。「継承」を活用することで、実践的なプログラミングを身に着けることができます。
この記事は、オブジェクト指向プログラミングの概念を理解しようとする初心者、または継承についてより深く理解したいと考えているプログラマーにとって役に立つ内容となっています。文章を通じて、全体的な概念を把握でき、さらに詳細な内容を理解することで、プログラミングスキルの向上に役立つでしょう。
継承の役割と重要性
継承はオブジェクト指向プログラミングの3つの主要な柱の1つであり、これによりソフトウェアの再利用性と保守性が大幅に向上します。
具体的には、継承は親クラスの特性(フィールド)と能力(メソッド)を子クラスに受け継ぐことを可能にします。これにより、既存のコードを再利用し、新たに追加や変更を行うことで新しいクラスを効率的に作成することが可能になります。
たとえば、”動物”というクラスを作成したとします。このクラスには、全ての動物が共有する一般的な特性(名前、年齢など)と能力(食べる、眠るなど)を定義します。その後、”犬”や”猫”という新しいクラスを作成する際には、”動物”クラスを親クラスとして継承し、これらの特性と能力を再利用することができます。さらに、犬や猫固有の特性や能力(吠える、鳴くなど)を追加することで、より詳細なクラスを作成することができます。
このように、継承はプログラムの構造を整理し、コードの再利用を促進し、開発の効率化をすることができます。
継承の基本概念
Javaでは、継承は「extends」というキーワードを使用して行います。
基本的な構文は以下のようになります。
class 子クラス名 extends 親クラス名 {
// 子クラスのフィールドやメソッドを記述
}
例えば、「Animal」クラス(親クラス)があるとして、その特性と能力を継承した「Dog」クラス(子クラス)を作成するには次のように記述します。
class Dog extends Animal {
// Dogクラスのフィールドやメソッドを記述
}
これにより、「Dog」クラスは「Animal」クラスの全ての公開フィールドとメソッドを利用することができます。
継承の例とメソッドのオーバーライド
では、継承の具体的な例を見てみましょう。「Animal」クラスを親クラスとし、その特性と能力を継承した「Dog」クラスを子クラスとして作成します。
まず、親クラスである「Animal」クラスを作成します。
class Animal {
void eat() {
System.out.println("The animal eats.");
}
}
次に、「Animal」クラスを継承した「Dog」クラスを作成します。「Dog」クラスは「Animal」クラスの全てのメソッド(この場合は「eat」メソッド)を利用することができます。
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}
また、子クラスでは親クラスのメソッドをオーバーライド(上書き)することができます。この場合、親クラスのメソッドと同じ名前のメソッドを子クラスで定義します。この新しいメソッドは親クラスのメソッドを上書きし、同じ名前のメソッドが呼び出されると子クラスのメソッドが実行されます。
以下の「Dog」クラスでは、「eat」メソッドをオーバーライドして、犬固有の食事の方法を定義します。
class Dog extends Animal {
@Override
void eat() {
System.out.println("The dog eats dog food.");
}
void bark() {
System.out.println("The dog barks.");
}
}
継承の利点と欠点の具体例
利点:コードの再利用
既存のクラスから新しいクラスを作成する際に、コードを再利用できます。たとえば、以下のような「Animal」クラスがあったとします。
class Animal {
void eat() {
System.out.println("The animal eats.");
}
}
このクラスを継承して新しい「Dog」クラスを作成するとき、eatメソッドはすでに「Animal」クラスから受け継がれるため、再度書く必要はありません。
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}
欠点:コードの複雑さ
しかし、一方で継承の使用が過度になると、コードが複雑になる可能性があります。特に、多層継承(クラスが多数の親クラスから派生する場合)を行うと、どのクラスがどのメソッドを持っているのか、またどのクラスがどのクラスから派生しているのかが分かりにくくなることがあります。
例えば、次のような状況を考えてみましょう。
class Animal {
void eat() {
System.out.println("The animal eats.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}
class Poodle extends Dog {
void doTrick() {
System.out.println("The poodle does a trick.");
}
}
この場合、「Poodle」クラスは「Animal」クラスと「Dog」クラスの両方のメソッドを持っています。これは一見すると便利に思えますが、継承のチェーンが長くなるほど、どのメソッドがどのクラスから継承されたものなのかを把握するのが難しくなる場合があります。
まとめ
今回はオブジェクト指向プログラミングの主要な考え方である継承についてご紹介していきました。
継承と聞くと難しい、というような印象があるかもしれませんが実はとてもシンプルであるということがお判りいただけたのではないでしょうか?
もしまだなかなかイメージができないというような方は何度か読み返し、コードを実際に書いてみたりし、100%理解できていなくても次の記事に進んでみてください。何度も復習することでふと理解できる瞬間がやってきたりします。
次回は抽象クラスについて紹介していきます。
お楽しみに!
コメント