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
ObjectLecture notes |
Pdf slides |
|
(#1 of 3) |
Shape extending
ObjectLecture notes |
Pdf slides |
|
(#2 of 3) |
Shape extending
ObjectLecture notes |
Pdf slides |
|
(#3 of 3) |
Rectangle instances
Lecture notes |
Pdf slides |
|
toString() in class
Rectangle.
Lecture notes |
Pdf slides |
|
Rectangle extending
ShapeLecture notes |
Pdf slides |
|
(#1 of 4) |
Rectangle extending
ShapeLecture notes |
Pdf slides |
|
(#2 of 4) |
Rectangle extending
ShapeLecture notes |
Pdf slides |
|
(#3 of 4) |
Rectangle extending
ShapeLecture 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 |
|
Lecture notes |
Pdf slides |
|
(#1 of 3) |
Lecture notes |
Pdf slides |
|
(#2 of 3) |
Lecture notes |
Pdf slides |
|
(#3 of 3) |
Lecture notes |
Pdf slides |
|
getArea()Lecture notes |
Pdf slides |
|
getArea() call
Lecture notes |
Pdf slides |
|
Lecture notes |
Pdf slides |
|
(#1 of 3) |
Lecture notes |
Pdf slides |
|
(#2 of 3) |
Lecture notes |
Pdf slides |
|
(#3 of 3) |
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 {
private double x, y;
...
@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 {
@Override // Syntax error: 'move(int, int)' cannot override
public void move(int xTrans, int yTrans) {... // 'move(int, int)' in 'inherit.Shape',
// overridden method is final |
|
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.); // Error: '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) {
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().
| Code | final Object[] instances = {
new String("Test"),
new Date()
};
printMetaInfo(instances);
-----------------------------------------------------
static void printMetaInfo(Object[] objects) {
for (Object o: objects) {
System.out.println(o.getClass().getName());
}
} |
|---|---|
| Result | java.lang.String java.util.Date |
|
|
|
|
| Code | final Shape[] shapes = {
new Rectangle(0, 0, 2, 3),
new Circle(0, 0, 1)};
}
printAreas(shapes);
----------------------------------------
static void printAreas(Shape[] shapes) {
for (Shape shape : shapes) {
System.out.println(shape.getArea());
}
} |
|---|---|
| Result | Area:6.0 Area:3.141592653589793 |