3分間プログラミング講座 第5回: 「共通の設計図」から「新しい設計図」を作る~継承~
登場人物:
チャット先生(通称:先生): オブジェクト指向マスター。普段は優しく、たまにユーモアも交えながら解説。
ボット助手(通称:ボット君): プログラミングを始めたばかりの若手。素朴な疑問を投げかけるのが得意。
ボット君: 先生!今日は「継承」について教えてくれるんですよね!「共通の設計図から新しい設計図を作る」って、なんだか秘密基地をパワーアップさせるみたいでワクワクします!
先生: ハハハ、またボット君らしい表現だね!まさにその「パワーアップ」や「共通部分の活用」が、今日のテーマ「継承(Inheritance)」の核心だよ。オブジェクト指向の三大要素(カプセル化、継承、ポリモーフィズム)の一つで、これもとても大切な概念なんだ。
ボット君: 三大要素、残りの一つですね!わくわくします!
先生: そうだよ。これまで「クラスは設計図、オブジェクトは実体」と学んできたね。そして「単一責任の原則」でクラスの役割を明確に分け、「カプセル化」でクラスの内部を安全に保つ方法を学んだ。継承は、これらの知識をさらに効率的に活用するための仕組みなんだ。
継承とは?~「親」から「子」へ受け継がれるもの~
先生: まずは、身近な例で考えてみよう。ボット君、君は「人間」だね。
ボット君: はい、そうです!
先生: じゃあ、人間にはどんな共通の特徴がある?
ボット君: えーと、二本足で歩く、言葉を話す、ご飯を食べる、みたいなことですか?
先生: その通り!では、人間の中にも「学生」や「社会人」や「先生」といった、いろいろな「種類」があるね。
ボット君: はい、僕も今は「学生」ボット君です!
先生: 素晴らしい!ここで考えてほしいのは、「学生」という種類は、「人間」という大きな枠組みが持っている特徴を、ほとんどそのまま持っている、ということだ。二本足で歩くし、言葉も話すし、ご飯も食べる。それに加えて、「学校に通う」「勉強する」といった「学生」ならではの特徴がある。
ボット君: なるほど!「人間」が持っていることを、そのまま受け継いで、さらに何か追加する、みたいな感じですか?
先生: まさにその感覚だ!プログラミングの世界でも、この「受け継ぐ」という仕組みを「継承(Inheritance)」と呼ぶんだ。
共通する特徴を持つ元のクラスを「親クラス(スーパークラス、基底クラス)」と呼ぶ。
親クラスの特徴を受け継ぎ、さらに独自の機能を追加・変更する新しいクラスを「子クラス(サブクラス、派生クラス)」と呼ぶ。
先生: 以降、分かりやすさのため「親クラス」「子クラス」と呼ぶことにするね。 こうすることで、親クラスに書かれた共通のデータやメソッドを、子クラスで繰り返し書かずに済むんだ。
継承の書き方と例
先生: Javaでは、extendsというキーワードを使って継承を表すよ。
Java
// 親クラス:Car (車の共通の設計図)
public class Car {
private String color;
private String maker;
private int speed;
public Car(String color, String maker) {
this.color = color;
this.maker = maker;
this.speed = 0;
System.out.println(this.maker + "製の" + this.color + "の車が作られました!");
}
// getterメソッド(省略)
public String getColor() { return this.color; }
public String getMaker() { return this.maker; }
public int getSpeed() { return this.speed; }
// setterメソッド(一部省略)
public void setSpeed(int speed) {
if (speed < 0) {
System.out.println("速度は負の値にできません。");
// 実際の開発では、不正な値に対しては例外を投げることも多いよ(例:throw new IllegalArgumentException("速度は負の値にできません。");)。
return;
}
if (speed > 300) {
System.out.println("速度上限を超えています。300km/hに設定します。");
this.speed = 300;
return;
}
this.speed = speed;
System.out.println("速度を" + speed + "km/hに設定しました。");
}
public void accelerate(int accelerationSpeed) {
setSpeed(this.speed + accelerationSpeed);
}
public void brake() {
setSpeed(0);
System.out.println(this.maker + "の車が停止しました。");
}
}
// 子クラス:ElectricCar (電気自動車の設計図)
// Carクラスの特徴を全て継承する
public class ElectricCar extends Car {
private int batteryLevel; // 電気自動車独自の属性
// コンストラクタ
public ElectricCar(String color, String maker, int batteryLevel) {
// 親クラス(Car)のコンストラクタを呼び出す
super(color, maker);
this.batteryLevel = batteryLevel;
System.out.println("これは電気自動車です。バッテリー残量:" + this.batteryLevel + "%");
}
// 電気自動車独自のメソッド
public void charge() {
this.batteryLevel = 100;
System.out.println("バッテリーを充電しました。残量:" + this.batteryLevel + "%");
}
// batteryLevelのgetter
public int getBatteryLevel() {
return this.batteryLevel;
}
}
ボット君: おお!extends Carって書くだけで、Carクラスの色とか速度とか、加速・停止のメソッドまで使えるようになるんですか!?すごい!バッテリーの機能はElectricCar独自のものなんですね!
先生: その通り!ElectricCarクラスは、Carクラスが持っているpublic、protected、そしてpackage-private(デフォルト)な属性やメソッドを受け継ぐんだ。ただし、privateなメンバーは継承されないよ。
先生: super(color, maker);という部分も重要だよ。これは、子クラスのコンストラクタから、親クラスのコンストラクタを呼び出すためのものなんだ。親が持つ共通の初期設定を、子も利用することで、コードの重複を防ぐことができる。
先生: 実際に使ってみると、こんな感じだよ。
Java
public class Main {
public static void main(String[] args) {
// 使用例
ElectricCar tesla = new ElectricCar("白", "Tesla", 80);
// 親クラスから継承したメソッドを使用
tesla.accelerate(50);
System.out.println("現在の速度: " + tesla.getSpeed() + "km/h");
// 子クラス独自のメソッドを使用
tesla.charge();
tesla.brake();
}
}
継承のメリット
先生: この継承という仕組みは、どんなメリットをもたらすと思う?
ボット君: えーと、共通のコードを何回も書かなくて済むから、楽!ですか?
先生: その通り!それが一番大きなメリットの一つだね。
コードの再利用性: 親クラスに共通の機能を集約することで、子クラスで同じコードを何度も書く必要がなくなる。
保守性・管理性の向上: 共通の機能にバグが見つかった場合、親クラスだけを修正すれば、それを継承している全ての子クラスに修正が反映される。
拡張性: 既存の親クラスを壊すことなく、新しい子クラスを追加して機能を拡張できる。
構造化: クラス間の関係(「AはBの一種である」という関係、これを「is-a」関係と呼ぶよ)を明確に表現でき、プログラム全体の構造が分かりやすくなる。
ボット君: なるほど!Carクラスを修正すれば、ElectricCarもGasolineCarも、全部自動で修正されるってことですね!それは便利だ!
先生: その通り!これはまさに「共通の設計図」を元に「専門化された新しい設計図」を作る、というイメージだよ。
継承使用時の注意点
先生: とても便利な継承だけど、いくつか注意点もあるよ。
Javaでは単一継承のみサポート: 一つのクラスは、直接的に一つの親クラスからしか継承できないんだ。
privateなメンバーは継承されない: 親クラスのprivateな属性やメソッドは、子クラスからは直接アクセスできない。
継承関係は「is-a」関係が成り立つ場合に使用する:
継承は、「AはBの一種である」という関係(is-a関係)が成り立つときに使うのが適切だよ。
例えば、「犬は動物の一種である(Dog is an Animal)」は正しい関係だね。
もし、「車はエンジンの一種である」のような関係で継承を使おうとすると、設計がおかしくなってしまうんだ。車はエンジンを「持っている」けれど、「エンジンの一種」ではないからね。
メソッドのオーバーライド~「親」の行動を「子」がアレンジ~
先生: 継承にはもう一つ、とても強力な機能があるんだ。例えば、普通の車と電気自動車で、加速の仕方が少し違う、なんてことがあるかもしれないね。
ボット君: ああ、エンジン音じゃなくてモーターの音がするとか!
先生: そうだね。そんな時に、子クラスが親クラスから受け継いだメソッドの中身だけを、子クラス独自の内容に「上書き(アレンジ)」することができるんだ。これを「オーバーライド(Override)」と呼ぶよ。
Java
// ElectricCarクラスに追記
public class ElectricCar extends Car {
// ... (既存のコード) ...
@Override // オーバーライドであることを示すアノテーション(注釈)
// このアノテーションにより、コンパイル時にオーバーライドの正確性がチェックされる
public void accelerate(int accelerationSpeed) {
// 親クラスのaccelerate()とは違う、電気自動車独自の加速処理
if (getBatteryLevel() > 10) { // バッテリーがあるか確認
setSpeed(getSpeed() + accelerationSpeed);
// バッテリー残量の変更は、表示と分離して行おう。
this.batteryLevel -= 5;
System.out.println("静かに加速します!現在バッテリー残量:" + this.batteryLevel + "%");
} else {
System.out.println("バッテリーが少ないため加速できません!");
}
}
}
ボット君: わー!@Overrideって書くと、同じ名前のaccelerateメソッドでも、電気自動車ならではの動きになるんですね!バッテリーの残量も減るんだ!
先生: その通り!共通の「加速する」という行動は持っているけど、その具体的な「加速の仕方」は電気自動車独自のものにできるんだ。
先生: ただし、オーバーライドする際は、メソッド名、引数の型と数は親クラスのメソッドと同じでなければならない。戻り値の型は、親クラスと同じか、そのサブタイプ(より具体的な型)でなければならないというルールがあるから注意してね。これもまた、オブジェクト指向の柔軟性を高める重要な機能だよ。
今日のまとめ!
継承(Inheritance):
既存のクラス(親クラス)の特徴(データやメソッド)を新しいクラス(子クラス)が受け継ぎ、さらに独自の機能を追加・変更する仕組み。
キーワード:extends を使って継承する。子クラスのコンストラクタからは super() で親クラスのコンストラクタを呼び出す。
メリット:
コードの再利用性:共通部分を何度も書かずに済む。
保守性・管理性の向上:親クラスの修正が子クラスに反映される。
拡張性:既存コードを壊さず機能を追加できる。
構造化:クラス間の「is-a(~の一種である)」関係を明確にする。
注意点: 単一継承、privateメンバーは継承されない、is-a関係が重要。
オーバーライド(Override):
親クラスから受け継いだメソッドの実装(中身)を、子クラスで独自に上書きすること。
@Overrideアノテーション(注釈)を付けて示すことが多い。これによりコンパイル時に正確性がチェックされる。
メソッド名、引数の型と数は親クラスと同一である必要があり、戻り値の型は親クラスと同じか、そのサブタイプでなければならない。
ボット君: 先生、今日は「継承」について、とてもよく分かりました!共通の設計図から新しい設計図を作ることで、すごく効率的にプログラムが書けるようになるんですね!オーバーライドもすごい!
先生: その調子だ、ボット君!これでオブジェクト指向の三大要素である「カプセル化」「継承」「ポリモーフィズム」のうち、二つまで理解したことになる。次回は、最後の「ポリモーフィズム」について学んでいこう。継承したクラスたちが、まるで変身ロボットのように、状況に応じて様々な姿を見せる、そんな面白い話だよ。
ボット君: 変身ロボット!ますます面白そうです!楽しみです!ありがとうございました!
次回:第6回:「色々な形」に「同じように接する」~ポリモーフィズム
いいなと思ったら応援しよう!
もしこの記事が少しでも役に立ったり、楽しんでいただけたりしたら、チップをいただけるととても嬉しいです!
いただいたチップは、今後のより良いコンテンツ制作のための書籍代📚とnote購入🗒️、他の方へのチップ代💰に使わせていただきます。
いつも応援ありがとうございます!