原因 - 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<String> = 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(); [复制]的主要内容,如果未能解决你的问题,请参考以下文章
java 多态性:为什么使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [重复]
多态性:为啥使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [复制]