在Java中的类型List和类型ArrayList的比较
在Java中的类型List和类型ArrayList的比较
这个问题已经在这里有了答案:
(1) List<?> myList = new ArrayList<?>(); (2) ArrayList<?> myList = new ArrayList<?>();
我知道使用(1),可以交换 List 接口的实现。看起来无论是否需要,(1)都通常用于应用程序(我自己总是这样使用)。
我想知道是否有人使用(2)?
另外,有多少情况实际上需要使用(1)而不是(2)(即在(2)不足以满足的情况下..除了编码到接口和最佳实践等方面)。
我想知道是否有人使用(2)?
是的。但很少有一个好的理由(在我看来)。
人们会因为使用ArrayList
而被烧伤,而他们应该使用List
:
-
像
Collections.singletonList(...)
或Arrays.asList(...)
这样的实用程序方法不会返回ArrayList
。 -
List
API中的方法不保证返回相同类型的列表。
举个例子,一个人在https://stackoverflow.com/a/1481123/139985中有问题,因为ArrayList.sublist(...)
不返回ArrayList
...而他设计他的代码来使用ArrayList
作为他所有列表变量的类型。最后,他通过将子列表复制到新的ArrayList
中来“解决”这个问题。
认为你需要知道List
如何运行的论点可以通过使用RandomAccess
标记界面在很大程度上得到解决。是的,这有点笨拙,但是替代品更糟糕。
此外,什么情况下实际上需要使用(1)而不是(2)(即在不考虑“编码到接口”和最佳实践等方面,(2)不能满足的情况下)?
“多么频繁”这个问题客观上无法回答。
(我可以请给个例子吗)
偶尔,应用程序可能需要使用ArrayList
API中不在List
API中的方法。例如,ensureCapacity(int)
,trimToSize()
或removeRange(int,int)
。(最后一个只会出现在您创建了一个声明该方法为public
的ArrayList的子类型的情况下。)
在我看来,编码到类而不是接口是唯一合理的理由。
(理论上可能会在某些平台下的某些情况下略微提高性能……但除非你真正需要最后的0.05%,否则不值得这样做。在我看来,这不是一个合理的理由。)
如果你不知道随机访问是否有效,那么就不能编写高效的代码。
这是一个有道理的观点。然而,Java提供了更好的解决方法,例如:
publicvoid test(T list) { // do stuff }
如果你用一个没有实现RandomAccess
的列表来调用它,你会得到一个编译错误。
你也可以动态地测试……使用instanceof
……如果静态类型过于笨拙。你甚至可以编写你的代码来使用不同的算法(动态地),具体取决于列表是否支持随机访问。
请注意,ArrayList
不是唯一实现RandomAccess
的列表类。其他的包括CopyOnWriteList
、Stack
和Vector
。
我见过人们对Serializable
提出同样的争论(因为List
没有实现它)……但上面的方法也解决了这个问题。(在使用运行时类型时,只要有一个元素不可序列化,ArrayList
就会失败地序列化。)
最后,我不会说“因为它是好的风格”。这个“理由”既是一个循环论证(“为什么是‘好的风格’?”),也是向一个未明示(并可能不存在!)的更高权威的呼吁(“谁说它是‘好的风格’?”)。
我认为按照接口编程是一种良好的风格,但我不会把它作为理由。最好让你们理解真正的原因,自行得出(我认为)正确的结论。根据不同的上下文,正确的结论可能并不总是相同的。
一般情况下,我们会更倾向于使用List
而不是ArrayList
,因为List
可以被转换成LinkedList
,而不会影响其他的代码部分。
如果选择使用ArrayList
而不是List
,那么将很难把ArrayList
实现改成LinkedList
,因为已经在代码库中使用了ArrayList
特定的方法,这也需要进行重构。
您可以在这里了解有关List
实现的信息。
您可以先从ArrayList
开始,但很快您可能会发现另一种实现是更合适的选择。