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

Posted

技术标签:

【中文标题】多态性:为啥使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [复制]【英文标题】:Polymorphism: Why use "List list = new ArrayList" instead of "ArrayList list = new ArrayList"? [duplicate]多态性:为什么使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [复制] 【发布时间】:2012-04-08 19:37:26 【问题描述】:

可能重复:Why should the interface for a Java class be prefered?

我应该什么时候使用

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

ArrayList继承自List,所以如果ArrayList中的某些功能不在List中,那么我将失去ArrayList的一些功能,对吧?并且编译器在尝试访问这些方法时会注意到错误?

【问题讨论】:

哦。对不起。因为我换成object,所以忘记了。 @duffymo - 这个问题是问为什么new List&lt;Object&gt;() 不起作用。这是一个完全不同的问题。 这不是一个重复的问题。可能的重复有一般性问题,但有具体细节。我发现标题中的这个问题与实际提出的问题更相关/更同步。 还有一个疑问guyz:“List list = new ArrayList();”将允许您仅访问 Arraylist 中的 List 接口的函数(因此我们不能使用 Arraylist 函数)。 "列表 列表 = 新的 LinkedList();"将允许您在 Linkedlist 中仅访问 List 接口的函数(因此我们不能使用 LinkedList 函数)。那么两者不一样吗?还是只是“时间复杂度”的不同? 如果可以,请使用Iterable。基本上,您希望使用最受限制、最窄的类型来记录变量的使用情况,然后再使用它。这更容易理解。这是主要原因。 【参考方案1】:

您这样做的主要原因是将您的代码与接口的特定实现分离。当您像这样编写代码时:

List list = new ArrayList();  

您的其余代码只知道数据是List 类型,这是更可取的,因为它允许您轻松地在List 接口的不同实现之间切换。

例如,假设您正在编写一个相当大的第 3 方库,并说您决定使用 LinkedList 来实现库的核心。如果你的库严重依赖访问这些列表中的元素,那么最终你会发现你做出了一个糟糕的设计决定;你会意识到你应该使用ArrayList(它提供 O(1) 访问时间)而不是 LinkedList(它提供 O(n) 访问时间)。假设您一直在对接口进行编程,那么进行这样的更改很容易。您只需将 List 的实例更改为,

List list = new LinkedList();

List list = new ArrayList();  

并且您知道这将起作用,因为您已经编写了代码以遵循List 接口提供的合同。

另一方面,如果您使用 LinkedList list = new LinkedList() 实现了库的核心,那么进行这样的更改就不会那么容易了,因为不能保证您的其余代码不会使用特定于 LinkedList 类的方法。

总而言之,选择只是设计问题...但是这种设计非常重要(尤其是在处理大型项目时),因为它允许您稍后进行特定于实现的更改而不会破坏现有的代码。

【讨论】:

很多人没有提到通过 ArrayList list = new ArrayList() 将其实例化为局部变量是完全可以接受的。只有在方法签名中使用 List 接口或作为类级别变量的类型才真正有益。谁在乎您是否必须稍后返回并更改本地方法声明?将 List 暴露给其他方法或库等时,整个好处就来了。 确实如此,感谢您指出这一点。事实上,现在我想起来,我从客户的角度而不是程序员本人的角度来举一个例子可能更有意义。在这两种情况下,使用List list = new ArrayList() 是为了确保您不会破坏现有代码。 @Zahan Safallwa List 的方法,或者你可以稍后通过向下转换来访问 ArrayList 的方法 你对 ArrayList 的list.removeRange(); 有什么看法?它迫使我将列表转换为 ArrayList 使用。与 LinkedList 的一些方法相同。 不做List al = new ArrayList()会让你失去一些可能与al一起使用的ArrayList功能?【参考方案2】:

这称为接口编程。如果您希望将来迁移到 List 的其他一些实现,这将很有帮助。如果你想要ArrayList 中的一些方法,那么你需要对ArrayList a = new ArrayList() 的实现进行编程。

【讨论】:

【参考方案3】:

这在公开公共接口时也很有帮助。如果你有这样的方法,

public ArrayList getList();

那你决定改成,

public LinkedList getList();

使用ArrayList list = yourClass.getList() 的任何人都需要更改他们的代码。另一方面,如果你这样做了,

public List getList();

更改实现不会为您的 API 用户带来任何改变。

【讨论】:

yourClass.getList() 我想这是我遇到的最实际的用例。非常感谢:)【参考方案4】:

我认为@tsatiz 的回答大部分是正确的(编程到接口而不是实现)。但是,通过对界面进行编程,您不会失去任何功能。让我解释。 如果您将变量声明为List&lt;type&gt; list = new ArrayList&lt;type&gt;,您实际上并没有失去ArrayList 的任何 功能。您需要做的就是将您的list 转换为ArrayList。这是一个例子:

List<String> list = new ArrayList<String>();
((ArrayList<String>) list).ensureCapacity(19);

最终,我认为 tsatiz 是正确的,因为一旦您转换为 ArrayList,您就不再需要对接口进行编码。但是,最初对接口进行编码仍然是一种很好的做法,如果以后有必要,再对实现进行编码。

希望有帮助!

【讨论】:

我真的不喜欢这个答案。如果您使用的是 ArrayList 方法,那么您应该将其定义为 ArrayList。如果有人去更改列表实现,他们肯定会对编译失败感到惊讶。 如果看起来有点草率,按照答案建议的操作在技术上是可以的,因为 List 是一个 ArrayList 的知识是函数本地的,并且从前一行显而易见。但是,将 ArrayList 作为 List 返回并在另一个函数中进行强制转换是一个糟糕的选择,因为这会违反接口编程的整个要点。【参考方案5】:

这使您可以编写如下内容:

void doSomething() 
    List<String>list = new ArrayList<String>();
    //do something

稍后,您可能希望将其更改为:

void doSomething() 
    List<String>list = new LinkedList<String>();
    //do something

无需更改方法的其余部分。

但是,例如,如果您想使用 CopyOnWriteArrayList,则需要将其声明为这样,而不是 List如果您想使用它的额外方法(例如 addIfAbsent ):

void doSomething() 
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();
    //do something, for example:
    list.addIfAbsent("abc");

【讨论】:

根据接受答案的@GreenieMeanie 评论,此更改无关紧要,因为这是一个局部变量。【参考方案6】:

我猜你问题的核心是为什么要program to an interface, not to an implementation

仅仅是因为接口给了你更多的抽象,并使代码 更灵活、更有弹性地应对变化,因为您可以使用不同的 相同接口的实现(在这种情况下,您可能希望将 List 实现更改为 linkedList 而不是 ArrayList )而不更改其客户端。

【讨论】:

【参考方案7】:

每当我不想增加问题的复杂性时,我都会使用这种结构。它只是一个列表,不需要说它是什么样的列表,因为它与问题无关。我经常在我的大多数解决方案中使用 Collection,因为最后,大多数时候,对于软件的其余部分,真正重要的是它包含的内容,我不想向 Collection 添加新对象.

此外,当您认为您可能想要更改您正在使用的列表的实现时,您会使用该结构。假设您正在使用带有 ArrayList 的构造,并且您的问题不是线程安全的。现在,您想让它成为线程安全的,例如,对于您的解决方案的一部分,您更改为使用 Vector。至于该列表的其他用途,不管是AraryList还是Vector,只是一个List,不需要新的修改。

【讨论】:

【参考方案8】:

一般来说,您希望针对接口进行编程。这使您可以随时交换实现。 这非常有用,尤其是当您通过了一个您不知道的实现时。

但是,在某些情况下,您更喜欢使用具体实现。 例如在 GWT 中序列化时。

【讨论】:

以上是关于多态性:为啥使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

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

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

Python中对列表list去重

Python中对列表list去重

Python中对列表list去重

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