程序包中的Collections.list()方法java.utils
返回ArrayList<T>
而不是的充分理由List<T>
吗?
显然,anArrayList
是a List
,但我的印象是返回接口类型而不是实现类型通常是一种好习惯。
程序包中的Collections.list()方法java.utils
返回ArrayList<T>
而不是的充分理由List<T>
吗?
显然,anArrayList
是a List
,但我的印象是返回接口类型而不是实现类型通常是一种好习惯。
List
保留添加元素的顺序,或者至少是由List
接口定义的常规协定:“有序集合(也称为序列) ”。
enum
。他们有一个名字,但没有别的。
Answers:
免责声明:我不是JDK作者。
我同意将自己的代码编写到接口是正确的,但是如果要将可变的集合返回给第三方,让第三方知道List
它们正在返回哪种类型非常重要。
LinkedList
并且ArrayList
有很大的不同,在性能方面,进行各种操作。例如,去除的第一元件ArrayList
是O(n)
,但除去所述第一元件的LinkedList
是O(1)
。
通过完全指定返回类型,JDK作者可以用明确的代码传达有关他们将给您什么样的对象的额外信息,因此您可以编写代码以正确使用此方法。如果确实需要一个LinkedList
,那么您必须在此处指定一个。
最后,在实现上对接口进行编码的主要原因是,如果您认为实现会改变。JDK作者可能认为他们永远不会改变这种方法。它永远不会返回aLinkedList
或a Collections.UnmodifiableList
。但是,在大多数情况下,您可能仍会这样做:
List<T> list = Collections.list(enumeration);
toLinkedList
方法,然后list
ArrayList版本的名称看起来很愚蠢。
返回时List
,您将把程序提升为接口,这是一个很好的做法。但是,这种方法有其局限性。例如,您不能使用某些为接口定义ArrayList
且不存在的方法List
-有关详细信息,请参见此答案。
我引用了Java™教程中的API设计:
......它的优良返回的对象的任何类型的那个工具或扩展集合接口之一。这可以是接口之一,也可以是扩展或实现这些接口之一的专用类型。
从某种意义上说,返回值应该具有与输入参数相反的行为:最好返回最具体的适用集合接口,而不是最通用的接口。例如,如果您确定将始终返回a
SortedMap
,则应为相关方法提供返回类型SortedMap
而不是Map
。SortedMap
实例的构建比普通Map
实例更耗时,并且功能也更强大。既然您的模块已经投入时间来构建SortedMap
,那么让用户访问其增强的功能非常有意义。此外,用户将能够将返回的对象传递给需要a的方法SortedMap
以及接受any的方法Map
。
由于ArrayList
本质上是一个数组,当我需要一个“集合数组”时,它们是我的首选。因此,如果要将枚举转换为列表,则选择数组列表。
在其他情况下,仍然可以这样写:
List<T> list = Collections.list(e);
SortedMap
,它为normal添加了功能Map
,因此我认为将其指定为返回类型是有意义的。但是,ArrayList
不会给添加任何内容List
,并且可以与进行交换,LinkedList
您将看不到任何不同(在功能方面而不是性能方面)。不过,我认为您的参考非常有趣。+1。
LinkedList
或时实际上要考虑很多事情ArrayList
。喜欢把自己的时间复杂度..
SortedMap
,则不应“因为它是一个”而将其返回。您应该确定呼叫者是否应该知道这是一个。而且您应该知道,一旦返回a ,就永远无法将其归纳为一个普通的东西-而总是有另一个方向(变得更加具体,并返回原来的a,仅返回了a )。SortedMap
SortedMap
Map
SortedMap
Map
返回新创建的可变对象的“专有所有权”的函数通常应该是最具体的实用类型。那些返回不可变对象的对象,特别是如果它们可能是共享的,则应该经常返回不太具体的类型。
区别的原因是,在前一种情况下,对象将始终能够产生指定类型的新对象,并且由于接收者将拥有该对象,并且无法告知接收者可能希望执行的操作,因此返回对象的代码通常无法知道任何其他接口实现是否可以满足接收者的需求。
在后一种情况下,对象是不可变的这一事实意味着该函数可能能够识别出替代类型,该类型可以在给定其确切内容的情况下完成更复杂的类型可以执行的所有操作。例如,Immutable2dMatrix
接口可以由一个ImmutableArrayBacked2dMatrix
类和一个ImmutableDiagonal2dMatrix
类来实现。如果主对角线上的所有元素都为零,或者不是,那么应该返回一个平方的函数Immutable2dMatrix
可以决定返回一个ImmutableDiagonalMatrix
实例ImmutableArrayBackedMatrix
。前一种将占用更少的存储空间,但是接收者不必在意它们之间的区别。
返回Immutable2dMatrix
而不是具体ImmutableArrayBackedMatrix
允许代码根据数组包含的内容选择返回类型。这也意味着,如果应该返回数组的代码恰好持有该数组的适当实现,Immutable2dMatrix
则可以简单地返回该数组,而不必构造新的实例。当处理不可变对象时,这两个因素都是主要的“胜利”。
但是,当使用可变对象时,这两个因素都不起作用。可变数组在生成时在主对角线上可能没有任何元素的事实并不意味着它永远不会有任何这样的元素。因此,虽然anImmutableDiagonalMatrix
实际上是an的子类型Immutable2dMatrix
,但是aMutableDiagonalMatrix
不是a的子类型Mutable2dMatrix
,因为后者可以接受主对角线的存储,而前者则不能。此外,虽然不可变对象经常可以并且应该被共享,但是可变对象通常不能。一个要求使用某些内容初始化的新可变集合的函数将需要创建一个新集合,无论其后备存储是否与请求的类型匹配。
有一个小的对象上调用方法VAR的接口,而不是直接开销。
该开销通常不超过1或2个处理器指令。如果JIT知道该方法是最终方法,则调用方法的开销甚至更低。对于您自己和我大多数的代码来说,这是无法测量的,但是对于java.utils中的低级方法,可能会在某些有问题的代码中使用。
同样在其他答案中已经指出,返回的对象的具体类型(即使隐藏在接口后面)也会影响使用该对象的代码的性能。这种性能上的变化可能非常大,以至于调用软件无法正常工作。
显然,作者java.utils
没有办法知道所有调用Collections.list()的软件会对结果产生什么影响,并且如果他们更改了Collections.list()的植入方式,也没有办法重新测试该软件。 因此,即使类型系统允许,它们也不会更改Collections.list()的植入以返回其他类型的List!
在编写自己的软件时,(希望)您进行了涵盖所有代码的自动化测试,并且很好地了解了代码之间的相互关系,包括知道性能存在问题。在软件设计不断变化的同时,能够更改方法而不必更改调用方的价值很大。
因此,这两组权衡是非常不同的。
ArrayList
是众所周知的,即使查看的源代码,我们也无法回答这个问题Collections
。