SE450: Types: Casting [35/47] Previous pageContentsNext page

What is a downcast, upcast, crosscast?

How are casts checked by the compiler?

How are casts checked by the runtime system?

file:types/casting/Main.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package types.casting;

interface Animal { default public String f () { return "Animal"; } }
interface Fish extends Animal { default public String f () { return "Fish"; } }
interface Bird extends Animal { default public String f () { return "Bird"; } }
class Cod implements Fish { public String f () { return "Cod"; } }
class Owl implements Bird { public String f () { return "Owl"; } }

public class Main {
  private Main() {}
  public static void main(String[] args) {
    Cod cod = new Cod ();
    Owl owl = new Owl ();
    
    /* Implicit upcasts always compile and run ok */
    Animal aCod = cod;
    Animal aOwl = owl;
    
    /* Explicit upcast  causes an unnecessary cast warning */
    //Animal aCod2 = (Animal) cod;

    /* Explicit downcasts always compile, but may cause runtime errors */
    //Fish f1 = aCod;        // implicit downcast: compiler error
    //Fish f2 = (Fish) aOwl; // explicit downcast: runtime error
    Fish f3 = (Fish) aCod;   // explicit downcast: runtime success

    /* Crosscasting to a class is disallowed by the compiler */
    //Cod f4 = (Cod) owl;          // crosscast: compiler error
    
    /* Crosscast can be replaced by upcast+downcast */
    //Cod f5 = (Cod) (Animal) owl; // upcast+downcast: runtime error

    /* Crosscasting to an interface is allowed by the compiler */
    //Fish f6 = (Fish) owl;        // crosscast: runtime error
    
    /* Casting changes the declared type, but not the actual type */
    System.out.println("Animal: " + aCod.f());
    System.out.println("Fish:   " + f3.f());
    System.out.println("Cod:    " + cod.f());
  }
}
The rules are as follows 

  class A {}
  class B extends A {}
  class C extends A {}

Upcast goes from subtype to supertype: (A)(new B())
Downcast goes from supertype to subtype: (B)(new A())
Any other cast is a "cross cast"

At compile time:
Cast to interface type is always allowed.
Cast to class type is allowed if the it is an upcast or a downcast.
The declared type of the cast expression is changed:

      new B()  has declared type B
  (A)(new B()) has declared type A

At runtime:
Casts are checked to ensure validity (ClassCastException if not)
The actual type of the object is unchanged:

      new B()  has actual type B
  (A)(new B()) has actual type B

Previous pageContentsNext page