このJavaのコードは、ポリモーフィズムと継承の概念を使っています。ポリモーフィズムとは、サブクラスのオブジェクトがスーパークラスの型で参照されることができる、というオブジェクト指向プログラミングの特徴です。以下のコードにコメントアウトを加えることで、それぞれのステートメントが何を意味するのかを説明します。
// Workerインターフェース定義。workメソッドが必要。
public interface Worker {
void work();
}
// EmployeeクラスはWorkerインターフェースを実装する。workとreportメソッドを持つ。
class Employee implements Worker {
public void work() {
System.out.println("work");
}
public void report() {
System.out.println("report");
}
}
// EngineerクラスはEmployeeクラスを継承する。createメソッドを新たに追加。
class Engineer extends Employee {
public void create() {
System.out.println("create future");
}
}
// メインクラスとメインメソッド。
public class Main {
public static void main(String[] args) {
Worker a = new Engineer(); // EngineerオブジェクトをWorker型でインスタンス化。
Employee b = new Engineer(); // EngineerオブジェクトをEmployee型でインスタンス化。
Engineer c = new Engineer(); // EngineerオブジェクトをEngineer型でインスタンス化。
a.create(); // コンパイルエラー。Worker型の参照変数はcreateメソッドを知らない。
b.work(); // 正常に動作。Employeeはworkメソッドを継承している。
c.report(); // 正常に動作。EngineerはEmployeeからreportメソッドを継承している。
}
}
解答 A「Mainクラスの6行目でコンパイルエラーが発生する」が正しい理由は、変数 a
が Worker
インターフェースの型で宣言されており、Worker
インターフェースには create()
メソッドが定義されていないためです。Javaでは、参照変数の型が持っているメソッドのみを呼び出せます。したがって、Worker
型の a
で create()
メソッドを呼び出そうとすると、コンパイラはそのメソッドを Worker
インターフェース内で見つけられず、エラーを出します。
Bは正しくない理由は、b.work();
は Employee
クラスの work()
メソッドを正しく呼び出すため、エラーにはなりません。Cは正しくない理由は、b
は Employee
型であり、create()
メソッドは Engineer
クラスにしか存在しないため、Employee
型の b
では create()
メソッドを呼び出すことができません。Eは report()
メソッドが Employee
クラスに存在し、Engineer
クラスがこれを継承しているため正しく実行できます。
追記
もし Worker
インターフェースに create()
メソッドが定義されていれば、a.create()
を呼び出す際にコンパイルエラーは発生しません。以下のように Worker
インターフェースを変更して create()
メソッドを定義することができます:
public interface Worker {
void work();
void create(); // createメソッドをインターフェースに追加
}
この変更を加えた後、Engineer
クラスは Worker
インターフェースから create()
メソッドも実装しなければなりません。ただし、既に Engineer
クラスには create()
メソッドの実装があるので、これ以上の変更は不要です。その結果、Worker
型の参照変数である a
でも create()
メソッドを呼び出せるようになり、エラーは解消されます。