在我的方法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);
}
}
“超级令牌类型”也可以,但对于不熟悉这种模式的开发人员来说可能有点难以理解,并且在 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);
}
}
你更倾向哪个?还是有更好的解决方案?