Javaジェネリクスでオーバーロード関数呼べるの?

オーバーロードメソッドを、型推論でコールしようとしても
型情報は消えているから、注意が必要だぞ!

自分はちょっと勘違いしていたので、共有しておきます。

テストしてみる

オーバーロードされている関数を用意

まず、テスト用のオーバロードされている関数を用意。

Object型と、Integer型を受け取る関数ですね。

private static void test(Object obj)
{
    System.out.println("DUMP Object:" + obj);
}

private static void test(Integer value)
{
    System.out.println("DUMP Integer:" + value);
}

test関数をwrapするような関数があったとして

で、ジェネリクスを利用して、ラップするようなメソッドが欲しいなぁと思って
下記のような関数を用意しました。

private static <T> void testWrap(Supplier<T> supplier)
{
    test(supplier.get());
}

型情報は消えてるよ

Integer型の関数をコールしてほしいのですが、型情報が消えているため、
Object型を受け取る関数がコールされます。

public static void main(String[] args)
{
    Integer a = 1;
    testWrap(() -> a); // test(Integer) じゃなく、test(Object) がコールされる。
}

型情報が消えるとは

上記の testWrap関数は、
コンパイルされるとTがObjectに置き換わった状態になります。

private static <T> void testWrap(Supplier<T> supplier)
{
    test(supplier.get());
}
private static void testWrap(Supplier<Object> supplier)
{
    test((Object)supplier.get());
}

コンパイル後のクラスファイルはこんな感じになっている。
これが型情報が消えるという事。

なので、いくら型パラメータを渡したとしても、
コンパイルしたクラスファイルでコールしているのは、test(Object) なのです。

コメントを残す