为什么Enumeration转换为ArrayList而不是java.utils中的List?

Tia*_*ong 74 java collections arraylist return-type

是否有一个很好的理由,包中的Collections.list()方法java.utils返回ArrayList<T>而不是List<T>

显然a ArrayList是a List,但我的印象是返回接口类型而不是实现类型通常是一种好习惯.

dur*_*597 54

免责声明:我不是JDK的作者.

我同意将自己的代码写入接口是正确的,但是如果你要将可变集合返回给第三方,那么让第三方知道List他们会回来的是什么类型是很重要的.

LinkedList并且ArrayList有很大的不同,在性能方面,进行各种操作.例如,删除a的第一个元素ArrayListO(n),但删除a的第一个元素LinkedListO(1).

通过完全指定返回类型,JDK作者正在以明确的代码方式传达有关他们给你的对象类型的额外信息,因此您可以编写代码以正确使用此方法.如果你真的需要LinkedList,你知道你必须在这里指定一个.

最后,如果您认为实现将发生变化,那么在实现上编写接口代码的主要原因是.JDK的作者可能认为他们永远不会改变这种方法; 它永远不会返回a LinkedList或a Collections.UnmodifiableList.但是,在大多数情况下,您可能仍会这样做:

List<T> list = Collections.list(enumeration);
Run Code Online (Sandbox Code Playgroud)

  • 看起来这是一种针对API设计的Postel定律:与您的输入一致,特定于您的输出. (19认同)
  • 有一天他们会添加`toLinkedList`方法,然后ArrayList版本的名称`list`看起来很傻. (2认同)

Mar*_*oun 31

返回时List,您将推动程序到界面,这是一个非常好的做法.但是,这种方法有其局限性.例如,您不能使用界面中定义的ArrayList和不存在的某些方法List- 有关详细信息,请参阅此答案.

我引用了The Java™Tutorials中的API Design:

......它的优良返回的对象的任何类型实现或者扩展的收集接口之一.这可以是接口之一,也可以是扩展或实现这些接口之一的专用类型.

..在某种意义上,返回值应该具有输入参数的相反行为:最好返回最具体的适用集合接口,而不是最一般的.例如,如果您确定您将始终返回a SortedMap,则应该为相关方法提供返回类型SortedMap而不是Map.SortedMap实例比普通Map实例更耗时,而且功能更强大.鉴于您的模块已经投入时间来构建一个SortedMap,因此让用户访问其增加的功能是很有意义的.此外,用户将能够将返回的对象传递给需要a的方法SortedMap以及接受any的方法Map.

由于ArrayList本质上是一个数组,当我需要一个"集合数组"时,它们是我的第一选择.因此,如果我想将枚举转换为列表,我的选择将是一个数组列表.

在任何其他情况下,它仍然有效写:

List<T> list = Collections.list(e);
Run Code Online (Sandbox Code Playgroud)

  • 要强调这一点:这应该是**设计决定**,而不是"巧合".如果你在"SortedMap"内部存储你的数据,你应该**不要**返回它"因为它**是**".你应该决定*调用者是否应该知道这是一个`SortedMap`.你应该知道,一旦你返回一个`SortedMap`,你将**永远不能将它概括为一个普通的`Map` - 而另一个方向(变得更具体,并返回一个`SortedMap`最初只能返回一个`Map`). (5认同)
  • 关于"最具体的适用集合接口而不是最一般的",这是有道理的,但ArrayList不是接口.在这种情况下,List似乎是最具体的接口. (4认同)
  • 在"SortedMap"的情况下,它为普通的`Map`添加了功能,所以我认为将它指定为返回类型是有意义的.但是,`ArrayList`不会给`List`添加任何东西,并且可以与`LinkedList`交换,你不会看到任何不同的东西(功能方面,而不是性能方面).不过,我认为你的参考非常有趣.+1. (2认同)

sup*_*cat 6

返回新创建的可变对象的"独占所有权"的函数通常应该是最具体的类型; 返回不可变对象的那些,特别是如果它们可能被共享,应该经常返回不太具体的类型.

区别的原因在于,在前一种情况下,对象将始终能够生成所指示类型的新对象,并且由于接收者将拥有该对象,并且不知道接收者可能希望执行哪些操作,返回对象的代码通常无法知道任何替代接口实现是否能满足接收​​者的需求.

在后一种情况下,对象是不可变的这一事实意味着该函数可能能够识别替代类型,该替代类型可以执行更复杂类型在给定其确切内容的情况下可以执行的所有操作.例如,Immutable2dMatrix接口可以由ImmutableArrayBacked2dMatrix类和ImmutableDiagonal2dMatrix类实现.如果主对角线上的所有元素都恰好为零,则假定返回正方形的函数Immutable2dMatrix可以决定返回ImmutableDiagonalMatrix实例,如果不是,则返回实例ImmutableArrayBackedMatrix.前一种类型会占用更少的存储空间,但接收者不应该关心它们之间的差异.

返回Immutable2dMatrix而不是具体ImmutableArrayBackedMatrix允许代码根据数组包含的内容选择返回类型; 它还意味着如果应该返回数组的代码碰巧持有一个合适的实现,Immutable2dMatrix它可以简单地返回它,而不是必须构造一个新实例.在处理不可变对象时,这两个因素都可能是主要的"胜利".

但是,在处理可变对象时,两个因素都不起作用.可变数组在生成时可能没有任何元素离开主对角线并不意味着它永远不会有任何这样的元素.因此,虽然a ImmutableDiagonalMatrix实际上是a的子类型Immutable2dMatrix,但a MutableDiagonalMatrix不是a的子类型Mutable2dMatrix,因为后者可以接受主对角线上的存储,而前者不能.此外,虽然不可变对象通常可以并且应该被共享,但是可变对象通常不能.要求使用特定内容初始化的新可变集合的函数将需要创建新集合,无论其后备存储是否与所请求的类型匹配.