Java 多态性:为什么使用“List list = new ArrayList”而不是“ArrayList list = new ArrayList”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9852831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 12:21:15  来源:igfitidea点击:

Polymorphism: Why use "List list = new ArrayList" instead of "ArrayList list = new ArrayList"?

javalistinterfacepolymorphism

提问by hqt

Possible Duplicate:
Why should the interface for a Java class be prefered?

可能的重复:
为什么应该首选 Java 类的接口?

When should I use

我应该什么时候使用

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

ArrayListinherits from List, so if some features in ArrayListaren't in List, then I will have lost some of the features of ArrayList, right? And the compiler will notice an error when trying to access these methods?

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

采纳答案by Alex Lockwood

The main reason you'd do this is to decouple your code from a specific implementation of the interface. When you write your code like this:

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

List list = new ArrayList();  

the rest of your code only knows that data is of type List, which is preferable because it allows you to switch between different implementations of the Listinterface with ease.

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

For instance, say you were writing a fairly large 3rd party library, and say that you decided to implement the core of your library with a LinkedList. If your library relies heavily on accessing elements in these lists, then eventually you'll find that you've made a poor design decision; you'll realize that you should have used an ArrayList(which gives O(1) access time) instead of a LinkedList(which gives O(n) access time). Assuming you have been programming to an interface, making such a change is easy. You would simply change the instance of Listfrom,

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

List list = new LinkedList();

to

List list = new ArrayList();  

and you know that this will work because you have written your code to follow the contract provided by the Listinterface.

并且您知道这会起作用,因为您已经编写了代码来遵循List接口提供的契约。

On the other hand, if you had implemented the core of your library using LinkedList list = new LinkedList(), making such a change wouldn't be as easy, as there is no guarantee that the rest of your code doesn't make use of methods specific to the LinkedListclass.

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

All in all, the choice is simply a matter of design... but this kind of design is very important (especially when working on large projects), as it will allow you to make implementation-specific changes later without breaking existing code.

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

回答by tsatiz

This is called programming to interface. This will be helpful in case if you wish to move to some other implementation of List in the future. If you want some methods in ArrayListthen you would need to program to the implementation that is ArrayList a = new ArrayList().

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

回答by assylias

This enables you to write something like:

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

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

Later on, you might want to change it to:

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

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

without having to change the rest of the method.

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

However, if you want to use a CopyOnWriteArrayListfor example, you would need to declare it as such, and not as a List if you wanted to use its extra methods(addIfAbsent for example):

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

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

回答by SHiRKiT

I use that construction whenever I don't want to add complexity to the problem. It's just a list, no need to say what kind of List it is, as it doesn't matter to the problem. I often use Collection for most of my solutions, as, in the end, most of the times, for the rest of the software, what really matters is the content it holds, and I don't want to add new objects to the Collection.

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

Futhermore, you use that construction when you think that you may want to change the implemenation of list you are using. Let's say you were using the construction with an ArrayList, and your problem wasn't thread safe. Now, you want to make it thread safe, and for part of your solution, you change to use a Vector, for example. As for the other uses of that list won't matter if it's a AraryList or a Vector, just a List, no new modifications will be needed.

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

回答by stefan bachert

In general you want to program against an interface. This allows you to exchange the implementation at any time. This is very useful especially when you get passed an implementation you don't know.

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

However, there are certain situations where you prefer to use the concrete implementation. For example when serialize in GWT.

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

回答by Brendan Long

This is also helpful when exposing a public interface. If you have a method like this,

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

public ArrayList getList();

Then you decide to change it to,

然后你决定把它改成,

public LinkedList getList();

Anyone who was doing ArrayList list = yourClass.getList()will need to change their code. On the other hand, if you do,

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

public List getList();

Changing the implementation doesn't change anything for the users of your API.

更改实现不会改变 API 用户的任何内容。

回答by Mouna Cheikhna

I guess the core of your question is why to program to an interface, not to an implementation

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

Simply because an interface gives you more abstraction, and makes the code more flexible and resilient to changes, because you can use different implementations of the same interface(in this case you may want to change your List implementation to a linkedList instead of an ArrayList ) without changing its client.

仅仅因为接口为您提供了更多抽象,并使代码更灵活和更灵活,因为您可以使用同一接口的不同实现(在这种情况下,您可能希望将 List 实现更改为 linkedList 而不是 ArrayList )无需更改其客户端。

回答by SecondSun24

I think @tsatiz's answer is mostly right (programming to an interface rather than an implementation). However, by programming to the interface you won't lose any functionality. Let me explain.

If you declare your variable as a List<type> list = new ArrayList<type>you do not actually lose anyfunctionality of the ArrayList. All you need to do is to cast your listdown to an ArrayList. Here's an example:

我认为@tsatiz 的答案大部分是正确的(编程到接口而不是实现)。但是,通过对接口编程,您不会丢失任何功能。让我解释。

如果您将变量声明为 a,List<type> list = new ArrayList<type>您实际上不会失去ArrayList 的任何功能。您需要做的就是将您的内容list转换为ArrayList. 下面是一个例子:

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

Ultimately I think tsatiz is correct as once you cast to an ArrayList you're no longer coding to an interface. However, it's still a good practice to initially code to an interface and, if it later becomes necessary, code to an implementation if you must.

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

Hope that helps!

希望有帮助!