2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Java Silver対策】抽象クラスとインターフェース 厳選10問

2
Posted at

Java Silver試験で頻出の「抽象クラスとインターフェース」に関する問題を10問収録しました。abstractクラス、インターフェースの定義と実装、デフォルトメソッド、staticメソッド、多重実装とダイヤモンド問題など、試験で問われやすいポイントを網羅しています。


問題1 ⭐(基本)

次のコードをコンパイル・実行すると、どうなりますか?

abstract class Shape {
    abstract double area();

    void describe() {
        System.out.println("Area: " + area());
    }
}

class Circle extends Shape {
    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * radius * radius;
    }
}

public class Main {
    public static void main(String[] args) {
        Shape s = new Circle(5);
        s.describe();
    }
}
  • A. Area: 78.53981633974483
  • B. Area: 0.0
  • C. コンパイルエラー
  • D. 実行時エラー
解答と解説

正解: A

抽象クラスShapeabstractメソッドarea()と具象メソッドdescribe()を持っています。CircleShapeを継承し、area()を実装しています。

describe()area()を呼び出しますが、ポリモーフィズムにより実行時のオブジェクト型Circlearea()が呼ばれます。Math.PI * 5 * 5 = 78.53981633974483が出力されます。

抽象クラスの重要なポイント:

  • 抽象クラスはインスタンス化できない(new Shape()はコンパイルエラー)
  • 抽象メソッドと具象メソッドの両方を持てる
  • サブクラスはすべての抽象メソッドを実装しなければならない(自身もabstractでない限り)

問題2 ⭐⭐(応用)

次のコードをコンパイル・実行すると、どうなりますか?

abstract class Vehicle {
    abstract void start();

    Vehicle() {
        System.out.println("Vehicle created");
        start();
    }
}

class Car extends Vehicle {
    String engine = "V8";

    @Override
    void start() {
        System.out.println("Engine: " + engine);
    }
}

public class Main {
    public static void main(String[] args) {
        Car c = new Car();
    }
}
  • A. Vehicle createdEngine: V8
  • B. Vehicle createdEngine: null
  • C. コンパイルエラー
  • D. 実行時エラー
解答と解説

正解: B

コンストラクタの実行順序に注意が必要です:

  1. new Car()でまず親クラスVehicleのコンストラクタが実行される
  2. "Vehicle created"が出力される
  3. start()が呼ばれる → ポリモーフィズムによりCarstart()が実行される
  4. この時点でCarのフィールド初期化(engine = "V8")はまだ行われていない
  5. engineはデフォルト値nullのまま → "Engine: null"が出力される

コンストラクタからオーバーライド可能なメソッドを呼び出すと、サブクラスのフィールドがまだ初期化されていない状態でメソッドが実行される可能性があります。これは避けるべき設計パターンです。


問題3 ⭐(基本)

次のコードをコンパイル・実行すると、どうなりますか?

interface Printable {
    void print();
}

interface Loggable {
    void log();
}

class Document implements Printable, Loggable {
    @Override
    public void print() {
        System.out.println("Printing document");
    }

    @Override
    public void log() {
        System.out.println("Logging document");
    }
}

public class Main {
    public static void main(String[] args) {
        Document doc = new Document();
        doc.print();
        doc.log();
    }
}
  • A. Printing documentLogging document
  • B. コンパイルエラー(複数インターフェースの実装不可)
  • C. コンパイルエラー(メソッドの実装漏れ)
  • D. 実行時エラー
解答と解説

正解: A

Javaではクラスの多重継承はできませんが、インターフェースは複数実装できます。DocumentPrintableLoggableの両方をimplementsで実装しています。

両方のインターフェースで宣言されたメソッドprint()log()をそれぞれ実装しているため、正常にコンパイル・実行できます。

インターフェースのメソッドを実装する際は、アクセス修飾子をpublicにする必要があります(インターフェースのメソッドは暗黙的にpublic abstractであるため)。


問題4 ⭐⭐(応用)

次のコードをコンパイル・実行すると、どうなりますか?

interface Greeting {
    default void greet() {
        System.out.println("Hello!");
    }

    static void info() {
        System.out.println("Greeting interface v1.0");
    }
}

class JapaneseGreeting implements Greeting {
    @Override
    public void greet() {
        System.out.println("Konnichiwa!");
    }
}

public class Main {
    public static void main(String[] args) {
        Greeting g = new JapaneseGreeting();
        g.greet();
        Greeting.info();
    }
}
  • A. Hello!Greeting interface v1.0
  • B. Konnichiwa!Greeting interface v1.0
  • C. Konnichiwa! のみ
  • D. コンパイルエラー
解答と解説

正解: B

defaultメソッドはインターフェースに実装を持たせることができ、実装クラスでオーバーライドできます。JapaneseGreetinggreet()をオーバーライドしているため、"Konnichiwa!"が出力されます。

staticメソッドはインターフェース名で直接呼び出します(Greeting.info())。インスタンス経由(g.info())では呼び出せません。インターフェースのstaticメソッドは継承されません


問題5 ⭐⭐⭐(チャレンジ)

次のコードをコンパイル・実行すると、どうなりますか?

interface A {
    default void show() {
        System.out.println("A");
    }
}

interface B {
    default void show() {
        System.out.println("B");
    }
}

class C implements A, B {
    @Override
    public void show() {
        A.super.show();
    }
}

public class Main {
    public static void main(String[] args) {
        C c = new C();
        c.show();
    }
}
  • A. A
  • B. B
  • C. コンパイルエラー(ダイヤモンド問題)
  • D. ABの両方
解答と解説

正解: A

2つのインターフェースが同じシグネチャのdefaultメソッドを持つ場合、実装クラスは必ずそのメソッドをオーバーライドしなければなりません(オーバーライドしないとコンパイルエラー)。

クラスCshow()をオーバーライドし、A.super.show()で明示的にAインターフェースのデフォルトメソッドを呼び出しています。

インターフェース名.super.メソッド名()の構文で、どのインターフェースのデフォルトメソッドを呼ぶか指定できます。オーバーライドを省略すると、コンパイラがどちらを使うか判断できずコンパイルエラーになります。


問題6 ⭐⭐(応用)

次のコードをコンパイルすると、どうなりますか?

abstract class Animal {
    abstract void eat();
    abstract void sleep();
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dog eats");
    }
}
  • A. コンパイル成功
  • B. コンパイルエラー: Dogsleep()を実装していない
  • C. コンパイルエラー: abstractクラスにコンストラクタがない
  • D. コンパイルエラー: abstractメソッドが2つ定義されている
解答と解説

正解: B

抽象クラスを継承する具象クラス(abstractでないクラス)は、すべての抽象メソッドを実装しなければなりません。Dogeat()のみ実装していますがsleep()を実装していないため、コンパイルエラーになります。

修正方法:

  • Dogsleep()の実装を追加する
  • またはDog自体をabstract class Dog extends Animalにする(ただしインスタンス化できなくなる)

問題7 ⭐⭐(応用)

次のコードをコンパイル・実行すると、どうなりますか?

interface Flyable {
    int MAX_ALTITUDE = 10000;

    void fly();
}

class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("Flying up to " + MAX_ALTITUDE);
    }
}

public class Main {
    public static void main(String[] args) {
        Bird b = new Bird();
        b.fly();
        // Flyable.MAX_ALTITUDE = 20000; // ← この行のコメントを外すとどうなる?
    }
}
  • A. Flying up to 10000(コメント行を外すとコンパイルエラー)
  • B. Flying up to 10000(コメント行を外すと20000に変わる)
  • C. コンパイルエラー
  • D. Flying up to 0
解答と解説

正解: A

インターフェースで宣言されたフィールドは暗黙的にpublic static finalです。つまりMAX_ALTITUDEは定数であり、再代入できません。

// 実質的に以下と同じ
public static final int MAX_ALTITUDE = 10000;

コメント行を外すとFlyable.MAX_ALTITUDE = 20000final変数への再代入となりコンパイルエラーになります。

インターフェースの変数は常に:

  • public → どこからでもアクセス可能
  • static → インスタンスなしでアクセス可能
  • final → 再代入不可

問題8 ⭐⭐⭐(チャレンジ)

次のコードをコンパイル・実行すると、どうなりますか?

interface X {
    default void hello() {
        System.out.println("X");
    }
}

interface Y extends X {
    default void hello() {
        System.out.println("Y");
    }
}

class Z implements X, Y {
}

public class Main {
    public static void main(String[] args) {
        Z z = new Z();
        z.hello();
    }
}
  • A. X
  • B. Y
  • C. コンパイルエラー(ダイヤモンド問題)
  • D. 実行時エラー
解答と解説

正解: B

YXを継承し、hello()をオーバーライドしています。ZXYの両方を実装していますが、YXのサブインターフェースなので、より具体的なインターフェース(Y)のデフォルトメソッドが優先されます。

これは「ダイヤモンド問題」のように見えますが、YXextendsしているため、コンパイラはYhello()を自動的に選択します。Zでオーバーライドする必要はありません。

もしYXextendsしていない(つまり独立した2つのインターフェース)場合は、Zで明示的にオーバーライドしなければコンパイルエラーになります。


問題9 ⭐(基本)

次のコードのうち、コンパイルエラーになるものはどれですか?

// 選択肢A
abstract class A1 {
    abstract void method();
    void concreteMethod() {
        System.out.println("concrete");
    }
}

// 選択肢B
abstract class B1 {
    void method() {
        System.out.println("not abstract");
    }
}

// 選択肢C
class C1 {
    abstract void method();
}

// 選択肢D
abstract class D1 {
    abstract void method() {
        System.out.println("has body");
    }
}
  • A. 選択肢Aのみ
  • B. 選択肢Cのみ
  • C. 選択肢CとDの両方
  • D. 選択肢A, C, Dの3つ
解答と解説

正解: C

  • A: 正常 — 抽象クラスは抽象メソッドと具象メソッドの両方を持てる
  • B: 正常 — 抽象クラスに抽象メソッドがなくてもよい(インスタンス化の防止などに使える)
  • C: コンパイルエラー — abstractメソッドはabstractクラス内でのみ宣言できる。C1abstractクラスではない
  • D: コンパイルエラー — abstractメソッドは本体({}ブロック)を持てない。abstractと本体は矛盾する

問題10 ⭐⭐⭐(チャレンジ)

次のコードをコンパイル・実行すると、どうなりますか?

interface Processor {
    static void process() {
        System.out.println("Processing in interface");
    }
}

class DataProcessor implements Processor {
    static void process() {
        System.out.println("Processing in class");
    }
}

public class Main {
    public static void main(String[] args) {
        Processor.process();
        DataProcessor.process();

        Processor p = new DataProcessor();
        // p.process(); // ← この行のコメントを外すとどうなる?
    }
}
  • A. Processing in interfaceProcessing in class(コメント行はコンパイルエラー)
  • B. Processing in interfaceProcessing in class(コメント行はProcessing in class
  • C. Processing in classProcessing in class
  • D. コンパイルエラー
解答と解説

正解: A

インターフェースのstaticメソッドの重要なルール:

  1. インターフェースのstaticメソッドは継承されないDataProcessorprocess()はインターフェースのprocess()とは無関係の新しいメソッド
  2. Processor.process() → インターフェースのstaticメソッドが呼ばれる → "Processing in interface"
  3. DataProcessor.process() → クラスのstaticメソッドが呼ばれる → "Processing in class"
  4. p.process()pの型はProcessor(インターフェース)で、インターフェースのstaticメソッドはインスタンス経由で呼び出せないためコンパイルエラー

クラスのstaticメソッドはインスタンス経由で呼び出せます(推奨されませんが)が、インターフェースのstaticメソッドはインターフェース名でしか呼び出せません。


参考


@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?