モジュールのレッスン (2/2)
ポリモーフィズムと抽象クラス
ポリモーフィズムと抽象クラスは、特定の実装に依存せずに柔軟で拡張可能なコードを作成できるようにする高度なオブジェクト指向プログラミング概念です。
ポリモーフィズム
ポリモーフィズム (さまざまな形式) という用語は、異なるクラスのオブジェクトを、あたかも共通の型に属しているかのように扱う機能を指します。 Java では、スーパークラス参照変数は、そのサブクラスのオブジェクトへの参照を格納できます。
class Animal {
public void makeSound() {
System.out.println("Verso...");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Woof");
}
}
class Cat extends Animal {
public void makeSound() {
System.out.println("Miao");
}
}ポリモーフィズムのおかげで、次のことが可能になります。
Animal myAnimal1 = new Dog(); // Polymorphism
Animal myAnimal2 = new Cat(); // Polymorphism
myAnimal1.makeSound(); // Executes Dog's method (Woof)
myAnimal2.makeSound(); // Executes Cat's method (Miao)どのメソッドを呼び出すかは、参照変数の型ではなく、実際のオブジェクトに基づいて実行時に決定されます (遅延バインディングまたは動的ディスパッチ)。
抽象クラス (abstract)
抽象クラス は、abstract キーワードでマークされたクラスであり、直接インスタンス化することはできません (new MyAbstractClass() は実行できません)。これは、他のクラスの「部分テンプレート」として機能します。
抽象メソッド
抽象クラスには、抽象メソッド を含めることができます。つまり、本体なし (中括弧やコードなし) で宣言され、セミコロンで終わるメソッドです。継承されたすべての抽象メソッドを実装するには、非抽象サブクラスが必要です。
abstract class Shape {
String color;
// Abstract method (no body)
public abstract double getArea();
}
class Circle extends Shape {
double radius;
public Circle(double radius) {
this.radius = radius;
}
// Required to implement getArea
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}動的バインディング/レイトバインディング
Java は実行時にどのメソッドを実行するかをどのようにして知るのでしょうか?このプロセスは、遅延バインディング (または動的バインディング) として知られています。オーバーロード (コンパイル時に解決される) とは異なり、コンパイラーはどの特定のメソッドが実行されるかを知りません。代わりに、汎用呼び出し命令を生成します。実行時に、Java 仮想マシン (JVM) はメモリ内の実際のオブジェクトを検査し、そのオブジェクトのクラスで定義されたメソッド実装を呼び出します。
抽象クラスと実装の欠落
サブクラスが抽象クラスから継承する場合、次の 2 つのオプションがあります。
- すべての抽象メソッドを実装します: この場合、サブクラスは通常の (具体的な) クラスにすることができ、インスタンス化できます。
- それ自体を抽象宣言します: サブクラスが継承されたすべての抽象メソッドの実装を提供していない場合は、
abstractキーワードを使用して宣言する必要もあります。
abstract class Animal {
public abstract void makeSound();
}
// This class MUST be abstract because it does not implement makeSound()
abstract class Canine extends Animal {
// Inherits makeSound() but does not implement it
}自分で試してみてください
Shape 型の変数 s を宣言し、ポリモーフィズムを使用して新しい Circle オブジェクトをそれに割り当てます。
ヒントを表示
基本型を参照型として使用するには、「Shape s = new Circle();」と記述します。
3 回の試行後に解決策が利用可能になります
Shape クラスを抽象化し、抽象メソッド double getArea() を追加します。次に、Square を完成させて、Shape を拡張し、side * Side を返す getArea() を実装します。
ヒントを表示
Shape で「public abstract double getArea();」を宣言します。 Square で、「@Override public double getArea() { return side * side;」を追加します。 }`。
3 回の試行後に解決策が利用可能になります
main メソッドで、半径 2.0 の Circle オブジェクトと辺 3.0 の Square オブジェクトを含む Shape[] 型の配列を宣言します。次に、ループ (for または for-each) を使用して、getArea() メソッドを呼び出して各図形の領域を出力します。
ヒントを表示
`Shape[]シェイプ = { new Circle(2.0), new Square(3.0) };`で配列を宣言し、`s.getArea()`を出力する`for (Shape s :shapes)`を使用してループします。
3 回の試行後に解決策が利用可能になります