Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
(#1 of 2) |
Lecture notes |
Pdf slides |
|
(#2 of 2) |
Lecture notes |
Pdf slides |
|
Shape
hierarchy
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Shape
constructor
Lecture notes |
Pdf slides |
|
Rectangle
instances
Lecture notes |
Pdf slides |
|
Rectangle
constructor
Lecture notes |
Pdf slides |
|
Shape
.equals()
Lecture notes |
Pdf slides |
|
Rectangle
.equals()
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Shape
's info
Lecture notes |
Pdf slides |
|
toString()
Lecture notes |
Pdf slides |
|
(#1 of 5) |
toString()
Lecture notes |
Pdf slides |
|
(#2 of 5) |
toString()
Lecture notes |
Pdf slides |
|
(#3 of 5) |
toString()
Lecture notes |
Pdf slides |
|
(#4 of 5) |
toString()
Lecture notes |
Pdf slides |
|
(#5 of 5) |
Shape
extending
Object
Lecture notes |
Pdf slides |
|
(#1 of 3) |
Shape
extending
Object
Lecture notes |
Pdf slides |
|
(#2 of 3) |
Shape
extending
Object
Lecture notes |
Pdf slides |
|
(#3 of 3) |
Rectangle
instances
Lecture notes |
Pdf slides |
|
toString()
in class
Rectangle
.
Lecture notes |
Pdf slides |
|
Rectangle
extending
Shape
Lecture notes |
Pdf slides |
|
(#1 of 4) |
Rectangle
extending
Shape
Lecture notes |
Pdf slides |
|
(#2 of 4) |
Rectangle
extending
Shape
Lecture notes |
Pdf slides |
|
(#3 of 4) |
Rectangle
extending
Shape
Lecture notes |
Pdf slides |
|
(#4 of 4) |
Circle
.toString()
Lecture notes |
Pdf slides |
|
Shape
and
toString()
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Shape
instances
Lecture notes |
Pdf slides |
|
(#1 of 3) |
Shape
instances
Lecture notes |
Pdf slides |
|
(#2 of 3) |
Shape
instances
Lecture notes |
Pdf slides |
|
(#3 of 3) |
Shape
movements
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
getArea()
call
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#1 of 7) |
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#2 of 7) |
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#3 of 7) |
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#4 of 7) |
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#5 of 7) |
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#6 of 7) |
abstract
method
getArea()
Lecture notes |
Pdf slides |
|
(#7 of 7) |
Lecture notes |
Pdf slides |
|
abstract
classes.
Lecture notes |
Pdf slides |
|
getArea()
implementation.
Lecture notes |
Pdf slides |
|
abstract
fields, methods
and classes.
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
protected
access
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
final
classes
Lecture notes |
Pdf slides |
|
final
classes rationale
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
equals(...)
:
Expectations
Lecture notes |
Pdf slides |
|
equals(...)
of
Shape
instances
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Rectangle
.equals()
Lecture notes |
Pdf slides |
|
Circle
.equals()
Lecture notes |
Pdf slides |
|
Shape
objects
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
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; ❸ ... } |
Create a parent class Shape
containing
common code portions.
Relate both Rectangle
and
Circle
to Shape
.
Common
Rectangle and Circle
attributes:
|
||
---|---|---|
|
||
Rectangle
attributes
|
Circle
attributes
|
|
|
|
Derived classes inherit state and behaviour.
Refinement, specialization.
“is-A” relationship:
A rectangle is a shape.
A circle is a shape.
|
|||
|
|
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);
/**
* 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;
}
final Rectangle r = new Rectangle(x, y ❶, width, height ❷);
Center coordinate components “belonging” to
superclass |
|
width and height “belonging” to class
|
Solution: Nested constructor call. Coming soon ...
/** * 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 ❷; }
equals()
and
hashCode()
public abstract class Shape { ... @Override ❶ public boolean equals(final Object o) { if (o instanceof Shape s ❷) { return x == s.x && y == s.y; ❸ } else { return false; ❹ } ...
public class Rectangle extends Shape { ... @Override public boolean equals(final Object o) { if (o instanceof Rectangle r) { return super.equals(o) ❶ && width == r.width && height == r.height ❷; } else { return false; } ...
Code | Output |
---|---|
package inherit; public class Run { public static void main(String[] args) { final Shape shape = new Shape(2.0, 3.0); // Center coordinates System.out.println(shape); |
inherit.Shape@37d31475 Desired: (2.0|3.0) |
Code | Output |
---|---|
|
(2.0|3.0) Desired: Rectangle at (2.0|3.0), width= 3.0, height=4.0 |
public class Rectangle extends Shape { @Override public String toString() { return "Rectangle at " + super.toString() ❶ + ", width= " + width + ", height=" + height; ❷ } ...
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;
}
final
methods
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;
} ...
public class Rectangle extends Shape {
@Override public void move(int xTrans, int yTrans) {
// I'm so dumb!
...
}
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) {...
|
|
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
No meaningful getArea()
method in
class Shape
possible.
Meaningful implementations exist both in subclass
Rectangle
and Circle
.
Solution: Abstract method getArea()
in
superclass Shape
.
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; } ... |
final Shape s =
new Shape(1., 2.); // 'Shape' is abstract; cannot be instantiated
// 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; }
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.
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; } ... }
final
classes
public final class Shape { ... }
-------------------------
public class Rectangle
extends Shape { // Error: final class cannot be extended
...
Design decision.
Slight performance gain.
Note
Prominent Example:
java.lang.String
.
instanceof
operator
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 |
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.
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 .
width
and height
or radius
match within a threshold of
.
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;
}
...
public class Rectangle extends Shape { @Override public boolean equals(Object o) { if (o instanceof Rectangle r) { final Rectangle oRectangle = (Rectangle) o; // Cast is «legal» return super.equalCenter(r) && Math.abs(r.width- width) + Math.abs(r.height- height) < 1.E-15; } return false; } ...
For o == null
the expression o instanceof
Rectangle
evaluates to false
.
public class Circle extends Shape { @Override public boolean equals(final Object o) { if (o instanceof Circle c){ return super.equalCenter(c) && Math.abs(c.radius - radius) < 1.E-15; } return false; } ...
|
r1.equals(r2): false r1.equals(r3): true c.equals(r1): false |
@Override
annotation.
public class Shape {
double x, y;
...
@Override // Promise: Subsequent method overrides Object.toString();
public String toString() {
return "(" + x + "|" + y + ")";
}
}
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 + ")";
}
}
Explanation: The given method does not override Object.toString()
.