我有一个列表,我需要返回相同类型的列表。
如果它是相关的,在我的例子中,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();
在运行时,您所拥有的只是一个LinkedList
或ArrayList
或诸如此类的项,但只要您不向列表中添加任何非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。在一般情况下,无法确定调用哪个构造函数:(