In many cases the superclass (or interface) describes a general Object but the subclasses differ in implementation to make the code either more efficient or more accessible.
A good example is the interface List
. It has two main subclasses AbstractList
and AbstractSequentialList
. These provide implementations of most methods in List
, but leave the actual memory management up to their subclasses.
When I create a List
object, it's usually because I want a length-changing array and not because of ArrayList
's exact implementation (Although it does specify a few more useful methods which you can't access in List
).
This means I just say
List<?> list = new ArrayList<?>();
because I want a list but have to also specify the implementation that's most efficient for my cause.
When it comes to your Vehicle
and Car
classes, I say it depends on what you want to achieve. In this case specifying your Car
object as follows is probably the most sensical:
Car car = new Car();
because you are asking for a car specifically and aren't just using Car
as a certain implementation of Vehicle
.
In conclusion:
SomeClass c = new SomeClassSuperclass();
is most useful and readable when SomeClass
is just an implementation of SomeClassSuperclass
.
SomeClass c = new SomeClass();
is most useful and readable when SomeClass
is supposed to be a different type of SomeClassSuperclass
, but still has it's own features that make it a SomeClass
rather than a SomeClassSuperclass
(Think of a car in real life, you don't point to a car and say "Look, An awesome vehicle!" or "Look, I got a new vehicle!", as those phrases don't really give you much information about what you are talking about)