読者です 読者をやめる 読者になる 読者になる

Class object を渡さずに戻り値の型を指定したい

後日談あり→<T> T hoge(String a, T... b) なメソッドに引数を1つしか渡さなかった場合の挙動が ECJ, JDK で異なる - f99aq8oveのブログ

# http://f99aq.hateblo.jp/ はてなブログを使い始めてみたのですが、super pre 記法でのシンタックス・ハイライトがうまく行かなかったので、こちらに書きます。

本題ですが、Java で「Class object を渡さずに戻り値の型を指定したい」のです。
文章でうまく表現できないので、とりあえず以下を見てください。

package net.f99aq8ove.junk;

import java.util.HashMap;
import java.util.Map;

public class HogeContainer {
    private final Map<String, Object> container = new HashMap<String, Object>();

    public void put(String key, Object obj) {
        container.put(key, obj);
    }

    public <E> E get1(String key, Class<E> klass) {
        Object obj = container.get(key);
        if (klass.isInstance(obj)) {
            return klass.cast(obj);
        } else {
            return null;
        }
    }

    public <E> E get2(String key, E... dummy) {
        @SuppressWarnings("unchecked")
        Class<E> klass = (Class<E>) dummy.getClass().getComponentType();

        Object obj = container.get(key);
        if (klass.isInstance(obj)) {
            return klass.cast(obj);
        } else {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public <E> E get3(String key) {
        return get2(key);
    }

    private <E> Class<E> getType(E... dummy) {
        return (Class<E>) dummy.getClass().getComponentType();
    }

    public <E> E get4(String key) {
        Class<E> klass = getType();

        Object obj = container.get(key);
        if (klass.isInstance(obj)) {
            return klass.cast(obj);
        } else {
            return null;
        }
    }

    public static void main(String[] args) {
        HogeContainer hoge = new HogeContainer();
        hoge.put("string", "hoge");
        hoge.put("integer", 1);

        String str1 = hoge.get1("string", String.class);
        String str2 = hoge.get2("string");
        String str3 = hoge.get3("string");
        String str4 = hoge.get4("string");
        System.out.printf("%s, %s, %s, %s\n", str1, str2, str3, str4);
        // hoge, hoge, hoge, hoge

        Integer int1 = hoge.get1("integer", Integer.class);
        Integer int2 = hoge.get2("integer");
        Integer int3 = hoge.get3("integer");
        Integer int4 = hoge.get4("integer");
        System.out.printf("%d, %d, %d, %d\n", int1, int2, int3, int4);
        // 1, 1, 1, 1

        Long long1 = hoge.get1("string", Long.class);
        Long long2 = hoge.get2("string");
        Long long3 = null; // hoge.get3("string"); // <- ClassCastException
        Long long4 = null; // hoge.get4("string"); // <- ClassCastException
        System.out.printf("%d, %d, %d, %d\n", long1, long2, long3, long4);
        // null, null, null, null
    }
}

制約事項として、JDK 5 を使うものとします。また、Key 毎に値の型は一意に決まるものとし、型は同一だが key が異なるものも存在することとします。

突っ込みどころはあると思いますが、現在 get1 のようなコードがあります。
これをどうにかして class object を渡さなくても良いようにしたいというモチベーションです。


Java変態文法最速マスター - プログラマーの脳みそ を参考にした結果、get2, get3, get4 が出来ました。

get2 は動きます。しかし、dummy が目障りです。

get3, get4 は、E の型情報が失われてしまっており、メソッドの戻り値を代入する時に ClassCastException が発生します。(メソッド中の klass は Object.class になっています。)

get2 から dummy を取り去る方法は無いものでしょうか。
Java は難しいです。