如何在Java中创建另一个List,给定一个List但列出了不同的类



我有一个列表,我需要返回相同类型的列表。

如果它是相关的,在我的例子中,Y是一个接口,X是它的超接口。

我假设我需要使用newInstance来获取List的类型。

public List<Y> foo() {
    List<X> xList = -a method that returns List<X>-;
    List<Y> yList = xList.getClass().newInstance(); //Is this right?
    ...
    return yList;
}

我可以制作一个ArrayList,但我不知道这是否是最好的做法,因为我可以收到任何类型的列表。

您是否将List的类与其泛型类型混淆了?应该很少需要返回List的特定实现(例如,如果它需要序列化)。我建议只使用ArrayList,事先大小合适。

关于接口,请小心,因为如果Y扩展了X,则通常不能将xList中的对象放在yList中(我认为您愿意),因为列表中可能有一个X实例不是Y

Java通过擦除实现泛型,因此在运行时,您将看不到List<X>.getClass()List<Y>的区别。然而,你应该能够说:

List<Y> yList = new ArrayList<Y>(); // Or LinkedList, or whatever implementation you want.

如果您不知道要使用哪个List实现,而这正是您想要的,这取决于支持xList的列表类型,那么您仍然可以使用newInstance:您只需要强制转换它:

List<Y> yList = (List<Y>)xList.getClass().newInstance();

在运行时,您所拥有的只是一个LinkedListArrayList或诸如此类的项,但只要您不向列表中添加任何非Y项,就可以安全地将其作为List<Y>返回。

由于您不知道List的类型,也不知道它是否有公共的无arg构造函数,因此您不能确定newInstance()不会抛出异常。

如果你不想要列表的副本,并且你知道列表实际上包含Y个实例,你可以只做

List<Y> yList = (List) xList;
List<Y> yList = (List<Y>) xList.getClass().newInstance();

只有在无args构造函数可用的情况下才能工作。如果无法访问,您可能需要使用反射覆盖访问可见性:

final Constructor cons = xList.getClass().getDeclaredConstructor();
cons.setAccessible(true);
List<Y> yList = (List<Y>) cons.newInstance();

如果该类没有可用的args构造函数,那么您可能运气不好!建议实现类提供以下形式的构造函数:

public MyListClass(Collection<T> items)

如果存在这样的构造函数,您可以尝试使用反射调用该构造函数,并向其传递一个空List。在一般情况下,无法确定调用哪个构造函数:(

最新更新