敬请谅解,敬请谅解。
假设我有一个方法可以根据List<T>
过滤任意类型的class
,并返回一个新的List
,其元素是输入列表中属于给定类实例的元素。这是一个简单的实现(是的,您也可以在带有流的1-liner中执行此操作):
public static <T> List<T> filterByClass(List<?> list, Class<T> clazz) {
List<T> filtered = new ArrayList<>();
for (Object o : list) {
if (clazz.isInstance(o)) {
filtered.add(clazz.cast(o));
}
}
return filtered;
}
如果您向其传递非普通类型的列表(例如
String
),则效果很好(如(打印foo bar
):List<Object> l = Arrays.<Object>asList(1, "foo ", 2, "bar ");
filterByClass(l, String.class).stream().forEach(System.out::println);
现在,我想传递对通用类型的类进行过滤,例如
Optional<T>
:List<Object> l = Arrays.<Object>asList(1, Optional.of("foo"), 2, Optional.of("bar"));
filterByClass(l, Optional.class).stream().forEach(System.out::println);
可以正常工作并打印:
Optional[foo]
Optional[bar]
问题是那里隐藏了原始类型。上面的
filterByClass
调用的返回类型是List<Optional>
,而不是List<Optional<...>>
。许多用途都会触发有关原始类型等的警告。现在,我了解类型擦除,并且我知道
class
对象将永远不会carry generic type information-没有此类Optional<String>.class
或Optional<Integer>.class
-只有Optional.class
。但是,仍然有一个比原始类型更好的返回值:我想要的是完全通用的通配符版本:
List<Optional<?>>
。这应该是完全类型安全的,因为任何Optional
都是Optional<?>
,对吧?分配不起作用,因为
List<Optional>
无法转换为List<Optional<?>>
List<Optional<?>> r = filterByClass(l, Optional.class);
强制转换也不起作用,因为类型甚至都不能强制转换(以相同的方式,无论不同类型
Foo<T>
和Foo<U>
之间的关系,T
都不能直接转换为U
)。唯一的解决方案似乎是一路转换为原始
List
,然后使用通配符参数化的类型参数返回列表:List<Optional<?>> r = (List)filterByClass(l, Optional.class);
现在显然这样的强制转换在一般情况下是不安全的,如果赋值
Optional<?>
中的type参数与传递给class
的filterByClass
对象不匹配(尽管是I think they are safe in the specific case that the class
matches the type parameter with unbounded wildcards),这将是完全不安全的。是否有某种方法可以通过更改
filterByClass
方法或对结果进行某种安全的转换来进行可能不安全的转换?另一个可能的答案是这是不安全的(即
filterByClass(..., Optional.class)
的结果不能安全地转换为List<Optional<?>>
,因此问题的格式不正确。 最佳答案
您可以将filterByClass
的签名更改为:
public static <T> List<T> filterByClass(List<?> list, Class<? extends T> clazz) {...}
然后,您可以从受让人推断
T
:List<Object> l = Arrays.<Object>asList(1, Optional.of("foo"), 2, Optional.of("bar"));
List<Optional<?>> result = filterByClass(l, Optional.class);
这是可行的,因为可以将原始
Optional
分配给Optional<?>
(这是安全的),因此Class<Optional>
满足Class<? extends Optional<?>>
,并且您可以将Optional
返回的cast
添加到Optional<?>
列表中。