原因 - List list = new ArrayList(); [复制]

Posted

技术标签:

【中文标题】原因 - List list = new ArrayList(); [复制]【英文标题】:Reason for - List list = new ArrayList(); [duplicate] 【发布时间】:2013-08-22 03:58:14 【问题描述】:

这样的代码我见过很多次了:

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

为什么人们取ArrayList(和其他类)的父类而不是生成对象的类型?

这会降低性能吗?或者为什么有人要这样做?

【问题讨论】:

对“性能”的执着是什么? 90% 的时间,这是编写代码中最不重要的方面! ***.com/questions/383947/… 你也可以看看这个:***.com/questions/17459553/… 如果我在程序中看不到某件事的原因,我还应该问什么?我不会说获取父引用会为您提供更“可读”的代码。 :) 但现在我有了答案,谢谢大家。 @TrudleR:它传达意图:List x = new ArrayList() 意味着您实际上并不需要 ArrayList 的任何特殊功能,您“承诺”“仅”使用 @987654327 公开的功能@ 界面。更进一步的是Collection x = new ArrayList() 甚至Iterable x = new ArrayList() 【参考方案1】:

当有人编写这样的代码时,他/她正在尝试遵循基本的 OO 设计原则,即 -

编程到接口,而不是具体实现

我已经在one of my blog posts 中解释了这个原理。查看Class Inheritance VS Interface Inheritance 部分。

总结这篇文章,当您使用父类型的引用来引用子类型的实例时,您会获得很大的灵活性。例如,如果您将来需要更改子类型的实现,您将能够轻松地做到这一点,而无需更改大部分代码。

考虑以下方法 -

public void DoSomeStuff(Super s) 
    s.someMethod();

以及对该方法的调用 -

DoSomeStuff(new Sub());

现在,如果您需要更改 someMethod 中的逻辑,您可以轻松地通过声明 Super 的新子类型(例如 NewSubType)并更改该实现中的逻辑来实现。这样,您将永远不必接触使用该方法的其他现有代码。您仍然可以通过以下方式使用您的 DoSomeStuff 方法 -

DoSomeStuff(new NewSubType());

如果您将DoSomeStuff 的参数声明为Sub,那么您也必须更改其实现 -

DoSomeStuff(NewSubType s) 
    s.someMethod();

它也可能链接/冒泡到其他几个地方。

就您的集合示例而言,这使您可以轻松更改变量指向的列表实现。您可以轻松地使用LinkedList 代替ArrayList

【讨论】:

“编程到一个接口,而不是一个具体的实现”是一个很好的建议。然而,做List<String> list = new ArrayList<String>(); 并不是一个真正的论据,因为a)由于构造函数,这段代码仍然与ArrayList 绑定,b)它更多的是关于API 设计而不是私有实现。这是您从一开始就学习的 java 东西之一,这并不合理。通常,实现提供了一些细节,如果你坚持使用接口,你将永远看不到这些细节。当然,答案仍然很好。 (+1) 但是,他的论点仍然成立。您可以通过更改参数来交换功能。这支持几个不错的代码特性,例如依赖注入、松散耦合和可替换性。 @atamanroman:该原则的结果鼓励您根据其接口来引用具体实例。这就是为什么我认为它在这里很重要。 @Chris:完全同意你的看法。 在原问题中,没有论据。只有List<Foo> l = new ArrayList<Foo>(); 如果实现改变,那一行就会改变。如果是ArrayList<Foo> l = new ArrayList<Foo>();,就不会有什么不同。如果列表是外部依赖项(以某种方式注入),整个情况就会改变。在这种情况下,对接口进行编程会有所作为,强烈推荐。【参考方案2】:

当你写作时:

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

那么你确定你只会使用接口List的功能。(ArrayList实现List,所以List更灵活)。 使用它,您可以在将来将ArrayList 更改为其他类型(如LinkedList..)。

【讨论】:

谢谢。这真的很有帮助【参考方案3】:

这意味着您可以随时将list 的类型替换为任何实现List 接口的东西,而不是创建一个只能使用ArrayList 的刚性模型。例如:

private List<String> list;

public SomeConstructor()

     // At this point, you can make it any type of object you want.
     list = new ArrayList<String>();
     list = new LinkedList<String>();
     list = new AttributeList<String>();

这将abstract 使用list 对象的代码,远离诸如list 的确切对象类型之类的细节。它只需要知道它有add 方法等。这称为Loose Coupling。

【讨论】:

【参考方案4】:

整理一下:

为了获得更大的灵活性,您可以启动接口List

因此,如果您不需要所有 ArrayList,请仅使用 List

你可以这样写:List&lt;String&gt; = Arrays.asList("aa", "bb","cc")

当然,较少的功能有助于提高性能。如您所知,如果您想使用多线程应用程序,请改用Vector,但这会降低您的性能。

取自here

【讨论】:

wilsonmar.com/1arrays.htm @Maxim Shoustin:好照片!这是否意味着我应该将“AbstractMap”作为所有地图集合对象的参考? @TrudleR: 不,AbstractMap 是一个你永远不应该真正关心的实现细节:你要么使用Map接口引用地图或 更具体的接口(如NavigableMap)。在极少数情况下,您可能需要特定的实现类型,但 AbstractMap 本身很少被任何人引用,除非他们扩展它。【参考方案5】:

因为方法不必知道您使用什么列表实现。

一个方法只需要知道它是一个列表。

该方法仍然可以使用。

始终针对接口进行编程,而不是针对具体实现进行编程。 (本例为列表)

【讨论】:

【参考方案6】:

通常,最好使用接口类(在这种情况下为List),以便以后在需求发生变化时可以用最小的麻烦来替换任何 List 实现。

虽然ArrayList 可能支持List 接口上不存在的一些方法,但此声明清楚地表明这些额外的方法在这种情况下不相关。

【讨论】:

【参考方案7】:
List<String> list = new ArrayList<String>();

在集合框架中List 是一个接口,而ArrayList 是实现。您这样做的主要原因是将您的代码与接口的特定implementation 分离,如果您将来希望转移到List 的其他实现,这将很有帮助。

【讨论】:

以上是关于原因 - List list = new ArrayList(); [复制]的主要内容,如果未能解决你的问题,请参考以下文章

集合类框架_List相关知识

java 多态性:为什么使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [重复]

列表生成器

多态性:为啥使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [复制]

为啥是List list = new ArrayList,而不直接用ArrayList

PHP中的list(),each(),reset()函数应用