Principle
-
If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface types. The only time you really need to refer to an object's class is when you're creating it with a constructor.
// Good - uses interface as type
List<Subscriber> subscribers = new Vector<Subscriber>();
-
If you depend on any special properties of an implementation, document these requirements where you declare the variable.
One caveat
If the original implementation offered some special functionality not required by the general contract of the interface and the code depended on that functionality, then it is critical that the new implementation provide the same functionality.
-
It is entirely appropriate to refer to an object by a class rather than an interface if no appropriate interface exists.
Examples:
- Value classes - String, BigDecimal
- Class-based framework - java.util.TimerTask
-
Classes that implement an interface but provide extra methods not found in the interface - LinkedHashMap
Summary
In practice, it depends whether a given object has an appropriate interface. If it does, your program will be more flexible if you use the interface to refer to the object; if not, just use the least specific class in the class hierarchy that provides the required functionality.