我如何从List<>转换?列出< T>在Java中使用泛型? [英] How do I convert from List<?> to List<T> in Java using generics?
问题描述
在Java中,如何使用通用目标将 List <?>>
转换为 List< T>
方法,以便我可以用一个方法调用替换如下的模式:
List untypedList = new ArrayList(); //或从传统方法返回
List< Integer> typedList = new ArrayList< Integer>();
for(Object item:untypedList)
typedList.add((Integer)item);
请注意,上述代码不会产生任何类型安全警告,理想情况下, t
下面的解决方案工作是否提供了列表 Class
有一个公共默认构造函数?
public class ListUtil {
public static< T,L extends List< T>> L typedList(List<> untypedList,Class< T> itemClass,Class< L> listClass){
L list = null;
尝试{
list = listClass.newInstance(); (对象项目:untypedList)
list.add(itemClass.cast(
)catch(InstantiationException e){
} catch(IllegalAccessException e){
}
项目));
返回列表;
$ b(注意
listClass。如果一个
实例抛出
没有公共的默认构造函数,如果方法没有正确处理这些异常,可能会出现什么问题?)InstantiationException
或IllegalAccessException
,则newInstance Class< L>
:
T
是结果列表中每个项目的类型。
L
是我希望创建的列表的类型(它扩展了List< T> $
untypedList
是untyped输入列表,实际上与List< ;对象>
。
itemClass
表示T
。
- nt来实例化,为什么不传入空的Collection< T>你想要填充?这给了你的api用户更多的灵活性,因为使用默认的构造函数并不总是理想的。 (例如,也许我想要一个提供预期元素数量的Set,或者我想要一个提供比较器的排序列表)。
listClass
表示L
的运行时类。
另外,作为注意,你应该总是编程到最通用的接口。在这种情况下,你的输入不需要比Iterable更具体,并且你的输出是Collection。
在这种情况下,我会这样写这个方法 - p>
public static< T,C extends Collection< T>> (对象项目:来自){
to.add(listClass.cast(item)); C类型安全增加(来自C,Class T等级类别的Iterable<>
}
返回;
}然后调用代码如下所示:
public static void main(String [] args){
List<?> untypedStringList = LegacyApi.getStringList();
列表< String> typesafeStringList = typesafeAdd(untypedStringList,new ArrayList< String>(),String.class);
}
2 Comments here:
- 如果您真的可以信任LegacyApi(或者提供给您的任何类型的List),只会返回一个包含预期类型的集合,那么您可以执行一个未经检查的转换并将其抑制。这应该尽可能在最小范围内进行本地化。即:创建类似于TypesafeLegacyApiWrapper的委托给LegacyApi的调用。
- 如果您有更复杂的事情,则此方法签名仍然失效。例如,如果您有一个List< List< String>>此方法无效。
In Java, how do I convert List<?>
to List<T>
using a general purpose method so that I can replace patterns like the following with a single method call:
List untypedList = new ArrayList(); // or returned from a legacy method
List<Integer> typedList = new ArrayList<Integer>();
for (Object item: untypedList)
typedList.add((Integer)item);
Note that the above code does not generate any type-safety warnings and, ideally, your solution shouldn't generate any such warnings, either.
Will the following solution work provided that list Class<L>
has a public default constructor?
public class ListUtil {
public static <T, L extends List<T>> L typedList(List<?> untypedList, Class<T> itemClass, Class<L> listClass) {
L list = null;
try {
list = listClass.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}
for (Object item: untypedList)
list.add(itemClass.cast(item));
return list;
}
}
(Note that listClass.newInstance()
throws InstantiationException
or IllegalAccessException
if an instance of Class<L>
does not have a public default constructor. What problems may arise if the method does not properly handle these exceptions?)
Notes:
T
is the type of each item in the resulting list.L
is the type of the list that I wish to create (which extendsList<T>
).untypedList
is the "untyped" input list, effectively the same asList<Object>
.itemClass
represents the runtime class ofT
.listClass
represents the runtime class ofL
.
Rather than passing in the type of the list you want to instantiate, why not just pass in the empty Collection<T> that you want populated? This gives the users of your api much more flexibility, as using the default constructor is not always ideal. (for example, maybe I want a Set where I provide the expected number of elements, or I want a sorted list where I provide the Comparator).
Also, as a side note, you should always program to the most generic interface possible. In this case, your input need be nothing more specific than an Iterable, and your output a Collection.
Given this, I would write the method this way --
public static <T, C extends Collection<T>> C typesafeAdd(Iterable<?> from, C to, Class<T> listClass) {
for (Object item: from) {
to.add(listClass.cast(item));
}
return to;
}
then the calling code looks like:
public static void main(String[] args) {
List<?> untypedStringList = LegacyApi.getStringList();
List<String> typesafeStringList = typesafeAdd(untypedStringList, new ArrayList<String>(), String.class);
}
2 Comments here:
- If you can really trust LegacyApi (or whatever provided you the untyped List) to only return to you a collection with the expected type in it, then you can just do an unchecked cast and suppress it. This should be localized to the smallest scope possible. ie: create something like TypesafeLegacyApiWrapper which delegates calls to LegacyApi.
- This method signature still breaks down if you have anything more complicated. For example if you have a List<List<String>> this method does not work.
这篇关于我如何从List<>转换?列出< T>在Java中使用泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!