从GenericType <t> .class过滤器

时间:2017-12-05 19:43:40

标签: java generics

我为这个糟糕的头衔提前道歉,并且热切地接受了改进建议。

我们假设我有一种基于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 - 只有{{1} }}

但是,仍然有比原始类型更好的返回值:我想要完全通用的通配符版本:Optional.class。这应该是完全类型安全的,因为任何List<Optional<?>>都是Optional,对吗?

分配不起作用,因为Optional<?>无法转换为List<Optional>

List<Optional<?>>

演员阵容也不起作用,因为类型甚至不能施放(就像List<Optional<?>> r = filterByClass(l, Optional.class); 永远无法直接转换为Foo<T>一样,无论不同之间的关系如何类型Foo<U>T)。

唯一的解决方案似乎是一直向下转换为原始U,然后使用wildcard-paramaterized type-parameter备份到列表:

List

现在很明显,在一般情况下这样的强制转换是不安全的,如果赋值List<Optional<?>> r = (List)filterByClass(l, Optional.class); 中的type参数与传递的Optional<?>对象不匹配,这将完全不安全至class - 尽管I think they are safe in the specific case that the class matches the type parameter with unbounded wildcards

有没有一些方法可以在没有潜在不安全的强制转换的情况下执行此操作,方法是更改​​filterByClass方法或结果的某些安全转换?

另一个可能的答案是,这不安全(即filterByClass的结果无法安全地转换为filterByClass(..., Optional.class),因此问题形成不良。

1 个答案:

答案 0 :(得分:4)

您可以将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<?>>,您可以添加Optionalcast返回Optional<?>列表。