Reading other people\'s code, I\'ve seen a lot of:
List ints = new ArrayList();
Map map = new HashMap();
@Bhushan answered why. To answer your confusion Why nobody uses
CharSequence s = new String("String");
or
OutputStream out = new PrintStream(OutputStream);
CharSequence
contains only few common methods. Other classes that implement this interface are mostly buffers and only String
is immutable. CharSequence
defines common api for classes backed by char array and This interface does not refine the general contracts of the equals and hashCode methods (see javadoc).
OutputStream
is low-level api for writing data. Because PrintStream
adds extra convenient methods for writing - higher level of abstraction, it's used over OutputStream.
This (good) style of declaring the type as the Interface
the class implements is important because it forces us to use methods only defined in the Interface
.
As a result, when we need to change our class implementations (i.e. we find our ArraySet
is better than the standard HashSet
) we are guaranteed that if we change the class our code will work because both classes implement the strictly-enforced Interface
.
For
List<E> ints = new ArrayList<E>();
Map<K, V> map = new HashMap<K, V>();
List
and Map
are the interfaces, so any class implementing those interfaces can be assigned to these references.
ArrayList
is one of the several classes (another is LinkedList
) which implement List
interface.
Same with Map
. HashMap
, LinkedHashMap
, TreeMap
all implement Map.
It is a general principle To program for interfaces and not for implementations. Due to this, the programming task becomes easier. You can dynamically change the behavior of the references.
If you write
ArrayList<E> ints = new ArrayList<E>();
HashMap<K, V> map = new HashMap<K, V>();
ints
and map
will be ArrayList
and HashMap
only, forever.
When you at some point decide to use a different implementation, say:
List<E> ints = new LinkedList<E>();
instead of
List<E> ints = new ArrayList<E>();
this change needs to be done only at a single place.
There is the right balance to strike:
usually you use the type which gives you the most appropriate guarantees. Obviously, a List
is also a Collection
which is also something Iterable
. But a collection does not give you an order, and an iterable does not have an "add" method.
Using ArrayList
for the variable type is also reasonable, when you want to be a bit more explicit about the need for fast random access by object position - in a LinkedList, a "get(100)" is a lot slower. (It would be nice if Java had an interface for this, but I don't think there is one. By using ArrayList, you disallow casting an array as list.)
This is programming to the interface not the implementation, as per the Gang of Four. This will help to stop the code becoming dependent on methods that are added to particular implementations only, and make it easier to change to use a different implementation if that becomes necessary for whatever reason, e.g. performance.
Using interfaces has the main advantage that you can later change the implementation (the class) without the need to change more than the single line where you create the instance and do the assignment.