从GenericType< T> .class过滤器获取最常用类型的集合 [英] Getting collection of most general type from a GenericType<T>.class filter

查看:98
本文介绍了从GenericType< T> .class过滤器获取最常用类型的集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



比方说,我有一个方法可以过滤 List< p ;基于 class 的任意类型的T> ,返回一个新的 List ,其元素是输入列表中的那些是给定类的实例。这是一个简单的实现(是的,你也可以在一个单行的流中):

  public static< T> ;列表与LT; 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));
}
}
返回过滤;


$


如果你传递一个非泛型类型的列表字符串如(打印 foo bar ):

 列表与LT;对象> l = Arrays。< Object> asList(1,foo,2,bar); 
filterByClass(l,String.class).stream()。forEach(System.out :: println);

现在我想通过过滤一个泛型类的类,比如可选< T>

  List< Object> < Object> asList(1,Optional.of(foo),2,Optional.of(bar)); 
filterByClass(l,Optional.class).stream()。forEach(System.out :: println);

可以正常工作并打印:

可选[foo] 
可选[bar]

问题是隐藏在那里的原始类型。上面 filterByClass 调用的返回类型是 List< Optional> ,而不是 List< Optional< ; ...>> 。许多用途会触发关于原始类型的警告等。

现在我明白了类型擦除,并且我知道 class 对象永远不会携带泛型类型信息 - 没有这样的可选< String> .class 可选< Integer> .class - 只有 Optional.class



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



由于 List< Optional> 不能转换为 List< Optional< ;? >>< / code>

  List< Optional<?>> r = filterByClass(l,Optional.class); 

转换不起作用,或者是因为这些类型甚至不可转换(与无论不同类型之间的关系如何, Foo 都不能直接转换为 Foo $ c> T U )。



唯一的解决方案似乎是强制转换为原始 List ,然后返回到带有通配符参数类型参数的列表:

 列表与LT;可选<?>> r =(List)filterByClass(l,Optional.class); 

现在很明显,这种转换在一般情况下并不安全,如果类型参数可选<?> 与传递给对象不匹配> filterByClass - 尽管我认为它们在匹配带有无限通配符的类型参数



有没有可能不安全的强制转换的方法,或者通过更改 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);

由于原始可选可分配给可选<> (这是安全的),所以 Class< Optional> 满足类< ;? extends可选<>> ,并且您可以添加由 cast 返回的可选 >到可选<?> 的列表。


I apologize in advance for the terrible title, suggestions for improvement are eagerly accepted.

Let's say I have a method which filters a List<T> of arbitrary type based on a class, returning a new List whose elements are those of the input list that are instances of the given class. Here's a straightforward implementation (yes, you can also do it in a 1-liner with streams):

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;
}

This works great if you pass it a list of a non-generic type like String as in (prints foo bar):

List<Object> l = Arrays.<Object>asList(1, "foo ", 2, "bar ");
filterByClass(l, String.class).stream().forEach(System.out::println);

Now I want to pass to filter on a class of a generic type, say 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);

That works fine and prints:

Optional[foo]
Optional[bar]

The problem is there is a raw type hidden there. The return type of the filterByClass call above is List<Optional>, not List<Optional<...>>. Many uses will trigger warnings about raw types, etc.

Now I understand type erasure, and I know that a class object will never carry generic type information - there is no such Optional<String>.class or Optional<Integer>.class - there is only Optional.class.

However, there is still a better return value than the raw type: I would like instead the fully-generic wildcard version: List<Optional<?>>. This should be totally type safe, since any Optional is an Optional<?>, right?

Assignment doesn't work, since List<Optional> is not convertible to List<Optional<?>>

List<Optional<?>> r = filterByClass(l, Optional.class);  

A cast doesn't work either because the types aren't even castable (in the same way that Foo<T> can never be directly cast to Foo<U> no matter the relationship between different types T and U).

The only solution seems to be to cast all the way down to a raw List and then back up to the list with wildcard-paramaterized type-parameter:

List<Optional<?>> r = (List)filterByClass(l, Optional.class);  

Now obviously such casts aren't safe in the general case, and this would be totally unsafe if the type parameter in the assignment Optional<?> didn't match the class object passed to filterByClass - although I think they are safe in the specific case that the class matches the type parameter with unbounded wildcards.

Is there some way to do this without the potentially unsafe casts, either by changing the filterByClass method or some safe casting of the result?

Another possible answer would be that this is not safe (i.e., the result of filterByClass(..., Optional.class) cannot safely be converted to List<Optional<?>>, so the question is ill-formed.

解决方案

You could change the signature of filterByClass to:

public static <T> List<T> filterByClass(List<?> list, Class<? extends T> clazz) {...}

Then you can have T be inferred from the assignee:

List<Object> l = Arrays.<Object>asList(1, Optional.of("foo"), 2, Optional.of("bar"));
List<Optional<?>> result = filterByClass(l, Optional.class);

This works since a raw Optional is assignable to Optional<?> (which is safe), so Class<Optional> satisfies Class<? extends Optional<?>>, and you can add the Optional returned by cast to the list of Optional<?>.

这篇关于从GenericType&lt; T&gt; .class过滤器获取最常用类型的集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆