在我的方法readList
中,我想构建一个用户定义类型的java.util.List
(具体的列表类型是一个参数)。但是,我不想将readList
限制为ArrayList
或LinkedList
;用户可以提供自己的java.util.List
实现。如果可能,该方法还可能缓存列表,因此该方法需要返回列表。我尝试了几件事。您认为以下哪一项是“最佳” API,或者还有另一种甚至更好的API?
可以进行以下编译,但是我得到编译器警告:“类型安全:ArrayList类型的表达式需要未经检查的转换才能符合ArrayList”,因此它并不是一个很好的解决方案:
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);
}
}
“超级 token 类型”也可以,但是可能有点难以理解
对于不熟悉此模式的开发人员,以及在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);
}
}
你更倾向哪个?还是有更好的解决方案?
最佳答案
我可能会委托另一个构建器类。一个只知道如何创建新列表的小类。它提供了更好的运行时安全性,因为它不依赖于给定类具有默认构造函数的假设。列表可能没有那么有用,因为我们应该总是能够创建一个空列表,但对于其他类型的类则更为重要。
例如。
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;
}
您可能无法准确知道自己拥有的列表类型,但这是一个问题,然后听起来您正在尝试做一些奇怪的事情。