(1) List<?> myList = new ArrayList<?>();

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

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

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

此外,情况实际上需要使用(1)而不是(2)的频率是多少(请给我一个例子)(即(2)是不够的..除了编码到接口和最佳实践等)。


当前回答

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

是的。但很少有合理的理由(我觉得)。

有些人因为在应该用List的时候用了数组列表而被惹恼了

像Collections.singletonList(…)或Arrays.asList(…)这样的实用方法不会返回数组列表。 List API中的方法不能保证返回相同类型的列表。

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

您需要知道List如何行为的参数在很大程度上是通过使用RandomAccess标记接口来解决的。是的,这有点笨拙,但另一种选择更糟糕。

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

“多久一次”这部分问题客观上是无法回答的。

(我能举个例子吗)

偶尔,应用程序可能会要求您使用不在List API中的ArrayList API中的方法。例如,ensureCapacity(int), trimToSize()或removeRange(int, int)。(最后一个问题只会出现在你创建了ArrayList的子类型并声明该方法为public的情况下。)

在我看来,这是针对类而不是针对接口进行编码的唯一合理理由。

(从理论上讲,你的性能可能会有轻微的提高……在某些情况下……在某些平台上……但除非你真的需要最后的0.05%,否则不值得这么做。在我看来,这不是一个合理的理由。)


如果你不知道随机访问是否有效,你就不能写出有效的代码。

这是一个有效的观点。然而,Java提供了更好的处理方法;如。

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

如果你用一个没有实现RandomAccess的列表调用它,你会得到一个编译错误。

你也可以动态测试…使用instanceof…如果静态类型太尴尬。您甚至可以根据列表是否支持随机访问来编写使用不同算法的代码(动态地)。

注意,ArrayList并不是唯一实现RandomAccess的列表类。其他包括CopyOnWriteList, Stack和Vector。

我看到人们对Serializable也有同样的看法(因为List没有实现它)…但是上面的方法也解决了这个问题。(在使用运行时类型完全可以解决的范围内。如果数组列表中有任何元素是不可序列化的,则数组列表序列化将失败。)


最后,我不会说“因为它的风格很好”。这个“理由”既是一个循环论证(“为什么这是‘好风格’?”),也是对一个未明说(可能根本不存在!)的更高权威的诉求(“谁说这是‘好风格’?”)。

(我确实认为根据界面编程是一种很好的风格,但我不会以此作为理由。你最好先了解真正的原因,然后自己得出正确的结论。正确的结论可能不总是一样的……视上下文而定。)

其他回答

列表接口有几个不同的类——ArrayList和LinkedList。LinkedList用于创建索引集合,ArrayList用于创建排序列表。你可以在你的参数中使用它,但是你可以允许其他使用你的代码,库等的开发人员使用不同类型的列表,而不仅仅是你在这个方法中使用的

ArrayList<Object> myMethod (ArrayList<Object> input) {
   // body
}

你只能在ArrayList中使用它,而不是LinkedList,但是你可以允许在其他地方使用它的方法,这只是你的选择,所以使用接口可以允许它:

List<Object> myMethod (List<Object> input) {
   // body
}

在这个方法参数中,你可以使用任何你想使用的List类:

List<Object> list = new ArrayList<Object> ();

list.add ("string");

myMethod (list);

结论:

尽可能在任何地方使用接口,不要限制您或其他人使用他们想要使用的不同方法。

(3) Collection myCollection = new ArrayList<?>();

我通常用这个。只有当我需要List方法时,我才会使用List。数组列表也是一样。你总是可以切换到更“窄”的界面,但你不能切换到更“宽”的界面。

我所知道的(2)可以更好的唯一情况是使用GWT,因为它减少了应用程序的占用空间(不是我的想法,但谷歌web工具包团队是这么说的)。但是对于在JVM(1)中运行的常规java来说,可能总是更好。

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

是的。但很少有合理的理由(我觉得)。

有些人因为在应该用List的时候用了数组列表而被惹恼了

像Collections.singletonList(…)或Arrays.asList(…)这样的实用方法不会返回数组列表。 List API中的方法不能保证返回相同类型的列表。

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

您需要知道List如何行为的参数在很大程度上是通过使用RandomAccess标记接口来解决的。是的,这有点笨拙,但另一种选择更糟糕。

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

“多久一次”这部分问题客观上是无法回答的。

(我能举个例子吗)

偶尔,应用程序可能会要求您使用不在List API中的ArrayList API中的方法。例如,ensureCapacity(int), trimToSize()或removeRange(int, int)。(最后一个问题只会出现在你创建了ArrayList的子类型并声明该方法为public的情况下。)

在我看来,这是针对类而不是针对接口进行编码的唯一合理理由。

(从理论上讲,你的性能可能会有轻微的提高……在某些情况下……在某些平台上……但除非你真的需要最后的0.05%,否则不值得这么做。在我看来,这不是一个合理的理由。)


如果你不知道随机访问是否有效,你就不能写出有效的代码。

这是一个有效的观点。然而,Java提供了更好的处理方法;如。

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

如果你用一个没有实现RandomAccess的列表调用它,你会得到一个编译错误。

你也可以动态测试…使用instanceof…如果静态类型太尴尬。您甚至可以根据列表是否支持随机访问来编写使用不同算法的代码(动态地)。

注意,ArrayList并不是唯一实现RandomAccess的列表类。其他包括CopyOnWriteList, Stack和Vector。

我看到人们对Serializable也有同样的看法(因为List没有实现它)…但是上面的方法也解决了这个问题。(在使用运行时类型完全可以解决的范围内。如果数组列表中有任何元素是不可序列化的,则数组列表序列化将失败。)


最后,我不会说“因为它的风格很好”。这个“理由”既是一个循环论证(“为什么这是‘好风格’?”),也是对一个未明说(可能根本不存在!)的更高权威的诉求(“谁说这是‘好风格’?”)。

(我确实认为根据界面编程是一种很好的风格,但我不会以此作为理由。你最好先了解真正的原因,然后自己得出正确的结论。正确的结论可能不总是一样的……视上下文而定。)

我会说1是首选,除非

你依赖于ArrayList中可选行为*的实现,在这种情况下显式使用ArrayList更清楚 你将在一个需要ArrayList的方法调用中使用ArrayList,可能用于可选的行为或性能特征

我的猜测是,在99%的情况下,您可以使用List,这是首选。

为实例removeAll,或add(null)