敬请谅解,敬请谅解。

假设我有一个方法可以根据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>.classOptional<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参数与传递给classfilterByClass对象不匹配(尽管是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<?>列表中。

10-07 18:56
查看更多