Easy Tutorial
❮ Android Tutorial Webview Javascrip Trinocular Operators In Lua ❯

Java Type Casting Issues

Category Programming Technology

Java type casting issues are not complicated, as long as you remember one phrase: a superclass reference points to a subclass object.

What does it mean for a superclass reference to point to a subclass object? Let me explain it slowly.

Let's start with two terms: upcasting and downcasting.

For example, there are two classes, Father is the superclass, and Son inherits from Father.

Example 1:

Father f1 = new Son();   // This is called upcasting
// Now f1 references a Son object

Son s1 = (Son)f1;   // This is called downcasting
// Now f1 still references a Son object

Example 2:

Father f2 = new Father();
Son s2 = (Son)f2;       // Error, a subclass reference cannot point to a superclass object

You might ask, in the first example: Son s1 = (Son)f1; Why is it correct?

It's simple because f1 points to a subclass object, Father f1 = new Son(); The subclass s1 reference can certainly point to a subclass object.

But f2 is assigned to a Father object, Father f2 = new Father(); The subclass s2 reference cannot point to a superclass object.

Summary:

  1. A superclass reference points to a subclass object, but a subclass reference cannot point to a superclass object.

  2. Assigning a subclass object directly to a superclass reference is called upcasting, and no explicit type casting is needed, such as:

    Father f1 = new Son();
    
  3. Assigning a superclass reference that points to a subclass object to a subclass reference is called downcasting, and explicit type casting is required, such as:

f1 is a superclass reference that points to a subclass object. Assigning f1 to the subclass reference s1, i.e., Son s1 = (Son)f1;

The (Son) before f1 must be added for explicit type casting.

I. Upcasting.

Colloquially, this means converting a subclass object to a superclass object. The superclass object here can be an interface.

1. Method invocation in upcasting:

Example

public class Animal {

  public void eat(){
    System.out.println("animal eatting...");
  }
}
class Bird extends Animal{

  public void eat(){
    System.out.println("bird eatting...");
  }

  public void fly(){

    System.out.println("bird flying...");
  }
}
class Main{

  public static void main(String[] args) {

    Animal b=new Bird(); // Upcasting
    b.eat(); 
    //! error: b.fly(); b points to a subclass object, but the fly() method is lost
    dosleep(new Male());
    dosleep(new Female());
  }

  public static void dosleep(Human h) {
    h.sleep();
  }
}

Example

public class Human {
  public void sleep() {
    System.out.println("Human sleep..");
  }
}
class Male extends Human {
  @Override
  public void sleep() {
    System.out.println("Male sleep..");
  }
}
class Female extends Human {
  @Override
  public void sleep() {
    System.out.println("Female sleep..");
  }
}

Note the upcasting here:

Animal b=new Bird(); // Upcasting
b.eat();

The subclass's eat() method will be called. Reason: b actually points to a Bird subclass object, so the subclass's method will be called.

It's important to note that during upcasting, b will lose other methods that are not shared with the superclass object. For example, the fly method is no longer accessible to b.

2. Benefits of upcasting

Look at the code above:

public static void dosleep(Human h) {
    h.sleep();
}

Using the superclass as a parameter, sometimes with a subclass as a parameter, takes advantage of upcasting. This makes the code more concise. Otherwise, if dosleep used subclass objects as parameters, a function would need to be written for each subclass. This also reflects Java's abstract programming philosophy.

II. Downcasting.

Opposite to upcasting, this means converting a superclass object to a subclass object.

Example

package com.wensefu.other1;
public class Girl {
  public void smile(){
    System.out.println("girl smile()...");
  }
}
class MMGirl extends Girl{

  @Override
  public void smile() {

    System.out.println("MMirl smile sounds sweet...");
  }
  public void c(){
    System.out.println("MMirl c()...");
  }
}
class Main{

  public static void main(String[] args) {

    Girl g1=new MMGirl(); // Upcasting
    g1.smile();

    MMGirl mmg=(MMGirl)g1; // Downcasting, both compile and run without errors
    mmg.smile();
    mmg.c();


    Girl g2=new Girl();
//    MMGirl mmg1=(MMGirl)g2; // Unsafe downcasting, compile error-free but runtime error
//    mmg1.smile();
//    mmg1.c();
/*output:
* CGirl smile sounds sweet...
* CGirl smile sounds sweet...
* CGirl c()...
* Exception in thread "main" java.lang.ClassCastException: com.wensefu.other1.Girl
* at com.wensefu.other1.Main.main(Girl.java:36)
*/
    if(g2 instanceof MMGirl){
      MMGirl mmg1=(MMGirl)g2; 
      mmg1.smile();
      mmg1.c();
    }

  }
}
Girl g1=new MMGirl(); // Upcasting
g1.smile();
MMGirl mmg=(MMGirl)g1; // Downcasting, both compile and run without errors

This downcasting is safe. Because g1 points to a subclass object.

But

Girl g2=new Girl();
MMGirl mmg1=(MMGirl)g2; // Unsafe downcasting, compile error-free but runtime error

Runtime error:

Exception in thread "main" java.lang.ClassCastException: com.wensefu.other1.Girl
    at com.wensefu.other1.Main.main(Girl.java:36)

As shown in the code, you can use instanceof to prevent exceptions.

❮ Android Tutorial Webview Javascrip Trinocular Operators In Lua ❯