Review:   a subclass object can perform all actions of a superclass object

It is safe to use a superclass reference variable to reference to a subclass object:

Because any request (action) that you make using a superclass variable a can be satisfied

Upcasting: converting a subclass type to a superclass type

  • Upcasting = casting (= converting) a subclass reference into a superclass reference

    Example:

      GeometricObject a;         // a is a superclass reference type
    
      Circle b = new Circle();   // b is a subclass reference type
    
      a = (GeometricObject) b;   // Performs an upcasting operation
    
      a = b;   // We can omit the cast operator because upcasting is safe  

  • Recall from the last slide that:

    • Upcasting is a safe operation

    because:

      • We can make fewer requests using a superclass variable a than using a subclass variable b

DEMO: demo/04-inheritance/21-casting/Demo.java --- compile and show no error

Review:   a superclass object may perform fewer actions than a subclass object

It is unsafe to use a subclass reference variable to reference to a superclass object:

E.g.: user can make the illegal request to execute a.method3() (the superclass object cannot perform method3())

Downcasting: converting a superclass type to a subclass type

  • Downcasting = casting (= converting) a superclass reference into a subclass reference

    Example:

     GeometricObject a = new GeometricObject("red"); // superclass reference
    
     Circle b;                                       // subclass reference
    
     b = (Circle) a;   // Performs an downcasting operation 
    
     b = a;            // Illegal to perform downcasting without cast operator 

  • Recall from the previous slide that:

    • Downcasting is a unsafe operation

    because:

      • We may make an illegal request using a subclass variable b

DEMO: demo/04-inheritance/21-casting/Demo2.java --- compile and show compile error

Safe downcasting operations

  • However.... there are situations where downcasting is safe (and neccessary)

  • The most common situation is:

      1. We first performed an upcasting operation

      2. Later, we want to perform an action defined in the subclass

  • Example:

          public static void main(String[] args)
          {
              GeometricObject a = new Circle("red", 1); 
                                                 // (1) Upcasting
      
              System.out.println(a.getArea());
              
              System.out.println(a.getRadius()); // (2) Error ! 
          }

    We cannot invoke getRadius() using a GeometricObject variable a !!

DEMO: demo/04-inheritance/21-casting/Demo3.java

Safe downcasting operations

  • How to perform a safe downcasting operation:

          public static void main(String[] args)
          {
              GeometricObject a = new Circle("red", 1); 
                                                // Upcasting
      
              System.out.println(a.getArea());
              
      	Circle b;
      
      	b = (Circle) a;
      
              System.out.println(a.getRadius()); // Error ! 
          }

    (0) The variable a ( GeometricObject type) does not have a getRadius() method

Safe downcasting operations

  • How to perform a safe downcasting operation:

          public static void main(String[] args)
          {
              GeometricObject a = new Circle("red", 1); 
                                                // Upcasting
      
              System.out.println(a.getArea());
             
      	Circle b;
       
      	b = (Circle) a;
      
              System.out.println(b.getRadius()); // OK ! 
          }

    (1) We must use a Circle typed variable to invoke the getRadius() method

Safe downcasting operations

  • How to perform a safe downcasting operation for Circle objects

          public static void main(String[] args)
          {
              GeometricObject a = new Circle("red", 1); 
                                                // Upcasting
      
              System.out.println(a.getArea());
             
      	Circle b;
       
      	b = (Circle) a;                  // Explicit upcasting
      
              System.out.println(b.getRadius()); // OK ! 
          }

    (2) Because a points to a Circle object, it is safe to downcast a to a Circle reference

DEMO: demo/04-inheritance/21-casting/Demo4.java

Another example of safe downcasting operation:   downcast a Rectangle

  • How to perform a safe downcasting operation for Rectangle objects:

          public static void main(String[] args)
          {
              GeometricObject a = new Rectangle("red", 1, 2); 
                                                // Upcasting
      
              System.out.println(a.getArea());
             
      	Rectangle b;
       
      	b = (Rectangle) a;                // Downcasting
      
              System.out.println(b.getWidth()); 
              System.out.println(b.getHeight()); 
          }

  • Note: we must downcast the superclass type to the correct subclass type !!!

DEMO: demo/04-inheritance/21-casting/Demo5.java
DEMO: demo/04-inheritance/21-casting/Demo5b.java (what happens if you cast to the wrong subtype)

Downcasting an non-specific subtype reference

  • Problem:

    • Suppose the superclass variable references to a subclass object of non-specific subclass...

    Example:

        public static void main(String[] args)
        {
            if ( ... )
                GeometricObject a = new Circle("red", 1);
            else
                GeometricObject a = new Rectangle("blue", 1, 2);
    
            // a can reference to a Circle or a Rectangle....
    
    	print its radius if a is a Circle
    	print its width and height if a is a Rectangle
        } 

  • How can we write the above program ??

The instanceof boolean condition

  • The instanceof operator:

        objectRefVar instanceof className
    
             Returns true if the object referenced to by
    	 objectRefVar is a object of className type
             or a subclass type of className
      
             Otherwise, returns false

  • Example:

        if ( a instanceof Circle )
            System.out.println("a is a Circle");
    
        if ( a instanceof Rectangle )
            System.out.println("a is a Rectangle");
    
        if ( a instanceof GeometricObject )
            System.out.println("a is a GeometricObject");
    

DEMO: demo/04-inheritance/21-casting/Demo6.java

How to downcast a unspecified subclass type

Skeletal code to downcast an unspecified superclass type to its correct subclass types:

    public static void main(String[] args)
    {
        GeometricObject a = (can be  a Circle or Rectangle object)
                            // Upcasting

        if ( a is a Circle )
	{


	    print its radius
	}
	else if ( a is a Rectangle )
	{


	    print its width and height

	}
        else
	    print "invalid subclass type"
    }

How to downcast a unspecified subclass type

If a references to a Circle object, then downcast (convert) and assign to a Circle variable:

    public static void main(String[] args)
    {
        GeometricObject a = (can be  a Circle or Rectangle object)
                            // Upcasting

        if ( a instanceof Circle )
	{
	    Circle b = (Circle) a; // Downcast to a Circle

	    System.out.println(b.getRadius());
	}
	else if ( a is a Rectangle )
	{


	    print its width and height

	}
        else
	    print "invalid subclass type"
    }  

How to downcast a unspecified subclass type

If a references to a Rectangle object, then downcast (convert) and assign to a Rectangle variable:

    public static void main(String[] args)
    {
        GeometricObject a = (can be  a Circle or Rectangle object)
                            // Upcasting

        if ( a instanceof Circle )
	{
	    Circle b = (Circle) a; // Downcast to a Circle

	    System.out.println(b.getRadius());
	}
	else if ( a instanceof Rectangle  )
	{
	    Rectangle b = (Rectangle) a; // Downcast to a Rectangle

	    System.out.println(b.getWidth());
	    System.out.println(b.getHeight());
	}
        else
	    print "invalid subclass type"
    }  

How to downcast a unspecified subclass type

Otherwise (it can be a GeometricObject !), print the warning message:

    public static void main(String[] args)
    {
        GeometricObject a = (can be  a Circle or Rectangle object)
                            // Upcasting

        if ( a instanceof Circle )
	{
	    Circle b = (Circle) a; // Downcast to a Circle

	    System.out.println(b.getRadius());
	}
	else if ( a instanceof Rectangle  )
	{
	    Rectangle b = (Rectangle) a; // Downcast to a Rectangle

	    System.out.println(b.getWidth());
	    System.out.println(b.getHeight());
	}
        else
	    System.out.println("Invalid subclass type");
    }  

Demo demo/04-inheritance/21-casting/Demo7.java

More examples of the instanceof boolean condition

  • Consider the following inheritance hierachy:

      Cat a;     a instanceof Cat    --> true    a instanceof Dog    --> false
                 a instanceof Animal --> true    a instanceof Object --> true
    
      Animal b;  b instanceof Cat    --> false   a instanceof Dog    --> false
                 b instanceof Animal --> true    b instanceof Object --> true