我们假设我正在使用一个我不知道源代码的库。它有一个返回List的方法,如下所示:
public List<SomeObj> getObjs() { ... }
我想知道这是不是一个好主意:
ArrayList<SomeObj> objs = (ArrayList<SomeObj>) getObjs();
例如,如果getObjs()里面的List的具体实现是LinkedList
,那么会不会出现某种类型的差异?
答案 0 :(得分:6)
不,这不是一个好主意。您应始终使用界面(List
)声明列表变量,除非您出于某种原因需要ArrayList
中的特定行为。
此外,如果您这样做,您需要确保返回的列表是ArrayList
。在这种情况下,承诺的getObjs()
合同只是返回类型是某种List
,所以你不应该假设其他任何东西。即使现在返回的List
为ArrayList
,也无法阻止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
接口只是声明对象必须满足的合约,以及如何查询它。图书馆作者将来可以自由选择ArrayList
,LinkedList
或LazyDatabasePopulatedList
。实际上,您可能会在运行时获得不同的实现,具体取决于提供类的实现方式。
只要你有合同要遵守,这就给你带来了很大的自由。只有说话和提供接口,并尽可能少地处理具体类,还有很多要说的。
答案 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);
并与之合作。但这并不是很有效。