Java Typecasting and instanceof operator

Typecasting in Java means converting one data type to another.

There are two types of typecasting, casting between primitive numeric types and casting between object references.

Casting between numeric types is used to convert one numeric type values to another numeric type values, such as from int to double. See the following sequence from narrower to wider types conversion:

byte -> short -> int -> long -> float -> double

Casting between object references is used to refer to an object by a compatible class, interface, or array type reference.

There can be two casting scenarios in Java —

  • Upcasting (or implicit casting)
  • Downcasting (or explicit casting)

Upcasting with respect to primitive numeric types means converting narrower data types to wider data types without loss of information (such as int to double).

Whereas, downcasting with respect to primitive numeric types means converting wider data types to narrower data types with loss of information (such as double to int).

When we cast a reference along the class hierarchy in a direction from the subclasses towards the superclass, it is an upcast. We need not use a cast operator in this case.

When we cast a reference along the class hierarchy in a direction from the superclass towards the subclasses, it is a downcast. We must use a cast operator in this case.

See the following coding example.

TypeCasting.java

class Animal { } //superclass

class Dog extends Animal { } //subclass

public class TypeCasting {

public static void main(String[] args) {
int a = 10;
double d = 23.5;
System.out.println("a = " + a);
System.out.println("d = " + d);

// implicit typecasting or upcasting (narrower to wider type) w.r.t. primitive type
long l = a;
float g = a;
d = l;
System.out.println("l = " + l);
System.out.println("g = " + g);
System.out.println("d = " + d);

// explicit typecasting or downcasting (wider to narrower type) w.r.t. primitive type
float f = (float) d;
System.out.println("f = " + f);

Animal animal = new Dog(); //upcasting w.r.t. reference type
Dog dog = (Dog)animal; //downcasting w.r.t. reference type
}
}

Output:

a = 10
d = 23.5
l = 10
g = 10.0
d = 10.0
f = 10.0

The compile-time rules are there to catch attempted casts in cases that are simply not possible. This happens when we try to attempt casts on objects that are totally unrelated (that is not subclass super class relationship or a class-interface relationship). At runtime a ClassCastException is thrown if the object being cast is not compatible with the new type it is being cast to. See the example below.

RuntimeCastDemo.java

// X is a supper class of Y and Z which are siblings.
class X {}
class Y extends X {}
class Z extends X {}

public class RuntimeCastDemo {

public static void main(String args[]) {
X x = new X();
Y y = new Y();
Z z = new Z();
X xy = new Y(); // compiles ok (up the hierarchy)
X xz = new Z(); // compiles ok (up the hierarchy)
// Y yz = new Z(); incompatible type (siblings)
// Y y1 = new X(); X is not a Y
// Z z1 = new X(); X is not a Z
X x1 = y; // compiles ok (y is subclass of X)
X x2 = z; // compiles ok (z is subclass of X)
Y y1 = (Y) x; // compiles ok but produces runtime error
Z z1 = (Z) x; // compiles ok but produces runtime error
Y y2 = (Y) x1; // compiles and runs ok (x1 is type Y)
Z z2 = (Z) x2; // compiles and runs ok (x2 is type Z)
// Y y3 = (Y) z; inconvertible types (siblings)
// Z z3 = (Z) y; inconvertible types (siblings)
Object o = z;
Object o1 = (Y) o; // compiles ok but produces runtime error
}
}

NOTE: Do not try to run this code as it will generate ClassCastException.

 

The instanceof operator

The instanceof operator is called the type comparison operator, lets us determine if an object belongs to a specific class, or implements a specific interface. It returns true if an object is an instance of the class or if the object implements the interface, otherwise it returns false. Below is an example showing the use of instanceof operator.

InstanceOfExample.java

class Vehicle {
String name;
Vehicle() {
name = "Vehicle";
}
}

class HeavyVehicle extends Vehicle {
HeavyVehicle() {
name = "HeavyVehicle";
}
}

class Truck extends HeavyVehicle {
Truck() {
name = "Truck";
}
}

public class InstanceOfExample {
static boolean result;
static HeavyVehicle hV = new HeavyVehicle();
static Truck t = new Truck();
static HeavyVehicle hv2 = null;

public static void main(String[] args) {
result = hV instanceof HeavyVehicle;

System.out.println("hV is an HeavyVehicle: " + result);
result = t instanceof HeavyVehicle;
System.out.println("t is an HeavyVehicle: " + result);
result = hV instanceof Truck;
System.out.println("hV is a Truck: " + result);
result = hv2 instanceof HeavyVehicle;
System.out.println("hv2 is an HeavyVehicle: " + result);
hV = t; //Successful Cast form child to parent
t = (Truck) hV; //Successful Explicit Cast form parent to child
}
}

Output:

hV is an HeavyVehicle: true
t is an HeavyVehicle: true
hV is a Truck: false
hv2 is an HeavyVehicle: false