4

在我的方法readList中,我想构建一个java.util.List用户定义的类型(具体的列表类型是一个参数)。我不想限制readListArrayList但是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);
    }
}

你更倾向哪个?还是有更好的解决方案?

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 回答