6. Inheritance
Programming Project 2021/22

6.9. Casting

The Java type system is made up of two kinds of types.

  • primitives
  • references

PrimitiveReference

Casting

Casting (conversion) of primitives and references are two different things

Primitive casting:

  1. Widening (implicit, automatic) casting
  2. Narrowing (explicit) casting

Widening primitive casting

1 byte -> 2 bytes -> 4 bytes -> 8 bytes

widening

int i = 100;
long l = i;	//no explicit type casting required
float f = l;	//no explicit type casting required
System.out.println("Int value "+i);
System.out.println("Long value "+l);
System.out.println("Float value "+f);
Int value 100
Long value 100
Float value 100.0

Narrowing primitive casting

8 bytes -> 4 bytes -> 2 bytes -> 1 bytes

narrowing type conversion

double d = 100.04;
long l = (long)d;  //explicit type casting required
int i = (int)l;	//explicit type casting required

System.out.println("Double value "+d);
System.out.println("Long value "+l);
System.out.println("Int value "+i);
}
Double value 100.04
Long value 100
Int value 100

Narrowing primitive casting may have unpredictable consequences.

double d = 108374658347560.04;
long l = (long)d;  //explicit type casting required
int i = (int)l;	//explicit type casting required

System.out.println("Double value "+d);
System.out.println("Long value "+l);
System.out.println("Int value "+i);
Double value 1.0837465834756005E14
Long value 108374658347560
Int value -251432408

Reference casting

Reference variables only refer to objects but do not contain the objects themselves.

Casting a reference variable doesn’t touch the object it refers to, it only labels this object in another way, expanding or narrowing opportunities to work with it.

Upcasting narrows the list of methods and properties available to the object.

Downcasting may extend the list of methods and properties available to the object.

Upcasting reference variables

Casting from a subclass to a superclass is called upcasting.

public class Animal {
  public void eat() {
      // ... 
  }
}

public class Cat extends Animal {
  public void meow() {
        // ... 
  }
}
Cat cat = new Cat();
Animal animal = cat; //implicit
animal = (Animal) cat; //explicit: not needed in upcasting

We’ve restricted the number of methods available to Cat instance but haven’t changed the instance itself.

Cat cat = new Cat();
Animal animal = cat; 

cat.meow();		// ok
animal.meow();  // not ok: method meow() is undefined for the type Animal

Downcasting reference variables

Casting from a a superclass to a subclass is called downcasting.

public class Animal {
  public void eat() {
      // ... 
  }
}

public class Cat extends Animal {
  public void meow() {
        // ... 
  }
}
Animal animal = new Cat();
Cat cat = (Cat) animal;

Exercise 11

  1. Write class A:
    • Add methodA()
  2. Write class B:
    • It extends A
    • Add methodB()
  3. Try upcasting and downcasting.

You can find the solution to this exercise here.

Casting with Interfaces

Consider the scenario below:

CAST1

public interface C1 { ...}
public interface C2 { ...}
public class A { ... }
class B extends A implements C1, C2 { ... }

Given this hierarchy, all the following statements are valid.

B b = new B();
A a	= (A) b;
C1 c1 = (C1) b;
C2 c2 = (C2) b;
C1 c11 = (C1)(A) b;

Now, supposed that both A and B implement the method whoAmI().

public class A {
  public void whoAmI() {
    System.out.println("I am A.");
  }
}

public class B extends A implements C1, C2 {
  @Override
  public void whoAmI() {
    System.out.println("I am B.");
  }
}

In our main() we write the following instructions.

B b = new B();
A a	= (A) b;
C1 c1 = (C1)b;
C2 c2 = (C2)b;

c1.whoAmI(); // compile error: not accessible through C1
c2.whoAmI(); // compile error: not accessible through C2

b.whoAmI(); // which version of the method will be invoked?
a.whoAmI(); // which version of the method will be invoked?

Which version of whoAmI() is going to be called in each line?

  • A.whoAmI()
  • B.whoAmI()

The answer is always the one that overrides.

I am B.
I am B.

Remember that both b and a point to the same object of type B, which has the following methods.

  • whoAmI()
  • anotherMethod()
  • The difference between variables a and b is only in the methods that are accessible.

Through b we have access to the methods (of the object of type B).

  • whoAmI()
  • anotherMethod()

Through a we have access only to the method (of the object of type B).

  • whoAmI()

Exercise 12

  1. Create an interface Sortable that contains
    • a method boolean isBiggerThan(Sortable obj).
  2. Create class Building implements Sortable
    • a field int height with a corresponding getter and setter.
  3. Create class Land implements Sortable
    • a field int width with a corresponding getter and setter.
    • a field length with a corresponding getter and setter.
  1. Create a class Runner with a main method that
    • creates three Building objects with heights 20, 80, and 60 meters,
    • creates three Land objects of the sizes 20x30, 10x5, and 25x25 square meters,
    • finds the tallest building, and
    • finds the largest land.

You can find the solution to this exercise here.