0

假设我有以下方法,它可以用来创建一个指定给定类型的集合。

private static Collection<?> void create(Class<? extends Collection<?>> cls) {
    return cls.newInstance();
}

如果在运行时传入 cls 参数,这一切都很好:

List<String> list = new LinkedList<String>();
create(list.getClass());

但是如何在没有未经检查的警告的情况下在代码中调用此方法?说我想做类似的事情:

create(LinkedList.class);

它会抱怨 create(Class) 没有定义,严格来说这是正确的,因为 List 不是 Collection 的#capture,但是我该如何让它工作呢?

非常感谢!

4

2 回答 2

3

Neal Gafter在这里几乎完全谈到了这个问题。解决方法是使用超类型标记。我相信这就是 Guice 用来维护泛型类型信息的方法。

基本上它是一个额外的类,你可以用它来表示一个类型而不是使用Foo.class. 你会这样使用它:

TypeReference<LinkedList<String>> x = new TypeReference<LinkedList<String>>() {};
create(x);

请注意,您尝试使用原始类型LinkedList仍会导致编译器抱怨,并且故意如此 - 当您使用原始类型时,您基本上选择退出类型安全。但是这种方案允许您以一种更难的方式表达泛型类型。

于 2010-09-21T05:52:56.047 回答
0

我们这里有两种泛型类型,一种用于集合的子类型,一种用于集合的元素类型。以下代码可以工作:

private static <C extends Collection<E>, E>
C create(Class<C> cls) throws Exception
{
    return cls.newInstance();
}

用法示例。没有警告。

    Class<LinkedList<String>> clazz = ...;
    LinkedList<String> result = create(clazz);

现在的问题变成了我们如何获得clazz?您必须非常努力地说服编译器:

    List<String> list = new LinkedList<String>();
    clazz = (Class<LinkedList<String>>)list.getClass();

    clazz = (Class<LinkedList<String>>)(Class<?>)LinkedList.class;

我们可以有一个实用方法来简化类型转换:

public static <C extends Collection, E, T extends Collection<E>>
Class<T> type(Class<C> classC, Class<E> classE)
{
    return (Class<T>)classC;
}

//usage:
    clazz = type(LinkedList.class, String.class);
    result = create(clazz);

乐趣是递归的:

    Class<LinkedList<LinkedList<String>>> clazz2;
    LinkedList<LinkedList<String>> result2;

    clazz2 = type(LinkedList.class, clazz);
    result2 = create(clazz2);

但在某个时候,我们必须停止这种愚蠢的游戏。泛型类型应该帮助我们,而不是折磨我们。当它变得太麻烦并且使我们的程序无法阅读时,就放弃它。使用我们多年来快乐生活的该死的原始类型。

于 2010-09-21T17:17:58.043 回答