Java 中的类型列表与类型 ArrayList
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2279030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Type List vs type ArrayList in Java
提问by kji
(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
I understand that with (1), implementations of the Listinterface can be swapped. It seems that (1) is typically used in an application regardless of need (myself I always use this).
我知道通过(1),可以交换List接口的实现。似乎(1)通常用于应用程序而不管需要(我自己总是使用它)。
I am wondering if anyone uses (2)?
我想知道是否有人使用(2)?
Also, how often (and can I please get an example) does the situation actually require using (1) over (2) (i.e. where (2) wouldn't suffice..aside coding to interfacesand best practicesetc.)
此外,这种情况多久(我可以举个例子)实际上需要使用(1)而不是(2)(即(2)在哪里不够......除了对接口和最佳实践进行编码等)
采纳答案by kgiannakakis
Almost always List
is preferred over ArrayList
because, for instance, List
can be translated into a LinkedList
without affecting the rest of the codebase.
几乎总是List
首选,ArrayList
因为例如,List
可以在LinkedList
不影响代码库其余部分的情况下转换为。
If one used ArrayList
instead of List
, it's hard to change the ArrayList
implementation into a LinkedList
one because ArrayList
specific methods have been used in the codebase that would also require restructuring.
如果使用一个ArrayList
而不是List
,则很难将ArrayList
实现更改为LinkedList
一个,因为ArrayList
代码库中使用了特定的方法,这些方法也需要重构。
You can read about the List
implementations here.
You may start with an ArrayList
, but soon after discover that another implementation is the more appropriate choice.
您可以从 开始ArrayList
,但很快就会发现另一个实现是更合适的选择。
回答by extraneon
I would say that 1 is preferred, unless
我会说 1 是首选,除非
- you are depending on the implementation of optional behavior* in ArrayList, in that case explicitly using ArrayList is more clear
- You will be using the ArrayList in a method call which requires ArrayList, possibly for optional behavior or performance characteristics
- 您依赖于 ArrayList 中可选行为 * 的实现,在这种情况下,显式使用 ArrayList 更清楚
- 您将在需要 ArrayList 的方法调用中使用 ArrayList,可能用于可选行为或性能特征
My guess is that in 99% of the cases you can get by with List, which is preferred.
我的猜测是,在 99% 的情况下,您可以使用 List,这是首选。
- for instance
removeAll
, oradd(null)
- 例如
removeAll
,或add(null)
回答by Stephen C
I am wondering if anyone uses (2)?
我想知道是否有人使用(2)?
Yes. But rarely for a sound reason (IMO).
是的。但很少出于合理的原因(IMO)。
And people get burned because they used ArrayList
when they should have used List
:
人们被烧毁是因为他们ArrayList
在应该使用的时候使用了List
:
Utility methods like
Collections.singletonList(...)
orArrays.asList(...)
don't return anArrayList
.Methods in the
List
API don't guarantee to return a list of the same type.
实用方法如
Collections.singletonList(...)
或Arrays.asList(...)
不返回ArrayList
.List
API 中的方法不保证返回相同类型的列表。
For example of someone getting burned, in https://stackoverflow.com/a/1481123/139985the poster had problems with "slicing" because ArrayList.sublist(...)
doesn't return an ArrayList
... and he had designed his code to use ArrayList
as the type of all of his list variables. He ended up "solving" the problem by copying the sublist into a new ArrayList
.
例如,有人被烧毁,在https://stackoverflow.com/a/1481123/139985 中,海报在“切片”方面存在问题,因为ArrayList.sublist(...)
没有返回ArrayList
...,他设计了自己的代码ArrayList
用作他的所有列表变量。他最终通过将子列表复制到新的ArrayList
.
The argument that you need to know how the List
behaves is largely addressed by using the RandomAccess
marker interface. Yes, it is a bit clunky, but the alternative is worse.
您需要知道List
行为方式的论点主要是通过使用RandomAccess
标记接口来解决的。是的,它有点笨重,但替代方案更糟。
Also, how often does the situation actually require using (1) over (2) (i.e. where (2) wouldn't suffice..aside 'coding to interfaces' and best practices etc.)
此外,这种情况实际上需要使用(1)而不是(2)的频率(即(2)在哪里不够......除了“编码到接口”和最佳实践等)
The "how often" part of the question is objectively unanswerable.
问题的“频率”部分客观上无法回答。
(and can I please get an example)
(我可以举个例子吗)
Occasionally, the application may require that you use methods in the ArrayList
API that are notin the List
API. For example, ensureCapacity(int)
, trimToSize()
or removeRange(int, int)
. (And the last one will only arise if you have created a subtype of ArrayList that declares the method to be public
.)
有时,应用程序可能会要求您使用ArrayList
API 中未包含在List
API 中的方法。例如,ensureCapacity(int)
、trimToSize()
或removeRange(int, int)
。(只有当您创建了 ArrayList 的子类型并将方法声明为 时,才会出现最后一个public
。)
That is the only sound reason for coding to the class rather than the interface, IMO.
这是对类而不是接口进行编码的唯一合理原因,IMO。
(It is theoretically possible that you will get a slight improvement in performance ... under certain circumstances ... on some platforms ... but unless you really need that last 0.05%, it is not worth doing this. This is not a sound reason, IMO.)
(理论上,您可能会在性能上略有提高……在某些情况下……在某些平台上……但除非您真的需要最后的 0.05%,否则不值得这样做。这不是一个合理的理由,IMO。)
You can't write efficient code if you don't know whether random access is efficient or not.
如果您不知道随机访问是否有效,您就无法编写有效的代码。
That is a valid point. However, Java provides better ways to deal with that; e.g.
这是一个有效的观点。然而,Java 提供了更好的方法来解决这个问题;例如
public <T extends List & RandomAccess> void test(T list) {
// do stuff
}
If you call that with a list that does not implement RandomAccess
you will get a compilation error.
如果您使用未实现的列表调用它,RandomAccess
您将收到编译错误。
You could also test dynamically ... using instanceof
... if static typing is too awkward. And you could even write your code to use different algorithms (dynamically) depending on whether or not a list supported random access.
instanceof
如果静态类型太笨拙,您还可以动态测试...使用...。您甚至可以编写代码以使用不同的算法(动态),具体取决于列表是否支持随机访问。
Note that ArrayList
is not the only list class that implements RandomAccess
. Others include CopyOnWriteList
, Stack
and Vector
.
请注意,这ArrayList
不是唯一实现RandomAccess
. 其他包括CopyOnWriteList
、Stack
和Vector
。
I've seen people make the same argument about Serializable
(because List
doesn't implement it) ... but the approach above solves this problem too. (To the extent that it is solvable at allusing runtime types. An ArrayList
will fail serialization if any element is not serializable.)
我见过人们对Serializable
(因为List
没有实现它)提出同样的论点……但上述方法也解决了这个问题。(就其完全可以使用运行时类型解决而言。ArrayList
如果任何元素不可序列化,An将无法序列化。)
回答by Pavel Vyazankin
(3) Collection myCollection = new ArrayList();
(3) Collection myCollection = new ArrayList();
I am using this typically. And onlyif I need List methods, I will use List. Same with ArrayList. You always can switch to more "narrow" interface, but you can't switch to more "wide".
我通常使用这个。而只有当我需要列出方法,我将使用清单。与 ArrayList 相同。你总是可以切换到更“窄”的界面,但你不能切换到更“宽”的界面。
回答by Hans Westerbeek
The only case that I am aware of where (2) can bebetter is when using GWT, because it reduces application footprint (not my idea, but the google web toolkit team says so). But for regular java running inside the JVM (1) is probably always better.
唯一的情况下,我知道在哪里(2)可以更好地使用GWT时,因为它减少了应用程序的足迹(不是我的主意,但谷歌Web Toolkit的团队是这么说的)。但是对于在 JVM 中运行的常规 java (1) 可能总是更好。
回答by True Soft
I think the people who use (2) don't know the Liskov substitution principleor the Dependency inversion principle. Or they really have to use ArrayList
.
我认为使用 (2) 的人不知道Liskov 替换原则或依赖倒置原则。或者他们真的必须使用ArrayList
.
回答by mazatwork
I use (2) if code is the "owner" of the list. This is for example true for local-only variables. There is no reason to use the abstract type List
instead of ArrayList
.
Another example to demonstrate ownership:
如果代码是列表的“所有者”,我使用 (2)。例如,这对于仅本地变量是正确的。没有理由使用抽象类型List
而不是ArrayList
. 另一个证明所有权的例子:
public class Test {
// This object is the owner of strings, so use the concrete type.
private final ArrayList<String> strings = new ArrayList<>();
// This object uses the argument but doesn't own it, so use abstract type.
public void addStrings(List<String> add) {
strings.addAll(add);
}
// Here we return the list but we do not give ownership away, so use abstract type. This also allows to create optionally an unmodifiable list.
public List<String> getStrings() {
return Collections.unmodifiableList(strings);
}
// Here we create a new list and give ownership to the caller. Use concrete type.
public ArrayList<String> getStringsCopy() {
return new ArrayList<>(strings);
}
}
回答by nazar_art
It is considered good styleto store a reference to a HashSet
or TreeSet
in a variable of type Set.
在 Set 类型的变量中存储对 a或的引用被认为是一种很好的风格。HashSet
TreeSet
Set<String> names = new HashSet<String>();
Set<String> names = new HashSet<String>();
This way, you have to change only one line if you decide to use a TreeSet
instead.
这样,如果您决定使用 aTreeSet
代替,则只需更改一行。
Also, methods that operate on sets should specify parameters of type Set:
此外,对集合进行操作的方法应指定 Set 类型的参数:
public static void print(Set<String> s)
public static void print(Set<String> s)
Then the method can be used for all set implementations.
然后该方法可用于所有集合实现。
In theory, we should make the same recommendation for linked lists, namely to save
LinkedList references in variables of type List. However, in the Java library, the List interface is common to both the ArrayList
and the LinkedList
class. In particular, it has get and set methods for random access, even though these methods are very inefficient for linked lists.
理论上,我们应该对链表做出同样的建议,即将 LinkedList 引用保存在 List 类型的变量中。但是,在 Java 库中,List 接口对于ArrayList
和LinkedList
类都是通用的。特别是,它具有用于随机访问的 get 和 set 方法,尽管这些方法对于链表非常低效。
You can't write efficient codeif you don't know whether random access is efficient or not.
如果您不知道随机访问是否有效,您就无法编写有效的代码。
This is plainly a serious design error in the standard library, and I cannot recommend using the List interface for that reason.
这显然是标准库中的严重设计错误,因此我不建议使用 List 接口。
To see just how embarrassing that error is, have a look at
the source code for the binarySearch
method of the Collectionsclass. That method takes a
List parameter, but binary search makes no sense for a linked list. The code then clumsily
tries to discover whether the list is a linked list, and then switches to a linear search!
要了解该错误有多么令人尴尬,请查看Collections类binarySearch
方法的源代码。该方法采用 List 参数,但二分查找对于链表没有意义。然后代码笨拙地尝试发现列表是否是链表,然后切换到线性搜索!
The Set
interface and the Map
interface, are well designed, and you should use them.
在Set
接口和Map
接口,都是精心设计的,你应该使用它们。
回答by Denis Kutlubaev
When you write List
, you actually tell, that your object implements List
interface only, but you don't specify what class your object belongs to.
当你写的时候List
,你实际上告诉你,你的对象List
只实现了接口,但你没有指定你的对象属于哪个类。
When you write ArrayList
, you specify that your object class is a resizable-array.
当您编写 时ArrayList
,您指定您的对象类是一个可调整大小的数组。
So, the first version makes your code more flexible in future.
因此,第一个版本使您的代码在未来更加灵活。
Look at Java docs:
查看 Java 文档:
Class ArrayList
- Resizable-array implementation of the List
interface.
类ArrayList
-List
接口的可调整大小的数组实现。
Interface List
- An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted.
接口List
- 有序集合(也称为序列)。此界面的用户可以精确控制每个元素在列表中的插入位置。
Array
- container object that holds a fixed number of values of a single type.
Array
- 包含固定数量的单一类型值的容器对象。
回答by Maxim Shoustin
For example you might decide a LinkedList
is the best choice for your application, but then later decide ArrayList
might be a better choice for performance reason.
例如,您可能会决定 aLinkedList
是您的应用程序的最佳选择,但后来ArrayList
出于性能原因决定可能是更好的选择。
Use:
用:
List list = new ArrayList(100); // will be better also to set the initial capacity of a collection
Instead of:
代替:
ArrayList list = new ArrayList();
For reference:
以供参考:
(posted mostly for Collection diagram)
(主要用于集合图)