The instanceof operator

Figure 478. Defeating polymorphism Slide presentation Create comment in forum
public static void main(String[] args) {
  final Shape[] shapes = {
    new Circle(1, 1, 2.),
    new Rectangle(1, -1, 2., 3.)};
  print(shapes);
}
static void print(final Shape[] shapes) {
  for (final Shape s : shapes) {
    if (s instanceof Rectangle) {
      System.out.println("Type Rectangle");
    } else if (s instanceof Circle) {
      System.out.println("Type Circle");
    }
  }
}
Type Circle
Type Rectangle

Figure 479. Defining equals(...): Expectations Slide presentation Create comment in forum
Rectangle r1 = new Rectangle(1, 2, 5, 4),
          r2 = new Rectangle(1, 2, 1, 7),
          r3 = new Rectangle(1, 2, 5, 4);

Circle c = new Circle(-2, 3, 5);

System.out.print(r1.equals("Hi"));//false: Differing classes Rectangle and String.
System.out.print(r1.equals(r2));  //false: Differing width and height.
System.out.print(r3.equals(r1));  //true:  Two rectangles having identical
                                  //       (x|y), width and height.
System.out.print(r1.equals(c));   //false: Differing classes Rectangle and Circle.
System.out.print(c.equals(c));    //true: Object equal to itself.

Figure 480. Defining equals(...) of Shape instances Slide presentation Create comment in forum

Two Shape instances shall be considered equal if:

  • Both instances are of common type i.e. either Rectangle or Circle.

  • Their center coordinates match within a threshold of 10 - 15 .

  • width and height or radius match within a threshold of 10 - 15 .


Figure 481. Comparing center coordinates Slide presentation Create comment in forum
public abstract class Shape {
  private double x, y;

  protected boolean equalCenter(final Shape o) {
      return Math.abs(o.x - x) + Math.abs(o.y - y) < 1.E-15;
  }
...

Figure 482. Implementing Rectangle.equals() Slide presentation Create comment in forum
public class Rectangle extends Shape {
    @Override public boolean equals(Object o) {
    if (o instanceof Rectangle) {

      final Rectangle oRectangle = (Rectangle) o; // Cast is «legal»
      return super.equalCenter(oRectangle) &&
             Math.abs(oRectangle.width- width) +
                 Math.abs(oRectangle.height- height) < 1.E-15;
    }
    return false;
  }
 ...

For o == null the expression o instanceof Rectangle evaluates to false.


exercise No. 168

Why is oRectangle = (Rectangle) o a legal cast? Create comment in forum

Q:

We consider:

Object o = new Scanner(System.in);
String s = (String) o;

On execution we receive a java.lang.ClassCastException:

Exception in thread "main" java.lang.ClassCastException: 
  class java.util.Scanner cannot be cast to class java.lang.String 
 at q.App.main(App.java:20)

The comment in Figure 482, “Implementing Rectangle.equals() states the following cast to be legal:

final Rectangle oRectangle = (Rectangle) o; // Cast is «legal»

Why is this claim indeed true?

Don't try digging too deep: The answer is quite simple.

A:

The cast in question appears within the following if block:

if (o instanceof Rectangle) {
   final Rectangle oRectangle = (Rectangle) o;
  ...
}

Thus the cast will only be executed if our variable o actually refers to an instance of class Rectangle. In other words: The if block guards our code against illegal cast attempts.

Rewriting our faulty code accordingly also removes the initial example's runtime exception:

Object o = new Scanner(System.in);
if (o instanceof String) {
   String s = (String) o;  // Unreachable code
}
Figure 483. Implementing Circle.equals() Slide presentation Create comment in forum
public class Circle extends Shape {
  @Override public boolean equals(final Object o) {
    if (o instanceof Circle){
      final Circle oCircle = (Circle) o;
      return super.equalCenter(o) &&
        Math.abs(oCircle.radius - radius) < 1.E-15;
    }
    return false;
  } ...

Figure 484. Testing equality of Shape objects Slide presentation Create comment in forum
final Rectangle
    r1 = new Rectangle(2, 3, 1,4),
    r2 = new Rectangle(2, 3, 2,8),
    r3 = new Rectangle(2, 3, 1,4);

final Circle c = new Circle(2,3, 7);

System.out.println("r1.equals(r2): " + r1.equals(r2));
System.out.println("r1.equals(r3): " + r1.equals(r3));
System.out.println("c.equals(r1): " + c.equals(r1));
r1.equals(r2): false
r1.equals(r3): true
c.equals(r1): false