Javaの抽象クラスを実践!動物クラスを作って学ぶオブジェクト指向
生徒
「Javaの抽象クラスって実際にどうやって使えばいいんですか?」
先生
「それなら、動物クラスを例にして、Javaの抽象クラスを実践的に学んでみましょうか。」
生徒
「動物クラスですか?具体的にどんなことができるんですか?」
先生
「共通の動作を抽象クラスで定義して、犬や猫など具体的な動物はサブクラスとして作るんです。コードもシンプルで、ポリモーフィズムも自然に使えるようになりますよ。」
1. Javaの抽象クラスとは?基本の考え方
Javaの抽象クラスは、共通する性質や動作をまとめるためのクラスで、abstractキーワードを使って定義します。抽象クラスには抽象メソッド(定義だけで中身のないメソッド)を含めることができ、具体的な処理はサブクラスで実装します。
たとえば、動物ならすべての動物が「鳴く」機能を持っているけど、その鳴き方は犬と猫で異なります。これを抽象クラスと具象クラスで表現することができます。
2. 動物クラスの設計と抽象クラスの定義
まずは「Animal(動物)」という抽象クラスを作成して、その中に共通のプロパティやメソッドを定義します。ここではnameという名前と、makeSound()という抽象メソッドを用意しましょう。
abstract class Animal {
String name;
Animal(String name) {
this.name = name;
}
abstract void makeSound();
void sleep() {
System.out.println(name + " is sleeping...");
}
}
このAnimalクラスでは、すべての動物がsleepするという共通の動作を持ち、鳴き方はサブクラスに任せるようにしています。
3. DogクラスとCatクラスを実装しよう
次に、Animalクラスを継承して、具体的な動物クラスを作成します。DogクラスとCatクラスを例に見てみましょう。
class Dog extends Animal {
Dog(String name) {
super(name);
}
@Override
void makeSound() {
System.out.println(name + " says: ワンワン!");
}
}
class Cat extends Animal {
Cat(String name) {
super(name);
}
@Override
void makeSound() {
System.out.println(name + " says: ニャーニャー!");
}
}
このように、継承を使って共通部分を引き継ぎつつ、個別の動作をそれぞれ定義できます。
4. 抽象クラスを使った実践コード
ここまで定義したクラスを使って、実際にJavaのメインメソッドでインスタンスを生成して動作を確認してみましょう。
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog("ポチ");
Animal myCat = new Cat("ミケ");
myDog.makeSound();
myCat.makeSound();
myDog.sleep();
myCat.sleep();
}
}
ポチ says: ワンワン!
ミケ says: ニャーニャー!
ポチ is sleeping...
ミケ is sleeping...
Javaの抽象クラスとポリモーフィズムを使うことで、コードの再利用性が高まり、保守性の高い設計が可能になります。
5. ポリモーフィズムを活用してコードをシンプルに
抽象クラスを通じて、ポリモーフィズム(多態性)を自然に利用することができます。同じAnimal型として扱うことで、配列やリストを使って複数の異なるオブジェクトをまとめて扱えるようになります。
public class Main {
public static void main(String[] args) {
Animal[] animals = {
new Dog("ポチ"),
new Cat("タマ"),
new Dog("シロ")
};
for (Animal animal : animals) {
animal.makeSound();
animal.sleep();
}
}
}
ポチ says: ワンワン!
ポチ is sleeping...
タマ says: ニャーニャー!
タマ is sleeping...
シロ says: ワンワン!
シロ is sleeping...
このように、動物の種類にかかわらず同じ型で処理ができるため、コードが非常にシンプルで管理しやすくなります。
6. 抽象クラスに引数を渡してみよう
さらに実践的に、動物の種類や鳴き声のパターンを外部から渡せるようにすることで、より柔軟な設計が可能になります。以下は改良例です。
abstract class Animal {
String name;
String sound;
Animal(String name, String sound) {
this.name = name;
this.sound = sound;
}
abstract void makeSound();
void sleep() {
System.out.println(name + " is sleeping...");
}
}
class Dog extends Animal {
Dog(String name) {
super(name, "ワンワン!");
}
@Override
void makeSound() {
System.out.println(name + " says: " + sound);
}
}
このように、フィールドに柔軟性を持たせることで、将来的にクラスの拡張がしやすくなります。
7. Javaの抽象クラスを使うときの注意点
- 抽象クラスは直接インスタンス化できません
- 抽象クラス内で抽象メソッドを1つでも定義した場合、必ずクラス自体を
abstractにする必要があります - サブクラスは、抽象メソッドをすべてオーバーライド(上書き)する義務があります
これらのルールを守ることで、Javaの抽象クラスはより安全で一貫性のある設計に役立ちます。