4

method 内で、ユーザー定義型のreadListを作成したいと思いjava.util.Listます (具体的なリスト型はパラメーターです)。ただし、またはに制限readListしたくありません。ユーザーは独自の実装を提供する場合があります。メソッドは、可能であればリストをキャッシュすることもあるため、メソッドはリストを返す必要があります。私はいくつかのことを試しました。次のうち、あなたが考える「最高の」API はどれですか。それとも、さらに優れた別の API はありますか?ArrayListLinkedListjava.util.List

次のコードはコンパイルされますが、コンパイラの警告が表示されます。

void classParameter() {
    ArrayList<String> a = readList(ArrayList.class);
    LinkedList<String> b = readList(LinkedList.class);
}

<X, T extends List<X>> T readList(Class<T> clazz) {
    try {
        return clazz.newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

次のコードはコンパイルされますが、それでもコンパイラの警告が表示され、実際には期待どおりに動作しません。

void classTypeParameters() {
    ArrayList<String> a = readList(ArrayList.class, String.class);
    LinkedList<String> b = readList(LinkedList.class, Integer.class);
}

<T extends List<X>, X> T readList(Class<T> clazz, Class<X> type) {
    try {
        return clazz.newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

次の作品は私の個人的なお気に入りです。リストの種類をチェックします。少し危険なのは、誰かが誤って結果を割り当てるのを忘れる可能性があることです。readListこれは、名前を変更することで解決できますreadListWithTemplate。戻り値が使用されることがより明確になります。それは似ていList.toArray(T[] a)ます:

void template() {
    ArrayList<String> a = readList(new ArrayList<String>());
    LinkedList<String> b = readList(new LinkedList<String>());
    // wrong usage:
    List<String> c = new LinkedList<String>();
    readList(c);
}

@SuppressWarnings("unchecked")
<X, T extends List<X>> T readList(T template) {
    try {
        return (T) template.getClass().newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

「スーパー トークン タイプ」も同様に機能しますが、このパターンに慣れていない開発者にとっては理解しにくいかもしれません。また、Eclipse では「空のブロックをドキュメント化する必要があります」という警告が表示されますが、これは避けたいと思います。

void superTypeToken() {
    ArrayList<String> a = readList(new ListType<ArrayList<String>>() {});
    LinkedList<String> b = readList(new ListType<LinkedList<String>>() {});
}

abstract static class ListType<X extends List<?>> {
    // super type token class
}

@SuppressWarnings("unchecked")
<X, T extends List<X>> T readList(ListType<T> t) {
    try {
        Type type = t.getClass().getGenericSuperclass();
        if (!(type instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Missing type parameters");
        }
        ParameterizedType pt = (ParameterizedType) type;
        type = pt.getActualTypeArguments()[0];
        pt = (ParameterizedType) type;
        Class<?> listClass = (Class<?>) pt.getRawType();
        return (T) listClass.newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

あなたはどちらを好みますか?または、より良い解決策はありますか?

4

1 に答える 1

4

私はおそらく別のビルダークラスに委任するでしょう。新しいリストを作成する方法を知っている小さなクラス。指定されたクラスにデフォルトのコンストラクターがあるという仮定に依存しないため、実行時の安全性が向上します。常に空のリストを作成できるはずなので、リストではあまり役に立たないかもしれませんが、他のタイプのクラスではより重要です。

例えば。

public interface EmptyListBuilder {

    public <E> List<E> newList();

    public static final EmptyListBuilder ARRAY_LIST_BUILDER = 
            new EmptyListBuilder() {

        public <E> List<E> newList() {
            return new ArrayList<E>();
        }
    };
}

静的フィールドで示されているように、いくつかの標準クラスのデフォルトの実装を提供することもできます。

次のようなクラスを使用します。

<T> List<T> readList(EmptyListBuilder builder) {
    List<T> list = builder.newList();
    // read in elements
    return list;
}

自分が持っているリストの種類を正確に知ることができなくなりますが、それが問題であるため、少し奇妙なことをしようとしているように聞こえます。

于 2012-12-17T15:30:52.490 に答える