この記事では、オブジェクト指向プログラミングにおける継承の基本概念と、Javaを使った具体的な実装例を理解することができます。継承とは、既存のクラスの特性を新しいクラスに引き継ぐオブジェクト指向プログラミングの重要な機能です。これにより、コードの再利用性が高まり、階層構造を持つプログラムの設計が可能になります。
はじめに
この記事のコードをコピペしてEclipseで出力結果を確認してみよう!
継承の基本
継承を使用すると、既存のクラス(親クラスまたはスーパークラス)の特性を新しいクラス(子クラスまたはサブクラス)に引き継ぐことができます。子クラスは親クラスのすべてのpublicおよびprotectedメンバー(フィールドとメソッド)を継承します。
Javaでは、extendsキーワードを使用してクラスを継承します。基本的な構文は次のとおりです:
public class 子クラス名 extends 親クラス名 {
// 子クラスの内容
}
プログラム例1: 動物と犬
以下は、動物クラスを親クラスとし、犬クラスを子クラスとする簡単な例です。
Animal.java
// 親クラス: 動物
public class Animal {
protected String name; // 動物の名前
// コンストラクタ
public Animal(String name) {
this.name = name;
}
// 鳴く方法(一般的な動物の鳴き方)
public void makeSound() {
System.out.println(name + "が鳴いています。");
}
}
Dog.java
// 子クラス: 犬
public class Dog extends Animal {
// コンストラクタ
public Dog(String name) {
super(name); // 親クラスのコンストラクタを呼び出す
}
// 犬特有の鳴き方をオーバーライド
@Override
public void makeSound() {
System.out.println(name + "がワンワンと吠えています。");
}
// 犬特有のメソッド
public void fetch() {
System.out.println(name + "がボールを取ってきました。");
}
}
Main.java
// メインクラス
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog("ポチ");
myDog.makeSound(); // 犬の鳴き方を呼び出す
myDog.fetch(); // 犬特有のメソッドを呼び出す
}
}
出力結果:
ポチがワンワンと吠えています。
ポチがボールを取ってきました。
Animal.javaの解説
クラス宣言
public class Animal {
// ...
}
public
キーワードは、このクラスが他のパッケージからもアクセス可能であることを示します。class Animal
は、Animal
という名前のクラスを定義しています。
フィールド宣言
protected String name; // 動物の名前
protected
キーワードは、このフィールドが同じパッケージ内のクラスとサブクラスからアクセス可能であることを示します。String name
は、動物の名前を格納するための文字列型のフィールドを宣言しています。
コンストラクタ
public Animal(String name) {
this.name = name;
}
- このコンストラクタは、
Animal
オブジェクトを生成する際に呼び出されます。 String name
パラメータを受け取り、それをクラスのフィールドname
に代入します。this.name
のthis
は、現在のオブジェクトを指すキーワードです。
メソッド
public void makeSound() {
System.out.println(name + "が鳴いています。");
}
public
キーワードは、このメソッドが他のクラスからもアクセス可能であることを示します。void
は、このメソッドが値を返さないことを示します。makeSound()
は、動物が鳴く動作を表現するメソッドです。System.out.println()
を使用して、動物の名前と「が鳴いています。」というメッセージを出力します。
このクラスは、動物の基本的な特性(名前と鳴く能力)を定義しており、他の具体的な動物クラス(例:犬、猫など)の親クラスとして使用できます。サブクラスでは、この基本的な機能を継承し、必要に応じて拡張や上書きを行うことができます。
Dog.javaの解説
クラス宣言
public class Dog extends Animal {
// ...
}
public
キーワードは、このクラスが他のパッケージからもアクセス可能であることを示します。class Dog
は、Dog
という名前のクラスを定義しています。extends Animal
は、Dog
クラスがAnimal
クラスを継承していることを示します。これにより、Dog
はAnimal
の特性を引き継ぎます。
コンストラクタ
public Dog(String name) {
super(name); // 親クラスのコンストラクタを呼び出す
}
- このコンストラクタは、
Dog
オブジェクトを生成する際に呼び出されます。 super(name)
は親クラス(Animal
)のコンストラクタを呼び出しています。これにより、name
フィールドが初期化されます。
メソッドのオーバーライド
@Override
public void makeSound() {
System.out.println(name + "がワンワンと吠えています。");
}
@Override
アノテーションは、このメソッドが親クラスのメソッドをオーバーライド(上書き)していることを明示します。- このメソッドは
Animal
クラスのmakeSound()
メソッドを犬特有の動作に再定義しています。 System.out.println()
を使用して、犬の名前と「がワンワンと吠えています。」というメッセージを出力します。
犬特有のメソッド
public void fetch() {
System.out.println(name + "がボールを取ってきました。");
}
fetch()
メソッドは、Dog
クラス特有のメソッドです。親クラスAnimal
にはこのメソッドはありません。- このメソッドは、犬がボールを取ってくる動作を表現しています。
System.out.println()
を使用して、犬の名前と「がボールを取ってきました。」というメッセージを出力します。
このクラスは、Animal
クラスの基本的な特性を継承しつつ、犬特有の動作(特定の鳴き方やボールを取ってくること)を追加しています。makeSound()
メソッドをオーバーライドすることで、一般的な動物の鳴き方ではなく、犬特有の鳴き方を実装しています。また、fetch()
メソッドの追加により、犬特有の行動を表現しています。
Main.javaの解説
クラス宣言
public class Main {
// ...
}
public
キーワードは、このクラスが他のパッケージからもアクセス可能であることを示します。class Main
は、Main
という名前のクラスを定義しています。これは通常、プログラムのエントリーポイントを含むクラスの名前として使用されます。
main メソッド
public static void main(String[] args) {
// ...
}
public static void main(String[] args)
は Java プログラムのエントリーポイントです。public
は、このメソッドが他のクラスからアクセス可能であることを示します。static
は、このメソッドがクラスレベルのメソッドであり、インスタンス化なしで呼び出せることを示します。void
は、このメソッドが値を返さないことを示します。String[] args
は、コマンドライン引数を受け取るための配列パラメータです。
オブジェクトの生成と操作
Dog myDog = new Dog("ポチ");
new Dog("ポチ")
でDog
クラスのインスタンスを生成しています。"ポチ"
は犬の名前として渡されています。- 生成されたオブジェクトは
myDog
変数に代入されます。
myDog.makeSound(); // 犬の鳴き方を呼び出す
myDog
オブジェクトのmakeSound()
メソッドを呼び出しています。- これは
Dog
クラスでオーバーライドされたメソッドなので、「ポチがワンワンと吠えています。」と出力されるはずです。
myDog.fetch(); // 犬特有のメソッドを呼び出す
myDog
オブジェクトのfetch()
メソッドを呼び出しています。- これは
Dog
クラス特有のメソッドで、「ポチがボールを取ってきました。」と出力されるはずです。
このメインクラスは、Dog
クラスのインスタンスを生成し、そのメソッドを呼び出すことで、継承とポリモーフィズムの動作を実演しています。makeSound()
メソッドは Animal
クラスから継承され Dog
クラスでオーバーライドされたもの、fetch()
メソッドは Dog
クラス特有のものであり、これらの呼び出しによって、オブジェクト指向プログラミングの基本概念が実践されています。
プログラム例2: 形状の階層
次の例では、形状の階層を示します。
Shape.java
// 親クラス: 形状
public class Shape {
protected String color; // 形状の色
// コンストラクタ
public Shape(String color) {
this.color = color;
}
// 面積を計算するメソッド(デフォルトでは0を返す)
public double calculateArea() {
return 0;
}
// 形状の情報を表示するメソッド
public void displayInfo() {
System.out.println("これは" + color + "色の形状です。");
}
}
Circle.java
// 子クラス: 円
public class Circle extends Shape {
private double radius; // 円の半径
// コンストラクタ
public Circle(String color, double radius) {
super(color); // 親クラスのコンストラクタを呼び出す
this.radius = radius;
}
// 円の面積を計算するメソッドをオーバーライド
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
// 円の情報を表示するメソッドをオーバーライド
@Override
public void displayInfo() {
super.displayInfo(); // 親クラスのメソッドを呼び出す
System.out.println("これは半径" + radius + "の円です。");
}
}
Main.java
// メインクラス
public class Main {
public static void main(String[] args) {
Circle myCircle = new Circle("赤", 5.0);
myCircle.displayInfo();
System.out.println("円の面積: " + myCircle.calculateArea());
}
}
出力結果:
これは赤色の形状です。
これは半径5.0の円です。
円の面積: 78.53981633974483
Shape.javaの解説
クラス宣言
public class Shape {
// ...
}
public
キーワードは、このクラスが他のパッケージからもアクセス可能であることを示します。class Shape
は、Shape
という名前のクラスを定義しています。これは様々な形状の基本となる親クラスです。
フィールド宣言
protected String color; // 形状の色
protected
キーワードは、このフィールドが同じパッケージ内のクラスとサブクラスからアクセス可能であることを示します。String color
は、形状の色を格納するための文字列型のフィールドを宣言しています。
コンストラクタ
public Shape(String color) {
this.color = color;
}
- このコンストラクタは、
Shape
オブジェクトを生成する際に呼び出されます。 String color
パラメータを受け取り、それをクラスのフィールドcolor
に代入します。this.color
のthis
は、現在のオブジェクトを指すキーワードです。
面積計算メソッド
public double calculateArea() {
return 0;
}
public
キーワードは、このメソッドが他のクラスからもアクセス可能であることを示します。double
は、このメソッドが倍精度浮動小数点数を返すことを示します。- このメソッドはデフォルトで0を返します。これは、具体的な形状がない一般的な
Shape
クラスでは面積を計算できないためです。 - このメソッドは子クラスでオーバーライドされることを想定しています。
情報表示メソッド
public void displayInfo() {
System.out.println("これは" + color + "色の形状です。");
}
void
は、このメソッドが値を返さないことを示します。- このメソッドは、形状の色に関する基本的な情報を表示します。
System.out.println()
を使用して、形状の色を含むメッセージを出力します。
このクラスは、形状の基本的な特性(色)と操作(面積計算、情報表示)を定義しています。具体的な形状(例:円、四角形など)のクラスは、この Shape
クラスを継承し、必要に応じてメソッドをオーバーライドすることで、より具体的な実装を提供できます。特に calculateArea()
メソッドは、子クラスで適切にオーバーライドされることが期待されています。
Circle.javaの解説
クラス宣言
public class Circle extends Shape {
// ...
}
public
キーワードは、このクラスが他のパッケージからもアクセス可能であることを示します。extends Shape
は、Circle
クラスがShape
クラスを継承していることを示します。これにより、Circle
はShape
の特性を引き継ぎます。
フィールド宣言
private double radius; // 円の半径
private
キーワードは、このフィールドがこのクラス内でのみアクセス可能であることを示します。double radius
は、円の半径を格納するための倍精度浮動小数点数型のフィールドを宣言しています。
コンストラクタ
public Circle(String color, double radius) {
super(color); // 親クラスのコンストラクタを呼び出す
this.radius = radius;
}
- このコンストラクタは、
Circle
オブジェクトを生成する際に呼び出されます。 super(color)
は親クラス(Shape
)のコンストラクタを呼び出しています。これにより、color
フィールドが初期化されます。this.radius = radius;
で、円の半径を初期化しています。
面積計算メソッドのオーバーライド
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
アノテーションは、このメソッドが親クラスのメソッドをオーバーライドしていることを明示します。- このメソッドは
Shape
クラスのcalculateArea()
メソッドを円特有の計算方法で再定義しています。 - 円の面積計算式(πr²)を使用して面積を計算し、結果を返します。
情報表示メソッドのオーバーライド
@Override
public void displayInfo() {
super.displayInfo(); // 親クラスのメソッドを呼び出す
System.out.println("これは半径" + radius + "の円です。");
}
- このメソッドも
@Override
アノテーションで親クラスのメソッドをオーバーライドしていることを示しています。 super.displayInfo();
で親クラスのdisplayInfo()
メソッドを呼び出し、基本的な形状情報を表示します。- その後、円特有の情報(半径)を追加で表示します。
このクラスは、Shape
クラスの基本的な特性を継承しつつ、円特有の属性(半径)と動作(面積計算、詳細情報表示)を追加しています。calculateArea()
メソッドをオーバーライドすることで、一般的な形状ではなく、円特有の面積計算を実装しています。また、displayInfo()
メソッドのオーバーライドにより、親クラスの情報に加えて円特有の情報も表示できるようになっています。
Main.javaの解説
クラス宣言
public class Main {
// ...
}
public
キーワードは、このクラスが他のパッケージからもアクセス可能であることを示します。class Main
は、Main
という名前のクラスを定義しています。これは通常、プログラムのエントリーポイントを含むクラスの名前として使用されます。
main メソッド
public static void main(String[] args) {
// ...
}
public static void main(String[] args)
は Java プログラムのエントリーポイントです。public
は、このメソッドが他のクラスからアクセス可能であることを示します。static
は、このメソッドがクラスレベルのメソッドであり、インスタンス化なしで呼び出せることを示します。void
は、このメソッドが値を返さないことを示します。String[] args
は、コマンドライン引数を受け取るための配列パラメータです。
オブジェクトの生成
Circle myCircle = new Circle("赤", 5.0);
new Circle("赤", 5.0)
でCircle
クラスのインスタンスを生成しています。"赤"
は円の色、5.0
は円の半径として渡されています。- 生成されたオブジェクトは
myCircle
変数に代入されます。
メソッドの呼び出し
myCircle.displayInfo();
myCircle
オブジェクトのdisplayInfo()
メソッドを呼び出しています。- これにより、円の色と半径に関する情報が表示されます。
System.out.println("円の面積: " + myCircle.calculateArea());
myCircle.calculateArea()
を呼び出して円の面積を計算し、その結果を出力しています。System.out.println()
を使用して、計算結果を “円の面積: ” というテキストと共に表示します。
このメインクラスは、Circle
クラスのインスタンスを生成し、そのメソッドを呼び出すことで、継承とポリモーフィズムの動作を実演しています。displayInfo()
メソッドは Shape
クラスから継承され Circle
クラスでオーバーライドされたもの、calculateArea()
メソッドも同様にオーバーライドされたものです。これらの呼び出しによって、オブジェクト指向プログラミングの基本概念が実践されています。
まとめ
- 継承はコードの再利用性を高め、クラス間の階層構造を作り出す強力な機能です
- 抽象クラスや抽象メソッドを使用することで、サブクラスでの実装を強制できます
- メソッドのオーバーライドにより、サブクラス固有の動作を定義できます
- 継承を適切に使用することで、柔軟で拡張性の高いプログラム設計が可能になります
継承の概念を理解し、適切に活用することで、より効率的で保守性の高いコードを書くことができます。ただし、継承の過剰な使用は避け、必要な場合にのみ適用することが重要です。
コメント