Java Language Inheritance Narrowing and Widening of object references


Casting an instance of a base class to a subclass as in : b = (B) a; is called narrowing (as you are trying to narrow the base class object to a more specific class object) and needs an explicit type-cast.

Casting an instance of a subclass to a base class as in: A a = b; is called widening and does not need a type-cast.

To illustrate, consider the following class declarations, and test code:

class Vehicle {

class Car extends Vehicle {

class Truck extends Vehicle {

class MotorCycle extends Vehicle {

class Test {

    public static void main(String[] args) {
        Vehicle vehicle = new Car();
        Car car = new Car();        
        vehicle = car; // is valid, no cast needed

        Car c = vehicle // not valid
        Car c = (Car) vehicle; //valid

The statement Vehicle vehicle = new Car(); is a valid Java statement. Every instance of Car is also a Vehicle. Therefore, the assignment is legal without the need for an explicit type-cast.

On the other hand, Car c = vehicle; is not valid. The static type of the vehicle variable is Vehicle which means that it could refer to an instance of Car, Truck,MotorCycle, or any other current or future subclass ofVehicle. (Or indeed, an instance ofVehicleitself, since we did not declare it as anabstractclass.) The assignment cannot be allowed, since that might lead tocarreferring to aTruck` instance.

To prevent this situation, we need to add an explicit type-cast:

Car c = (Car) vehicle;

The type-cast tells the compiler that we expect the value of vehicle to be a Car or a subclass of Car. If necessary, compiler will insert code to perform a run-time type check. If the check fails, then a ClassCastException will be thrown when the code is executed.

Note that not all type-casts are valid. For example:

String s = (String) vehicle;  // not valid

The Java compiler knows that an instance that is type compatible with Vehicle cannot ever be type compatible with String. The type-cast could never succeed, and the JLS mandates that this gives in a compilation error.