如何将列表转换为他们的conrecte实现?
假设我正在使用一个我不知道源代码的库。 它有一个返回List的方法,如下所示:
public List getObjs() { ... }
我想知道这是不是一个好主意:
ArrayList objs = (ArrayList) getObjs();
例如,如果getObjs()里面的List的具体实现是LinkedList
那么会不会出现某种类型的差异?
不,这不是一个好主意。 除非由于某种原因需要ArrayList
特定行为,否则应始终使用接口( List
)声明列表变量。
此外,如果这样做,您需要确保返回的列表是ArrayList
。 在这种情况下, getObjs()
的承诺合约只是返回类型是某种List
,所以你不应该假设其他任何东西。 即使现在返回的List
是ArrayList
,也没有什么能阻止getObjs()
的实现者稍后更改返回的List
类型,这会破坏你的代码。
转换为您调用的API定义的返回类型。
如果它说它返回List
,那就是。 不要尝试检索基础类型,因为:
a)它可能随新版本(甚至是通话之间)而变化
b)您无需知道任何实现类。
如果你需要一个ArrayList,那么做new ArrayList
使用接口(List)的重点是隐藏实现细节。 为什么要将其转换为具体实现?
你是对的。 这不是一个好主意。 您需要使用它返回的界面表单。
如果你下载到ArrayList,它会抛出一个ClassCastException,而实际上它是一个LinkedList。 一般来说,如果你没有编写返回你想要向下转换的对象的代码,那么这样做也不是一个好主意。 此外,如果您使用这样的第三方库,他们可能会改变他们在改进代码时返回的内容。 如果你在你的代码中放置这样的downcast,它今天可能会工作,但是当你升级你的libs时,它会突然中断。 并且它在运行时断开而不是编译时间,所以在运行之前你不会知道它的损坏。 这是违反图书馆与您签订合同的问题,只有使用List界面。
它返回List
的原因是你不必关心它接口的底层。
List
接口只是声明对象必须满足的合约,以及如何查询它。 图书馆作者将来可以自由选择ArrayList
, LinkedList
或者LazyDatabasePopulatedList
。 实际上,您可能会在运行时获得不同的实现,具体取决于提供类的实现方式。
只要你有合同要坚持,这就给你带来了很大的自由。 只有说话和提供接口,并尽可能少地处理具体类,还有很多要说的。
您应始终使用界面代替Handle
。 这就是OOP
Languages的重点,以便您以后可以在任何实现之间切换。
如果要转换为任何具体类,编译器将警告您可能发生Cast
Exception。 如果您非常确定类型,可以使用SuppressWarning
。
这不是一个好主意,因为您不知道该方法返回的实现方式; 如果它不是ArrayList
,你将得到一个ClassCastException
。 实际上,您不应该关心该方法返回的确切实现。 请改用List
界面。
如果由于某种原因,您绝对需要一个ArrayList
,那么创建自己的ArrayList
并使用该方法返回的List
对其进行初始化:
ArrayList myOwnList = new ArrayList(getObjs());
但是不要这样做,除非你绝对需要一个ArrayList
– 因为它效率低下。
你为什么不这样做:
List objs = getObjs();
然后使用该列表。 如果由于某种原因你确实需要一个ArrayList,你总是可以这样做
ArrayList arrayList = new ArrayList (); arrayList.addAll(objs);
并与之合作。 但这不是很有效。