从GenericType< T> .class过滤器获取最常用类型的集合 [英] Getting collection of most general type from a GenericType<T>.class filter
问题描述
比方说,我有一个方法可以过滤 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<>>
,所以问题是格式不正确的。
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< T> .class过滤器获取最常用类型的集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!