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