I see this syntax a lot and don't understand the reasoning behind it. I thought you generally want to work with classes rather than interfaces to make it easier to carry out the full panoply of operations you might want to perform.
Why do this:
List<Foo> foo = new ArrayList<Foo>(something.getFoo());
instead of this:
ArrayList<Foo> foo = new ArrayList<Foo>(something.getFoo());
when you later want to perform operations on foo? Isn't it easier if foo is represented by the class ArrayList rather than the interface List?
Occasionally, yes. If you actually need a method that's declared in
ArrayList<T>
but not inList<T>
then sure, go for it.However, the reverse is more flexible - if you don't need any methods declared in
ArrayList<T>
, then your code can express that by declaring the variable to be of typeList<T>
instead. That says, "I just need a list. I happen to be pickingArrayList<T>
, but just because its behaviour suits me... not because I need any extra features it exposes."That's useful to know if later someone wonders whether they could substitute a different implementation, for example. It also limits how much a reader has to think about... the more general the type of the variable, the less one can do with it - so the less one needs to think about it.
For example, if I see a variable of type
Iterable<T>
I know there's precious little that's likely to be done with it later: basically, it's going to be used to iterate, and that's all. I don't need to worry about whether any later code is going to try to add a value to the collection, or access it by index etc.This is relatively unimportant for local variables, but much more so for instance variables and particularly parameters: the less concrete you make your parameters, the more flexibility the caller has about which arguments they'll pass.
In order to keep your code well decoupled it is best to hide implementation details so you can later do things in a different way.
Therefore it is customary to only expose the interface which is needed in the other parts to avoid that others will make assumptions on the contract that you must later honor.
If a lot of use is made of specific implementations you end up with contorted code when you get a LinkedList from method A and an ArrayList from methodB.
Programming against interfaces makes it also easier to mock objects out in unit testing.
The entire point of polymorphism is to NOT bind your implementation to another data type's implementation. In this case, you don't want to marry your class to an ArrayList. Rather, you want to marry your class to an abstract List type.