Java 中的类型列表与 ArrayList 类型

2022-08-31 04:12:20
(1) List<?> myList = new ArrayList<?>();

(2) ArrayList<?> myList = new ArrayList<?>();

我知道使用(1),List接口的实现可以交换。似乎(1)通常用于应用程序,而不管是否需要(我自己总是使用它)。

我想知道是否有人使用(2)?

此外,这种情况多久需要使用(1)而不是(2)(即(2)不够。除了编码到接口最佳实践等)


答案 1

几乎总是优先选择,因为例如,可以转换为LinkedList而不会影响代码库的其余部分。ListArrayListList

如果使用 一个而不是 ,则很难将实现更改为一个,因为在代码库中使用了特定的方法,这些方法也需要重构。ArrayListListArrayListLinkedListArrayList

您可以在此处阅读有关实现的信息List

您可以从 开始,但很快就会发现另一个实现是更合适的选择。ArrayList


答案 2

我想知道是否有人使用(2)?

是的。但很少出于合理的理由(IMO)。

人们被烧伤,因为他们在应该使用的时候使用:ArrayListList

  • 实用工具方法(如 或不返回 .Collections.singletonList(...)Arrays.asList(...)ArrayList

  • API 中的方法不保证返回相同类型的列表。List

例如,有人被烧伤,https://stackoverflow.com/a/1481123/139985 海报在“切片”方面存在问题,因为没有返回...他将自己的代码设计为用作所有列表变量的类型。他最终通过将子列表复制到新的列表中来“解决”问题。ArrayList.sublist(...)ArrayListArrayListArrayList

您需要知道行为方式的论点在很大程度上通过使用标记接口来解决。是的,它有点笨拙,但另一种选择更糟。ListRandomAccess

此外,这种情况实际需要使用(1)而不是(2)的频率(即(2)不够的地方)。除了“编码到接口”和最佳实践等)

这个问题的“频率”部分客观上是无法回答的。

(我能举个例子吗)

有时,应用程序可能要求您在 API 中使用 API 中没有的方法。例如,或 。(最后一个只有在您创建了 ArrayList 的子类型,该子类型将方法声明为 .)ArrayListListensureCapacity(int)trimToSize()removeRange(int, int)public

这是编码到类而不是接口IMO的唯一合理原因。

(从理论上讲,您可能会在性能方面略有提高...在某些情况下...在某些平台上...但除非你真的需要最后的0.05%,否则不值得这样做。这不是一个合理的理由,IMO。


如果您不知道随机访问是否有效,则无法编写有效的代码。

这是一个有效的观点。但是,Java提供了更好的方法来解决这个问题。例如:

public <T extends List & RandomAccess> void test(T list) {
    // do stuff
}

如果使用未实现的列表调用它,则会收到编译错误。RandomAccess

您还可以动态测试...用。。。如果静态键入太尴尬。您甚至可以编写代码以使用不同的算法(动态),具体取决于列表是否支持随机访问。instanceof

请注意,这不是实现 的唯一列表类。其他包括 和 。ArrayListRandomAccessCopyOnWriteListStackVector

我看到人们提出同样的论点(因为没有实现它)......但上面的方法也解决了这个问题。(在某种程度上,它可以使用运行时类型来解决。如果任何元素不可序列化,则 序列化将失败。SerializableListArrayList


最后,我不会说“因为它是好的风格”。这个“理由”既是一个循环论证(“为什么它是'好风格'?”),也是对一个未声明的(可能不存在的!)更高权威的呼吁(“说它是'好风格'?”)。

(我确实认为编程到界面是很好的风格,但我不会以此为理由。您最好了解真正的原因并为自己得出(IMO)正确的结论。正确的结论可能并不总是相同的...取决于上下文。