如何将列表强制转换为具体实现?

时间:2012-08-08 14:52:01

标签: java

我们假设我正在使用一个我不知道源代码的库。它有一个返回List的方法,如下所示:

public List<SomeObj> getObjs() { ... }

我想知道这是不是一个好主意:

ArrayList<SomeObj> objs = (ArrayList<SomeObj>) getObjs();

例如,如果getObjs()里面的List的具体实现是LinkedList,那么会不会出现某种类型的差异?

9 个答案:

答案 0 :(得分:6)

不,这不是一个好主意。您应始终使用界面(List)声明列表变量,除非您出于某种原因需要ArrayList中的特定行为。
此外,如果您这样做,您需要确保返回的列表是ArrayList。在这种情况下,承诺的getObjs()合同只是返回类型是某种List,所以你不应该假设其他任何东西。即使现在返回的ListArrayList,也无法阻止getObjs()的实施者稍后更改返回的List类型,这会破坏您的代码。

答案 1 :(得分:4)

转换为您正在调用的API定义的返回类型。

如果它说它返回List<SomeObj>,那就是。不要尝试检索基础类型,因为:

a)它可能随新版本(甚至是通话之间)而变化

b)你不需要知道任何实现类。

如果需要一个ArrayList,请执行new ArrayList<SomeObject)(getObjs());

答案 2 :(得分:3)

使用接口(List)的重点是隐藏实现细节。你为什么要把它投射到具体的实现?

答案 3 :(得分:2)

你是对的。这不是一个好主意。您需要使用它返回的界面表单。

答案 4 :(得分:1)

如果你下载到ArrayList,它实际上是一个LinkedList,它会抛出一个ClassCastException。一般来说,如果你没有编写返回你想要向下转换的对象的代码,那么这样做就不是一个好主意了。此外,如果您使用这样的第三方库,他们可能会改变他们在改进代码时返回的内容。如果你在你的代码中放置这样的downcast,它今天可能会工作,但是当你升级你的libs时,它会突然崩溃。并且它在运行时断开而不是编译时间,所以在运行它之前你不会知道它的损坏。这是违反图书馆与您签订合同的问题,只有使用List界面。

答案 5 :(得分:1)

原因它返回List的原因是为了让您不必关心该界面的基础。

List接口只是声明对象必须满足的合约,以及如何查询它。图书馆作者将来可以自由选择ArrayListLinkedListLazyDatabasePopulatedList。实际上,您可能会在运行时获得不同的实现,具体取决于提供类的实现方式。

只要你有合同要遵守,这就给你带来了很大的自由。只有说话和提供接口,并尽可能少地处理具体类,还有很多要说的。

答案 6 :(得分:1)

您应始终使用界面代替Handle。这就是OOP语言的重点,以便您以后可以在任何实现之间切换。

如果要转换为任何具体类,编译器将警告您可能发生Cast异常的可能性。如果您非常确定类型,可以使用SuppressWarning

答案 7 :(得分:1)

这不是一个好主意,因为您不知道该方法返回的实现方式;如果它不是ArrayList,您将获得ClassCastException。实际上,您不应该关心该方法返回的确切实现。请改用List界面。

如果出于某种原因,您绝对需要ArrayList,那么请创建自己的ArrayList并使用该方法返回的List对其进行初始化:

ArrayList<SomeObj> myOwnList = new ArrayList(getObjs());

但是不要这样做,除非你绝对需要ArrayList - 因为它效率低下。

答案 8 :(得分:1)

你为什么不这样做:

List<SomeObj> objs = getObjs();

然后使用该列表。如果由于某种原因你真的需要一个ArrayList,你总是可以做

ArrayList<SomeObj> arrayList = new ArrayList<SomeObj>();
arrayList.addAll(objs);

并与之合作。但这并不是很有效。