我如何从List<>转换?列出< T>在Java中使用泛型? [英] How do I convert from List<?> to List<T> in Java using generics?

查看:130
本文介绍了我如何从List<>转换?列出< T>在Java中使用泛型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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
  • listClass 表示 L 的运行时类。
  • nt来实例化,为什么不传入空的Collection< T>你想要填充?这给了你的api用户更多的灵活性,因为使用默认的构造函数并不总是理想的。 (例如,也许我想要一个提供预期元素数量的Set,或者我想要一个提供比较器的排序列表)。



    另外,作为注意,你应该总是编程到最通用的接口。在这种情况下,你的输入不需要比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 extends List<T>).
    • untypedList is the "untyped" input list, effectively the same as List<Object>.
    • itemClass represents the runtime class of T.
    • listClass represents the runtime class of L.

    解决方案

    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&lt;&gt;转换?列出&lt; T&gt;在Java中使用泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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