LoginSignup
4
0

More than 5 years have passed since last update.

ポリモーフィズムクイズ

Last updated at Posted at 2016-12-26

Java Puzzlers Advent Calendar 2016の投稿は一つだけ足りないという惜しい状況になっていますので、Day 5の記事を代打させて頂きます。

問題

class MyTest
{
    private static class A {
        String message = "hello";
        Consumer<String> hello = s -> System.out.print(message + s);
        void hello(String s) { this.hello.accept(s); }
    }

    private static class B extends A {
        String message = "ハロー";
        void hello(String s) { this.hello.accept(s); }
    }

    public static void main(String[] args) {
        A b = (A) new B();
        b.hello(" world");
        System.out.print("/");
        b.hello.accept(" world");
    }
}

上記のコードの実行結果は

  • A. ハロー world/hello world
  • B. ハロー world/ハロー world
  • C. hello world/ハロー world
  • D. hello world/hello world
  • E. コンパイルエラー

正解

答えは

  • D. hello world/hello world

説明

一見複雑そうですが、実はポリモーフィズムをちゃんと理解できれば、すぐ解けるはずです。それでは、mainメソッドの処理を追って見ましょう。

- mainメソッドの一行目ではAB実装の変数bを宣言しました。(A)というアップキャストの処理が書かれていますが、実はコンパイラが自動的に行ってくれる作業なので、ただの目障りで意味がありません(勿論エラーにもなりませんが・・)。
- bのメソッドを利用する際に、コンパイラはまず実装型にそのメソッドがあるかどうかを見ます(二行目)。クラスBhelloというメソッドがありましたね。オーバーライドが明記されていませんが、シグネチャに違いがない為、親クラスのhelloメソッドがオーバーライドされていることは分かります。ポリモーフィズムのルールによりクラスBhelloメソッドが実行されます。
- helloいうメソッドはhelloというコンシューマー関数のフィールドを呼んでいますが、残念ながらAクラスにしかhelloが存在しません。その為、やむを得ずAクラス内のhello関数を利用することになります。(ちなみに、メソッド名とフィールド名の重複は許されますので、コンパイルエラーになりません)
- helloという関数はmessageというフィールドを使います。クラスAmessagehelloですので、出力結果はhello worldになります。クラスBにもmessageというフィールドが存在しますが、今使っているhello関数とは無関係ですね。
- さらにmainの四行目ですが、bオブジェクトのhello関数を利用しているように見えますね。しかし、フィールド変数のオーバーライドが存在しないことを忘れてはいけません。hello関数はhelloメソッドと同じく処理手続きを定義するものですが、本質的にはmessageのようなフィールド変数です。その為、どのフィールドが利用されるかは宣言時の参照型によります。Aとして宣言された為、クラスAhello関数が利用され、二行目の出力結果と同じようになります。

参考

4
0
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
4
0