Overview

  • Inheritance

    Lecture notes

Guess who's inheriting the money

Guess who's inheriting the money

Lecture notes

  • Inheritance

Create comment

Biology and inheritance

Biology and inheritance

Lecture notes

  • Inheritance

Create comment

Duplicate code

public class Rectangle{
  // Center coordinate
  private double x; 
  private double y;

  public void move
    (double dx, double dy){ 
     x += dx;
     y += dy;
  }
  private double width, height;  ...
}
public class Circle {
  // Center coordinate
  private double x; 
  private double y;

  public void move
    (double dx, double dy){ 
     x += dx;
     y += dy;
  }
  private double radius;  ...
}

Lecture notes

  • Inheritance

Create comment

Idea: Centralize common code

  • Create a parent class Shape containing common code portions.

  • Relate both Rectangle and Circle to Shape.

Lecture notes

  • Inheritance

Create comment

Common and specific properties

Common Rectangle and Circle attributes:
double x;
double y;
Rectangle attributes Circle attributes
double width;
double height;
double radius;

Lecture notes

  • Inheritance

Create comment

Basic shape inheritance

layered SVG image

Lecture notes

  • Inheritance

Create comment

Basic shape inheritance

layered SVG image

Lecture notes

  • Inheritance

Create comment

Inheritance

  • Derived classes inherit state and behaviour.

  • Refinement, specialization.

  • is-A relationship:

    • A rectangle is a shape.

    • A circle is a shape.

Lecture notes

  • Inheritance

Create comment

Implementing Shape hierarchy

public class Shape {
  private double x, y;
}
public class Rectangle extends Shape {
  private double width;
  private double height;
}
public class Circle extends Shape {
  private double radius;
}

Lecture notes

  • Inheritance

Create comment

Creating instances

final double x = 2, y = 3;
final Shape shape = new Shape(x, y);

final double width = 2, height = 5;
final Rectangle r = new Rectangle(x, y , width, height);

final double radius = 2.5;
final Circle circle = new Circle(x, y , radius);

Lecture notes

  • Inheritance

Create comment

Shape constructor

/**
  * Creating a shape located at center coordinate.
  * @param x The center's x component.
  * @param y The center's y component.
  */
public Shape(double x,double y) {
  this.x = x;
  this.y = y;
}

Lecture notes

  • Inheritance

Create comment

Creating Rectangle instances

final Rectangle r = 
   new Rectangle(x, y ,
                 width, height );

Center coordinate components belonging to superclass Shape.

width and height belonging to class Rectangle.

Solution: Nested constructor call. Coming soon ...

Lecture notes

  • Inheritance

Create comment

Rectangle constructor

/**
  * Creating a rectangle at (x|y) of given width and height.
  * @param x Center's x component.
  * @param y Center's y component.
  * @param width Rectangle's width.
  * @param height Rectangle's height.
  */
public Rectangle(double x, double y,
             double width, double height) {
  super(x, y) ;
  this.width = width; this.height = height ;
}

Lecture notes

  • Inheritance

Create comment

Overview

  • Inheritance
    • ➟ Overriding equals() and hashCode()

      Lecture notes

Shape.equals()

public abstract class Shape {
  ...
  @Override  public boolean equals(final Object o) {
    if (o instanceof Shape ) {
      final Shape other = (Shape) o; 
      return x == other.x && y == other.y; 
    } else {
      return false; 
    } ...

Lecture notes

  • Inheritance
    • ➟ Overriding equals() and hashCode()

Create comment

Rectangle.equals()

public class Rectangle extends Shape {
  ...
  @Override public boolean equals(final Object o) {
    if (o instanceof Rectangle) {
      final Rectangle other = (Rectangle) o;
      return super.equals(o)  &&  width == other.width && height == other.height ;
    } else {
      return false;
    } ...

Lecture notes

  • Inheritance
    • ➟ Overriding equals() and hashCode()

Create comment

Overview

  • Inheritance
    • ➟ Overriding toString()

      Lecture notes

Shape log info

public class Run {
  static final Logger log = LogManager.getLogger(Run.class);
  public static void main(String[] args) {
    final double x = 2.0, y = 3.0;
    final Shape shape = new Shape(x, y);
    log.info(shape);  ...
2017... INFO  [main] inherit.Run ... - inherit.Shape@37d31475

Desired:

2017... INFO  [main] inherit.Run ... - (2.0|3.0)

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Overwriting toString()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Overwriting toString()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Overwriting toString()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Overwriting toString()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Overwriting toString()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Shape extending Object

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Shape extending Object

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Shape extending Object

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Logging Rectangle instances

public class Run {
  static final Logger log = LogManager.getLogger(Run.class);
  public static void main(String[] args) {
    final double x = 2, y = 3, width = 3., height = 4.;
    final Rectangle r = new Rectangle(x, y, width, height);
    log.info(r); ...
2017 ... INFO  [main] inherit.Run (Run.java:15) - (2.0|3.0)

Desired:

2017 ... INFO  Rectangle at (2.0|3.0), width= 3.0, height=4.0

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Override toString() again.

public class Rectangle extends Shape {
  @Override public String toString() {
    return "Rectangle at " + super.toString()  +
      ", width= " + width + ", height=" + height; 
  } ...

The super keyword allows for calling the toString() method from superclass Shape.

Append class Rectangle's own width and height attributes.

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Rectangle extending Shape

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Rectangle extending Shape

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Rectangle extending Shape

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Rectangle extending Shape

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Implementing Circle.toString()

public class Circle extends Shape {
  /**
   * Creating a circle of given center and radius
   * @param x Center's x component.
   * @param y Center's y component.
   * @param radius The circle's radius.
   */
  public Circle(double x,double y, double radius) {
    super(x, y);
    this.radius = radius;
  }
  @Override public String toString() {
    return "Circle at " + super.toString() +", radius= " + radius;
  }
  private double radius;
}

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Shape and toString()

Shape and toString()

Lecture notes

  • Inheritance
    • ➟ Overriding toString()

Create comment

Followup exercises

Overview

  • Inheritance
    • ➟ final methods

      Lecture notes

Moving Shape instances

layered SVG image

Lecture notes

  • Inheritance
    • ➟ final methods

Create comment

Moving Shape instances

layered SVG image

Lecture notes

  • Inheritance
    • ➟ final methods

Create comment

Moving Shape instances

layered SVG image

Lecture notes

  • Inheritance
    • ➟ final methods

Create comment

Implementing Shape movements

public class Shape {
  /**
   * Move by a given translation vector
   * @param xTrans Translation's x component
   * @param yTrans Translation's y component
   */
  public void move(final int xTrans, final int yTrans) {
    x += xTrans;
    y += yTrans;
  } ...

Lecture notes

  • Inheritance
    • ➟ final methods

Create comment

Fools are everywhere!

public class Rectangle extends Shape {
  @Override public void move(int xTrans, int yTrans) {
    // I'm so dumb!
    ...
  }

Lecture notes

  • Inheritance
    • ➟ final methods

Create comment

Solution: final prevents overriding

public abstract class Shape {
... public final void move(final int xTrans, final int yTrans) {
      x += xTrans;
      y += yTrans;
    }...
public class Rectangle extends Shape {
  // Syntax error: 'move(int, int)' cannot override
  // 'move(int, int)' in 'inherit.Shape'; overridden method is final
  @Override public void move(int xTrans, int yTrans) {...

Lecture notes

  • Inheritance
    • ➟ final methods

Create comment

Overview

  • Inheritance
    • ➟ Abstract methods

      Lecture notes

Calculating a shape's area

public class Rectangle extents Shape {
  /**
   * Calculate the area.
   * @return The rectangle's area
   */
  public double getArea() {
    return width * height;
  }
public class Circle extents Shape {
  /**
   * Calculate the area.
   * @return The circle's area
   */
  public double getArea() {
    return Math.PI * radius * radius;
  }

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

Desired: Polymorphic getArea() call

final Shape[] shapes  = {
    new Circle(1, 1, 2.) ,
    new Rectangle(1, -1, 2., 3.)};

for (final Shape s : shapes) {
  System.out.println(s.toString() + ": area = " + s.getArea()); 
}
Circle at (1.0|1.0), radius= 2.0: area = 12.566370614359172
Rectangle at (1.0|-1.0), width= 2.0, height=3.0: area = 6.0

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

Problems:

  • No meaningful getArea() method in class Shape possible.

  • Meaningful implementations exist both in subclass Rectangle and Circle.

Solution: Abstract method getArea() in superclass Shape.

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

abstract public class Shape {
  /**
   * Calculate the shape's area.
   * @return The shape's area
   */
  abstract public double getArea(); ...
public class Rectangle extends Shape {
  @Override
  public double getArea() {
    return width * height;
  }...
public class Circle ... {
 @Override
  public double getArea() {
    return Math.PI *
           radius * radius;
  } ...

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

abstract method getArea()

layered SVG image

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

What's a shape anyway?

What's a “shape” anyway?

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

No instances of abstract classes.

final Shape s =
   new Shape(1., 2.); // 'Shape' is abstract; cannot be instantiated

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

Mandatory getArea() implementation.

// Error: Class 'Circle' must either be declared abstract or
//        implement abstract method 'getArea()' in 'Shape'
public class Circle extends Shape {

  public Circle(double x,double y, double radius) {
    super(x, y);
    this.radius = radius;
  }
  private double radius;
}

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

Facts about abstract fields, methods and classes.

  • A class containing an abstract method must itself be declared abstract.

  • abstract classes are allowed to host non-abstract methods.

  • A class may be declared abstract irrespective of purely containing non-abstract methods.

Lecture notes

  • Inheritance
    • ➟ Abstract methods

Create comment

Overview

  • Inheritance
    • ➟ Abstract methods
      • ➟ Geometry classes reconsidered

        Lecture notes

Moving shapes

Moving shapes

Lecture notes

  • Inheritance
    • ➟ Abstract methods
      • ➟ Geometry classes reconsidered

Create comment

Followup exercises

Overview

  • Inheritance
    • ➟ protected access

      Lecture notes

protected access

package model;
public abstract class Shape {

  final protected long creationTime = System.nanoTime();
...
}
------------------------------------------------
package model.sub;
public class Rectangle extends Shape {
  static final Logger log = LogManager.getLogger(Rectangle.class);

  @Override public double getArea() {
    log.info("Rectangle creation time:" + creationTime );
    return width * height;
  } ...
}

Lecture notes

  • Inheritance
    • ➟ protected access

Create comment

Followup exercises

Overview

  • Inheritance
    • ➟ final classes

      Lecture notes

final classes

public final class Shape { ... }

-------------------------
public class Rectangle
  extends Shape { // Error: final class cannot be extended
...

Lecture notes

  • Inheritance
    • ➟ final classes

Create comment

final classes, rationale

  • Design decision.

  • Slight performance gain.

Note

Prominent Example: java.lang.String.

Lecture notes

  • Inheritance
    • ➟ final classes

Create comment

Overview

  • Inheritance
    • ➟ The instanceof operator

      Lecture notes

Defeating polymorphism

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

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Defining equals(...): Expectations

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.println(r1.equals("Hello")); // false: Differing classes Rectangle and String.
System.out.println(r1.equals(r2));      // false: Differing width and height.
System.out.println(r3.equals(r1));      // true:  Two rectangles, 
                                        // identical (x|y), width and height.
System.out.println(r1.equals(c));  // false: Differing classes Rectangle and Circle.
System.out.println(c.equals(c));   // true: Object equal to itself.

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Defining equals(...) of Shape instances

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 .

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Comparing center coordinates

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;
  }
...

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Implementing Rectangle.equals()

public class Rectangle extends Shape {
    @Override public boolean equals(Object o) {
    if (o instanceof Rectangle){
      final Rectangle oRectangle = (Rectangle) o;
      return super.equalCenter(oRectangle) &&
          Math.abs(oRectangle.width- width) +
          Math.abs(oRectangle.height- height) < 1.E-15;
    }
    return false;
  }
 ...

if o == null then o instanceof Rectangle evaluates to false.

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Implementing Circle.equals()

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;
  } ...

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Testing equality of Shape objects

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

Lecture notes

  • Inheritance
    • ➟ The instanceof operator

Create comment

Overview

  • Inheritance
    • ➟ The @Override annotation.

      Lecture notes

Overriding Object.toString()

public class Shape {

  double x, y;
 ...
  @Override  // Promise: Subsequent method overrides Object.toString();
  public String toString() {
    return "(" + x + "|" + y + ")";
  }
}

Lecture notes

  • Inheritance
    • ➟ The @Override annotation.

Create comment

Failure: Not overriding Object.toString()

public class Shape {

  double x, y;
 ...
  @Override  // Error: method does not override a method from a supertype
  public String toString(int value) {
    return "(" + x + "|" + y + ")";
  }
}

Lecture notes

  • Inheritance
    • ➟ The @Override annotation.

Create comment