让我们假设以下方法(比如来自Guava的Iterables):
public static <T> Iterable<T> filter(final Iterable<?> unfiltered, final Class<T> type) {
return null;
}
和这个集合:
Set<?> objs = ...;
然后编译以下代码并正确派生泛型
Iterable<String> a2 = Iterables.filter(objs, String.class);
(在Guava中,这将返回objs
中所有字符串的可迭代。)
但现在让我们假设以下课程:
static class Abc<E> {
E someField;
}
我不知道如何致电filter
并获取Iterable<Abc<?>>
:
Iterable<Abc> a3 = Iterables.filter(objs, Abc.class);
Iterable<Abc<?>> a4 = Iterables.filter(objs, Abc.class); // Compile error - Abc and Abc<?> are incompatible types
Iterable<Abc<?>> a5 = Iterables.filter(objs, Abc<?>.class); // Compile error
Iterable<Abc<?>> a6 = Iterables.<Abc<?>>filter(objs, Abc.class); // Compile error
Iterable<Abc<?>> a7 = (Iterable<Abc<?>>) Iterables.filter(objs, Abc.class); // Compile error - inconvertible types
Iterable<Abc<?>> a8 = Iterables.filter(objs, new Abc<?>().getClass()); // Compile error
Iterable<Abc<?>> a8a = Iterables.filter(objs, new Abc<Object>().getClass()); // Compile error
只有a3编译,但是我没有Abc上的参数,因此后续代码中没有进行泛型类型检查。
我知道类型参数在运行时不存在,因此我不会尝试编写如下代码:
Iterable<Abc<String>> a9 = Iterables.filter(objs, Abc<String>.class); // Compile error
我只想过滤Abc类型的所有对象(如a3所做),但在结果中包含泛型参数。我发现这样做的唯一方法是以下,这很愚蠢:
Iterable<Abc<?>> a10 = new HashSet<Abc<?>>();
for (Abc<?> a : Iterables.filter(objs, Abc.class)) {
((Set<Abc<?>>)a10).add(a);
}
感谢。
答案 0 :(得分:6)
这个问题没有令人满意的答案。仅使用无界通配符参数化的类型的类文字在理论上可以解决,我们只是没有它们。
您可以使用未经检查的强制转换生成Class<Abc<?>>
类型的类对象,并将其移动到实用程序方法或字段。只要Abc
s很少,这就非常有效。
@SuppressWarnings("unchecked")
public static Class<Abc<?>> ABC = (Class<Abc<?>>)(Object) Abc.class;
答案 1 :(得分:0)
我发现这个编译..
public static <T> Iterable<Abc<T>> myFilter (Iterable<Abc<T>> myIterator) {
Class<Abc<T>> myClass = null;
Iterable<Abc<T>> a3 = Iterables.filter(myIterator, myClass);
return a3;
}
但它只会将同样的问题移到 myFilter()的调用者处。我怀疑Ben Schulz有正确的答案。