多态性:为什么使用“List List List = new ArrayList”而不是“ArrayList List = new ArrayList”?(复制)

时间:2021-07-20 04:18:50

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

可能的重复:为什么应该优先使用Java类的接口?

When should I use

当我应该使用

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

ArrayList inherits from List, so if some features in ArrayList aren'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的一些特性,对吧?编译器在尝试访问这些方法时会注意到错误吗?

8 个解决方案

#1


214  

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 List interface with ease.

其余的代码只知道数据是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 List from,

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

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 List interface.

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

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 LinkedList class.

另一方面,如果您使用LinkedList = 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.

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

#2


63  

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 ArrayList then you would need to program to the implementation that is ArrayList a = new ArrayList().

这叫做接口编程。如果您希望在将来实现列表的其他实现,这将是很有帮助的。如果您希望在ArrayList中有一些方法,那么您将需要对ArrayList a = new ArrayList()的实现进行编程。

#3


18  

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 = yourClass.getList()的人都需要修改他们的代码。另一方面,如果你这样做,

public List getList();

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

对API的用户来说,更改实现不会改变任何东西。

#4


9  

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 any functionality of the ArrayList. All you need to do is to cast your list down to an ArrayList. Here's an example:

我认为@tsatiz的答案大部分是正确的(编程接口而不是实现)。但是,通过对接口的编程,您不会丢失任何功能。让我解释一下。如果将变量声明为List List = new ArrayList ,那么实际上不会丢失ArrayList的任何功能。你所需要做的就是把你的列表放到一个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!

希望会有帮助!

#5


6  

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 CopyOnWriteArrayList for 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):

但是,如果你想要使用CopyOnWriteArrayList,你需要这样声明它,如果你想使用它的额外方法,你需要不声明它的列表(例如addifabsend):

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

#6


5  

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作为我的大多数解决方案,最后,大多数时候,对于软件的其余部分,真正重要的是它所包含的内容,我不想向集合添加新对象。

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的构造,你的问题不是线程安全的。现在,您想要使它成为线程安全的,并且对于您的部分解决方案,您需要更改为使用一个向量,例如。至于列表的其他用途,不管它是AraryList还是Vector,只要一个列表,都不需要任何新的修改。

#7


4  

I guess the core of your question is why to 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.

简单地说,因为接口提供了更多的抽象,并且使代码更灵活,更能适应变化,因为您可以使用相同接口的不同实现(在本例中,您可能希望将您的列表实现改为linkedList而不是ArrayList),而不需要更改它的客户端。

#8


2  

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中序列化时。

#1


214  

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 List interface with ease.

其余的代码只知道数据是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 List from,

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

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 List interface.

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

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 LinkedList class.

另一方面,如果您使用LinkedList = 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.

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

#2


63  

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 ArrayList then you would need to program to the implementation that is ArrayList a = new ArrayList().

这叫做接口编程。如果您希望在将来实现列表的其他实现,这将是很有帮助的。如果您希望在ArrayList中有一些方法,那么您将需要对ArrayList a = new ArrayList()的实现进行编程。

#3


18  

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 = yourClass.getList()的人都需要修改他们的代码。另一方面,如果你这样做,

public List getList();

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

对API的用户来说,更改实现不会改变任何东西。

#4


9  

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 any functionality of the ArrayList. All you need to do is to cast your list down to an ArrayList. Here's an example:

我认为@tsatiz的答案大部分是正确的(编程接口而不是实现)。但是,通过对接口的编程,您不会丢失任何功能。让我解释一下。如果将变量声明为List List = new ArrayList ,那么实际上不会丢失ArrayList的任何功能。你所需要做的就是把你的列表放到一个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!

希望会有帮助!

#5


6  

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 CopyOnWriteArrayList for 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):

但是,如果你想要使用CopyOnWriteArrayList,你需要这样声明它,如果你想使用它的额外方法,你需要不声明它的列表(例如addifabsend):

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

#6


5  

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作为我的大多数解决方案,最后,大多数时候,对于软件的其余部分,真正重要的是它所包含的内容,我不想向集合添加新对象。

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的构造,你的问题不是线程安全的。现在,您想要使它成为线程安全的,并且对于您的部分解决方案,您需要更改为使用一个向量,例如。至于列表的其他用途,不管它是AraryList还是Vector,只要一个列表,都不需要任何新的修改。

#7


4  

I guess the core of your question is why to 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.

简单地说,因为接口提供了更多的抽象,并且使代码更灵活,更能适应变化,因为您可以使用相同接口的不同实现(在本例中,您可能希望将您的列表实现改为linkedList而不是ArrayList),而不需要更改它的客户端。

#8


2  

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中序列化时。