この記事で学べる知識:クラスの継承
この記事の練習問題で使用する知識:
基礎構文、制御構造、メソッド、コレクション(レッスン1~4)、クラスの定義と使用、コンストラクタ、カプセル化、クラスメンバとインスタンスメンバ、クラスの継承、メソッドのオーバーライド、抽象クラス、インターフェース
<<前のページ | JAVA Topへ |
次のページ>> |
JAVAの文法「クラスの継承」とは
ここではクラスの継承の意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。
クラスの継承は、既存のクラス(親クラスやスーパークラスとも呼ばれます)の機能を引き継ぎ、新しいクラス(子クラス)を作成する際に使用する重要な仕組みです。
これにより重複したコードを減らし、再利用性や保守性の向上が期待できます。
Javaにおいてはこの継承の仕組みを正しく理解することが、効率的でスッキリとしたコードを書くための鍵となります。
クラスの継承とは?
継承とはあるクラスのプロパティ(フィールド)やメソッドを別のクラスに引き継がせる機能です。
例えばAnimal
という動物クラスがあったとすると、そのクラスを継承してDog
やCat
といった具体的な動物クラスを作成できます。
これにより共通する特徴や動作を「親クラス」に集約し、特定の動作や属性を「子クラス」で追加する形で、コードが整理されます。
継承の基本構文と使い方
Javaでクラスを継承する際には、extends
キーワードを使用します。
以下が継承の基本構文です。
class 親クラス { // 親クラスのメソッドやフィールド } class 子クラス extends 親クラス { // 子クラスの独自メソッドやフィールド }
上記のように子クラスは「extends 親クラス名
」と記述することで、親クラスのフィールドやメソッドを引き継ぐことができます。
また親クラスの機能をそのまま利用できるほか、子クラスで特別な機能を追加することも可能です。
例えばAnimal
というクラスからDog
クラスを継承する例を考えてみましょう。
class Animal { //親クラス void eat() { System.out.println("食べています"); } } class Dog extends Animal { //Animalクラスを継承したDogクラス void bark() { System.out.println("ワンワン!"); } } public class Main { public static void main(String[] args) { Dog dog = new Dog(); //Dog型の変数dogに、生成したインスタンスを代入 dog.eat(); // 親クラスのメソッド dog.bark(); // 子クラスのメソッド } }
このコードではDog
クラスがAnimal
クラスを継承しているため、Dog
クラスはAnimal
クラスのeat
メソッドを使えるようになっています。
継承を使うメリット
継承を使用する主なメリットは以下の通りです。
- コードの再利用:一度定義したクラスの機能を複数のクラスで再利用できます。
- 保守性の向上:親クラスでメソッドを修正すれば、すべての子クラスに変更が反映されるため、保守が容易になります。
- クラスの階層化:共通の機能を親クラスにまとめ、異なる機能を子クラスに持たせることで、論理的なクラス構造が生まれます。
継承の使用例
以下の例ではPerson
クラスを親クラスとし、Teacher
クラスとStudent
クラスを子クラスとして継承しています。
class Person { 親クラス //親クラスのフィールド String name; int age; //親クラスのコンストラクタ Person(String name, int age) { this.name = name; this.age = age; } //親クラスのメソッド void introduce() { System.out.println("名前: " + name + ", 年齢: " + age); } } class Teacher extends Person { //Personクラスを継承したTeacherクラス //Teacherクラスのフィールド String subject; //Techerクラスのコンストラクタ Teacher(String name, int age, String subject) { super(name, age); // 親クラスのコンストラクタを呼び出す this.subject = subject; } //Teacherクラスのメソッド void teach() { System.out.println(subject + "を教えています。"); } } class Student extends Person { //Personクラスを継承したStudentクラス //Studentクラスのフィールド int studentId; //Studentクラスのコンストラクタ Student(String name, int age, int studentId) { super(name, age); this.studentId = studentId; } //Studentクラスのメソッド void study() { System.out.println("勉強しています。"); } } public class Main { //メインクラス public static void main(String[] args) { //メインメソッド Teacher teacher = new Teacher("田中", 30, "数学"); //インスタンス生成 Student student = new Student("佐藤", 18, 12345); //インスタンス生成 teacher.introduce(); // 親クラスのメソッド teacher.teach(); // 子クラスのメソッド student.introduce(); // 親クラスのメソッド student.study(); // 子クラスのメソッド } }
この例ではPerson
クラスがTeacher
クラスとStudent
クラスに継承されています。
Teacher
クラスとStudent
クラスは、Person
クラスのintroduce
メソッドを使いつつ、それぞれteach
やstudy
といった独自のメソッドを持っています。
このように継承を用いることで、共通の属性と処理を親クラスにまとめ、各クラスごとの固有の処理を追加することができます。
まとめ
クラスの継承はコードの再利用と保守性を高めるための強力な機能です。
Javaではextends
キーワードを用いて既存のクラスを基に新しいクラスを作成し、共通の機能を継承することができます。
継承を適切に活用することでコードの構造をシンプルにし、複雑なシステムの設計がしやすくなります。
今回の解説を参考に、実際に継承を使ったプログラムを作成してみましょう。
JAVA練習問題5-5_車クラスを作り、動作をシミュレーションしよう
親クラス「Vehicle」を作成し、名前を持たせ、動くための基本的なメソッドを定義します。
次に「Car」という子クラスを作成し、親クラス「Vehicle」を継承して、独自の行動を追加します。
このプログラムでは、「Vehicle」の動作と「Car」特有の動作を確認します。
この問題の要件
以下の要件に従ってプログラムを作成して下さい。
- 親クラス「Vehicle」を作成し、以下の要素を含むこと:
- 変数
name
:乗り物の名前を格納するための変数。 - コンストラクタ:引数として名前を受け取り、
name
変数に設定する。 - メソッド
move()
:乗り物が動いていることを表すメッセージを出力する。
- 変数
- 子クラス「Car」を作成し、以下の要素を含むこと:
- 親クラス「Vehicle」を継承すること。
- コンストラクタ:引数として車の名前を受け取り、親クラスのコンストラクタを呼び出す。
- メソッド
honk()
:クラクションを鳴らすメッセージを出力する。
- メインクラスで以下の操作を行うこと:
- 車の名前を「プリウス」として「Car」オブジェクトを生成する。
move()
メソッドを使用して、車が動いていることを確認する。honk()
メソッドを使用して、車がクラクションを鳴らす動作を確認する。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
プリウスが動いています。 プリウスがクラクションを鳴らしています。
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
正解のコードは上から順に以下のような構成となっています。
1:Vehicleクラスの定義
□ String型のname変数を宣言
□ コンストラクタVehicleを定義し、引数nameで初期化
□ moveメソッドを定義し、”{name}が動いています。”と出力
2:Carクラスの定義
□ コンストラクタCarを定義し、superで親クラスのコンストラクタを呼び出す
□ honkメソッドを定義し、”{name}がクラクションを鳴らしています。”と出力
3:Mainクラスの定義
□ mainメソッドの定義
□ □ Carクラスのインスタンスcarを作成し、”プリウス”を引数として設定
□ □ moveメソッドを呼び出し、”{name}が動いています。”と出力
□ □ honkメソッドを呼び出し、”{name}がクラクションを鳴らしています。”と出力
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
// 乗り物クラス(親クラス)を定義します。 class Vehicle { // 乗り物の名前を格納する変数 String name; // コンストラクタで乗り物の名前を設定します /*【穴埋め問題1】 ここにVehicleクラスのコンストラクタを定義してください。 コンストラクタでは引数nameを初期化します。 */ // 乗り物が動くメソッド(親クラスで定義される基本的な動作) void move() { System.out.println(name + "が動いています。"); } } // 車クラス(子クラス)を定義します。Vehicleクラスを継承します。 class Car extends Vehicle { /*【穴埋め問題2】 ここにCarクラスのコンストラクタを定義してください。 コンストラクタで親クラスのコンストラクタを呼び出し、名前を設定します。 */ // 車専用の行動(クラクションを鳴らす)を定義します void honk() { System.out.println(name + "がクラクションを鳴らしています。"); } } // 実行用クラス public class Main { public static void main(String[] args) { // 車オブジェクトを生成し、名前を「プリウス」に設定します /*【穴埋め問題3】 ここにCarクラスのオブジェクトを作成し、変数carに代入するコードを書いてください。 */ // 親クラスで定義されたメソッドを呼び出します car.move(); // 子クラスで定義されたメソッドを呼び出します car.honk(); } }
この問題の穴埋めコードは以上です。
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
解答例と解説
この問題の一つの正解例とそのコードの解説を以下に示します。
正解コードの例
例えば以下のようなプログラムが考えられます。
// 乗り物クラス(親クラス)を定義します。 class Vehicle { // 乗り物の名前を格納する変数 String name; // コンストラクタで乗り物の名前を設定します Vehicle(String name) { this.name = name; } // 乗り物が動くメソッド(親クラスで定義される基本的な動作) void move() { System.out.println(name + "が動いています。"); } } // 車クラス(子クラス)を定義します。Vehicleクラスを継承します。 class Car extends Vehicle { // コンストラクタで車の名前を設定します(親クラスのコンストラクタを呼び出します) Car(String name) { super(name); } // 車専用の行動(クラクションを鳴らす)を定義します void honk() { System.out.println(name + "がクラクションを鳴らしています。"); } } // 実行用クラス public class Main { public static void main(String[] args) { // 車オブジェクトを生成し、名前を「プリウス」に設定します Car car = new Car("プリウス"); // 親クラスで定義されたメソッドを呼び出します car.move(); // 子クラスで定義されたメソッドを呼び出します car.honk(); } }
正解コードの解説
このコードではJAVAの「クラスの継承」を使って親クラスと子クラスの関係を表現しています。
コードの各ブロックで使用されている文法と、どのような動作を実現しているのかを解説していきます。
親クラスの定義
class Vehicle { String name; Vehicle(String name) { this.name = name; } void move() { System.out.println(name + "が動いています。"); } }
- クラス定義:
Vehicle
クラスは親クラスとして定義されています。このクラスはすべての「乗り物」を表現する基本的な特徴を持ちます。 - 変数の定義:
String name;
で乗り物の名前を格納する変数name
を定義しています。この変数はクラス内のどこでも使用できるようにクラス全体でアクセス可能です。 - コンストラクタ:
Vehicle(String name)
は、Vehicle
オブジェクトが生成される際に、名前を初期設定するために使われます。このコンストラクタは、オブジェクトのname
変数に引数で渡された名前を代入します。 - メソッドの定義:
void move()
は、Vehicle
クラスの基本的な動作である「動く」機能を表しています。このメソッドを呼び出すと、設定されたname
に基づいて「○○が動いています。」と表示されます。
子クラスの定義と継承
class Car extends Vehicle { Car(String name) { super(name); } void honk() { System.out.println(name + "がクラクションを鳴らしています。"); } }
- 継承の仕組み:
class Car extends Vehicle
と記述することで、Car
クラスはVehicle
クラスを継承します。これにより、Vehicle
クラスの機能(変数name
とメソッドmove()
)がCar
クラスにも引き継がれます。継承は、共通の動作を持つクラス間でコードを再利用するために使われます。 - superキーワード:
Car(String name)
の中でsuper(name);
としています。super
は親クラスのコンストラクタを呼び出すためのキーワードです。これにより、Car
オブジェクトが生成されるとVehicle
のコンストラクタが実行され、name
が設定されます。 - 子クラスのメソッド:
void honk()
は、車専用の動作として「クラクションを鳴らす」機能を追加しています。honk()
メソッドを呼ぶと「○○がクラクションを鳴らしています。」と出力されます。これにより、親クラスVehicle
にはない独自の機能が子クラスCar
で実現されました。
メインクラスでの実行
public class Main { public static void main(String[] args) { Car car = new Car("プリウス"); car.move(); car.honk(); } }
- オブジェクトの生成:
Car car = new Car("プリウス");
では、Car
クラスのオブジェクトを生成し、car
という変数に代入しています。このとき、Car
のコンストラクタに「プリウス」という名前を渡すことで、name
が「プリウス」に設定されます。 - 親クラスのメソッド呼び出し:
car.move();
でVehicle
クラスで定義されたmove()
メソッドが呼び出され、「プリウスが動いています。」と表示されます。このように、継承によりCar
オブジェクトは親クラスVehicle
のメソッドを利用できます。 - 子クラスのメソッド呼び出し:
car.honk();
でCar
クラス特有のhonk()
メソッドを呼び出し、「プリウスがクラクションを鳴らしています。」と表示されます。子クラスは、親クラスのメソッドに加え、独自の機能も持たせることができるのです。
<<前のページ |
JAVA Topへ |
次のページ>> |
この記事への質問・コメント
この問題を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。