77

这两个声明有什么区别?

声明一:

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

声明 2:

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

10 回答 10

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

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

这种机制在您设计库等的情况下很有用,这可能会在某个时间点更改它们的实现细节,而客户端的更改最少。

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

这要求您始终需要返回ArrayList。在某个时间点,如果您想将实现细节更改为LinkedList,客户端也应该进行更改以使用LinkedList而不是ArrayList.

于 2012-09-07T15:32:58.687 回答
16

List是一个接口,ArrayList是 List 接口的一个实现。除了 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<>();

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

于 2015-04-23T09:03:45.310 回答
9

不同之处在于变体 1 强制你使用ArrayListwhile 变体 2 只保证你有任何实现的东西List<String>

稍后您可以轻松地将其更改为List<String> arrayList = new LinkedList<String>();。变体 1 可能不仅需要更改该行,还需要更改其他部分(如果它们依赖于使用ArrayList<String>.

因此,我List<String>几乎在任何情况下都会使用,除非我需要调用ArrayList提供的附加方法(迄今为止从未如此):ensureCapacity(int)trimToSize().

于 2012-09-07T15:33:51.963 回答
4

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

于 2012-09-07T15:34:13.710 回答
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(...));

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

至于 using Object l = new ArrayList<>();,您没有访问ListorArrayList实现,因此您无法对集合做太多事情。

于 2015-04-23T08:36:42.717 回答
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
于 2015-03-11T11:42:22.183 回答
1

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

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

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

于 2012-09-07T15:33:32.723 回答
1

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

在那种非常具体的上下文中,您应该使用第一个。

于 2012-09-07T15:36:32.573 回答
1

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

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

于 2012-09-07T15:39:47.147 回答
0

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

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

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

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

这是通用方法和这种专门的方法

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

供参考:Effective Java 2nd Edition:Item 52:通过接口引用对象

于 2016-05-27T18:18:12.050 回答