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

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

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?


Solution 1:

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.

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,

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.

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.

Solution 2:

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().

Solution 3:

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,

public List getList();

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

Solution 4:

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:

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.

Hope that helps!

Solution 5:

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

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