Thursday, 29 March 2012

ClassCastException in Java

public class ClassCastException
extends RuntimeException

Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance. i.e.Thrown when attempting to cast a reference variable to a type that fails the IS-A test.

Before discussing more about ClassCastException let us go through reference variable casting.

Reference Variable Casting

Java allows us to cast variables of one type to another as long as the casting happens between compatible data types.The compatible data types means they should follow the following contracts.

1. Both the reference variables types should be in the same inheritance hierarchy.Else compile-time error occurs.
2. When attempting to cast a reference variable to a type that should pass the IS-A test.Else run-time error occurs ,i.e. throws ClassCastException.


Let us take one inheritance hierarchy as given below


Compatible types
  • Car to Vehicle 
  • Car to Object 
  • Vehicle to Object
  • Bus to Vehicle 
  • Bus to Object 
All of them are following above mentioned two contracts for reference variable casting.For example Car to Vehicle, from diagram you can see that both the Car and Vehicle are in the same inheritance hierarchy.Car IS-A Vehicle, so passes the IS-A test .So Car to Vehicle casting clears both the contracts.

Incompatible types

  • Car to Bus 
  • Bus to Car
Car and Bus are not in same inheritance hierarchy so compile-time error occurs.
  • Vehicle to Car
  • Object to Car
  • Object to Vehicle
  • Vehicle to Bus
  • Object to Bus 
All of them are in the same inheritance hierarchy so compile successfully.But none of them pass the IS-A test, so ClassCastException occurs.For example Vehicle to Car ,both Vehicle and Car are in the same inheritance hierarchy but Vehicle IS-A Car test fails.We are sure that Vehicle is not a Car because Car has some additional features compared to a Vehicle.

Types of reference variable casting

There are two types of reference variable casting: upcasting and downcasting.

Upcasting

You can assign a reference variable to a supertype reference variable explicitly or implicitly.

Downcasting

If you have a reference variable of supertype that refers to a subtype object,you can assign it to a reference variable of the subtype. You must make an explicit cast to do this, and the result is that you can access the subtype's members with this new reference variable.

Let us discuss the types of casting with examples.

Upcasting Example

class Vehicle {
}

class Car extends Vehicle {

}

class Bus extends Vehicle {
}

public class Main {

 public static void main(String args[]) {

  Car car = new Car();
  Bus bus = new Bus();
  Vehicle vehicle = new Vehicle();
  Vehicle obj1 = car;
  Vehicle obj2 = (Car) car;
  Vehicle obj3 = bus;
  Vehicle obj4 = (Bus) bus;
  Object obj5 = vehicle;
  Object obj6 = (Vehicle) vehicle;
  Object obj7 = car;
  Object obj8 = (Car) car;
  Object obj9 = bus;
  Object obj10 = (Bus) bus;

 }
}

The above code compiles and runs successfully.Notice that you can assign a reference variable to a supertype reference variable explicitly or implicitly. 

Downcasting Example
class Vehicle {
}

class Car extends Vehicle {

}

class Bus extends Vehicle {
}

public class Main {

 public static void main(String args[]) {

  Car car1 = new Car();
  Vehicle vehicle = car1;
  Car car2 = (Car) vehicle;

 }
}

The above code compiles and runs successfully.The reference variable vehicle is of class type Vehicle and referring an object of type Car.Here we are downcasting the type of reference variable vehicle from  supertype Vehicle to subtype Car.Now both car1 and car2 are referring the same object of type Car.

Suppose the reference variable vehicle is not referring a subtype object (In the above e.g. Car) ,instead of that referring the supertype(i.e. Vehicle).

class Vehicle {
}

class Car extends Vehicle {

}

class Bus extends Vehicle {
}

public class Main {

 public static void main(String args[]) {

  Vehicle vehicle = new Vehicle();
  Car car = (Car) vehicle;
 }
}

The output is

Exception in thread "main" java.lang.ClassCastException: Vehicle cannot be cast to Car
at Main.main(Main.java:17)

The above code compiles successfully but fails the execution,throws ClassCastException.The compiler fails to understand that vehicle is referring an object of supertype Vehicle not the subtype Car.

How to Avoid ClassCastException

Do an instanceof test before performing the casting.See the code given below

class Vehicle {
}

class Car extends Vehicle {

}

class Bus extends Vehicle {
}

public class Main {

 public static void main(String args[]) {

  Vehicle vehicle = new Vehicle();
  if (vehicle instanceof Car) {
   Car car = (Car) vehicle;
  }

 }
}

The above code compiles and runs successfully.At run-time checks vehicle is an instance of class Car, if yes execute the casting else not.In the above example vehicle is not an instance of Car so casting does not perform.

The links you may like

Casting Reference Variables- Downcasting, Upcasting 

instanceof operator in Java

No comments:

Post a Comment