You're really asking: what reference type should I use?
Generally you want to use as general a reference type as possible that still gives you access to the behavior that you need. This means any of the interfaces or parent classes of your concrete type, rather than the concrete type itself. Of course, don't take this point too far -- for example, you certainly don't want to declare everything as an
Consider these options:
Set<String> values1 = new TreeSet<String>();
TreeSet<String> values2 = new TreeSet<String>();
SortedSet<String> values3 = new TreeSet<String>();
All three are valid, but generally the first option of
values1 is better because you will only be able to access the behavior of the
Set interface, so later you can swap in another implementation quite easily:
Set<String> values1 = new HashSet<String>();
Beware of using the second option
values2. It allows you to use specific behavior of the
TreeSet implementation in such a way that swapping in a different implementation of
Set becomes more difficult. This is fine as long as that's your goal. So, in your example, use a
Bike reference only when you need access to something that's not in the
IVehicle interface. Be aware though that the following would not work:
TreeSet<String> values2 = new HashSet<String>(); // does not compile!
Still there are times when you need access to the methods that are in the most general type. This is illustrated in the third option
values3 -- the reference is more specific than
Set, which allows you to rely on the behavior of
TreeSet<String> values3 = new ConcurrentSkipListSet<String>();
The question about reference types applies not only where variables are declared, but also in methods where you have to specify the type of each parameter. Fortunately the "use as general a reference type as possible" rule of thumb applies to method parameters, too.