Java中的ArrayList或List声明


73

这两个声明之间有什么区别?

宣言1:

ArrayList<String> arrayList = new ArrayList<String>();

宣言2:

List<String> arrayList = new ArrayList<String>();




1
汤姆

Answers:


66
List<String> arrayList = new ArrayList<String>();

这是通用的,您想在将实现细节返回给客户端时隐藏实现细节,以后可以将实现从透明地更改ArrayListLinkedList

在设计库等的情况下,此机制很有用,这些库可能会在某些时间点更改其实现详细信息,而在客户端进行的更改最少。

ArrayList<String> arrayList = new ArrayList<String>();

这是您始终需要返回的命令ArrayList。在某些时候,如果您想将实现细节更改为LinkedList,也应该在客户端进行更改以LinkedList代替ArrayList


3
并且不要忘记Collections类完全与List接口一起使用,因此诸如Collections.emptyList,Collections.synchronizedList,Collections.unmodifiableList之类的东西都将返回List。因此,如果API期望使用ArrayList,那么如果您想使用这些方法包装现有列表,那将很不走运。
马特

对于输入参数,我同意,但这是相反的。即对象实例化。在这种情况下,它唯一要做的就是删除所有应该可用的特定于ArrayList的函数。
Nyerguds

顺便说一句,“此命令您始终需要返回ArrayList”是完全错误的。List无论您内部使用什么,都可以完美地使返回类型正确。
Nyerguds

15

List是一个接口,并且ArrayList是List接口的实现。该ArrayList班只有几个方法(i.e clone(), trimToSize(), removeRange() and ensureCapacity())除了在列表界面中可用的方法。这没有太大的区别。

   1. List<String> l = new ArrayList<>();
   2. ArrayList<String> l = new ArrayList<>();

如果使用第一个,则将能够调用List界面中可用的方法,并且无法调用ArrayList该类中可用的新方法。ArrayList如果您使用第二种方法,则可以自由使用的所有可用方法。

我会说第一种方法是一种更好的方法,因为在开发Java应用程序时,当您应该将集合框架对象作为方法的参数传递时,则最好采用第一种方法。

List<String> l = new ArrayList<>();
doSomething(l);

将来由于性能限制,如果您要更改实现以使用LinkedList或其他实现List接口的类,而不是ArrayList,则只需在一点上更改(实例化部分)。

List<String> l = new LinkedList<>();

否则,无论您在何处使用特定的类实现作为方法参数,都应该在所有地方进行更改。


您能否详细说明为什么使用第一个选项使我们所做的更改超出了声明行?
TheLogicGuy

人们为什么不断传播愚蠢的“以后可以更改”的说法?如果设计得好,那应该永远是例外,而不是规则。唯一的实际效果是,您失去ArrayListList基本功能以外的所有可用功能。
Nyerguds

9

不同之处在于,变体1迫使您使用ArrayList而变体2仅保证您拥有实现的任何东西List<String>

稍后,您可以将其更改为List<String> arrayList = new LinkedList<String>();没有太多麻烦。变体1可能要求您不仅更改该行,而且如果其他部分依赖于使用ArrayList<String>

因此List<String>,几乎在任何情况下都可以使用,除非需要调用提供的其他方法ArrayList(到目前为止从来没有这样):ensureCapacity(int)trimToSize()


4

第一个声明必须是ArrayList,第二个声明可以轻松更改为其他List类型。因此,首选第二个,因为它可以清楚地表明您不需要特定的实现。(有时确实需要一种实现,但这很少见)


好吧,当速度是焦点时,第二个不是首选:-pinvokeinterface可能比慢一点invokevirtual,这在某些情况下可能很重要。
obataku 2012年

3

基本上,它允许Java通过通用类型声明(如class MyStructure<T extends TT>)在一个结构实现中存储几种类型的对象,这是Java的主要功能之一。

面向对象的方法基于关注点分离的模块化和可重用性-将结构与任何类型的对象一起使用的能力(只要遵循一些规则)。

您可以按照以下方式实例化:

ArrayList list = new ArrayList();

代替

ArrayList<String> list = new ArrayList<>();

通过声明和使用泛型类型,您可以将其要管理的对象类型通知结构,例如,如果您要向该结构中插入非法类型,则编译器将能够通知您。比方说:

// this works
List list1 = new ArrayList();
list1.add(1);
list1.add("one");

// does not work
List<String> list2 = new ArrayList<>();
list2.add(1); // compiler error here
list2.add("one");

如果您想查看一些示例,请查阅文档文档

/**
 * Generic version of the Box class.
 * @param <T> the type of the value being boxed
 */
public class Box<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

然后,您可以实例化以下内容:

class Paper  { ... }
class Tissue { ... }

// ...
Box<Paper> boxOfPaper = new Box<>();
boxOfPaper.set(new Paper(...));

Box<Tissue> boxOfTissues = new Box<>();
boxOfTissues.set(new Tissue(...));

从中得出的主要内容是,您要指定要装箱的对象类型。

至于使用Object l = new ArrayList<>();,您不会访问ListArrayList实现,因此您将无法对该集合做很多事情。


3

易于将实现更改ListSet

Collection<String> stringList = new ArrayList<String>();
//Client side
stringList = new LinkedList<String>();

stringList = new HashSet<String>();
//stringList = new HashSet<>(); java 1.7 and 1.8

1

在某些情况下,例如在某些没有JIT编译器的JVM上,您可能更喜欢第一种(稍微)提高性能。

出于这种非常特定的上下文,您应该使用第一个。


1

可能您可以参考此链接 http://docs.oracle.com/javase/6/docs/api/java/util/List.html

List是一个接口。ArrayList,LinkedList等是实现list的类。使用List接口时,必须使用ListIterator来逐元素化,并且可以向前和向后移动,在List中,如在ArrayList中使用Iterator迭代和其元素可以是访问单向方式。


1

List是接口,而ArrayList是实现的具体类。始终建议使用。

List<String> arrayList = new ArrayList<String>();

因为这里列表引用是灵活的。它也可以容纳LinkedList or Vector物体。


0

每当您看到来自Guava之类的开源社区和Google Developer(Android库)的编码时,他们就使用这种方法

List<String> strings = new ArrayList<String>();

因为它对用户隐藏了实现细节。你就是

List<String> strings = new ArrayList<String>(); 

这是通用方法,也是这种专门方法

ArrayList<String> strings = new ArrayList<String>();

供参考:有效的Java 2nd Edition:项目52:通过其接口引用对象

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.