Week 3: Methods and Object Orientation II
27.04.2026
Slides
Download Week 3 Slides (PDF) →
Code Examples
Three reference packages, each mapped to one of today’s main ideas: inheritance with overriding, the delegation pattern, and a small simulation.
Code/Week3/src/at/ac/univie/gis/week3/
├── inheritance/
│ ├── Geometry.java Parent class (name field + default toString)
│ ├── Point.java extends Geometry; overrides toString + equals
│ └── InheritanceMain.java Polymorphism demo, == vs .equals()
├── polyline/
│ ├── Point.java Lightweight 2D point, no inheritance
│ ├── PolyLine.java HAS-A ArrayList<Point> (delegation)
│ └── PolyLineMain.java Builds a polyline, iterates, prints length
└── zombies/
├── Corridor.java int[] cells with the step() rule
└── ZombiesMain.java Runs the corridor until it stabilises
1. inheritance/ — extends, toString, equals
Geometry.java — The parent class. Holds a protected name field shared by every geometry (slide 23 visibility level) and a default toString that subclasses are free to override.
package at.ac.univie.gis.week3.inheritance;
/**
* A simple parent class in our small geometry hierarchy.
* Every Geometry has a name (just a label, e.g. "origin", "lake-outline").
*
* The name field is protected, which is the visibility level introduced
* on slide 23: visible to this class and to any subclass, but not to
* unrelated outside code.
*/
public class Geometry {
// protected: a subclass like Point can read and write this field directly.
protected String name = "";
public String getName() {
return name;
}
/**
* Default text representation. Subclasses typically override this
* to include their own fields (see Point.toString).
*/
@Override
public String toString() {
return "Geometry{name=" + name + "}";
}
}
Point.java — A Point IS-A Geometry. Adds x and y, sets the inherited name via direct protected access, and overrides both toString and equals.
package at.ac.univie.gis.week3.inheritance;
/**
* A Point is-a Geometry, with two coordinate fields added on top.
* Demonstrates extends, accessing a protected field from a subclass,
* and overriding both toString and equals.
*/
public class Point extends Geometry {
private double x;
private double y;
public Point(String name, double x, double y) {
// Parent construction always happens first — Java runs Geometry's
// no-arg constructor before any line in this body executes.
// We then assign the inherited 'name' field directly, which is
// possible because Geometry declared it protected (slide 23).
this.name = name;
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
/**
* Override Geometry's toString so println shows the coordinates,
* not just "Geometry{name=...}".
*/
@Override
public String toString() {
return "Point{name=" + name + ", x=" + x + ", y=" + y + "}";
}
/**
* Override Object's equals so two Points with the same coordinates
* compare equal. Without this, .equals falls back to == (identity).
* getClass() comes from Object — every class has it for free.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || o.getClass() != this.getClass()) return false;
Point other = (Point) o;
return x == other.x && y == other.y;
}
}
InheritanceMain.java — A Geometry variable holding a Point still calls Point’s toString (dynamic dispatch). Side-by-side comparison of == and .equals().
package at.ac.univie.gis.week3.inheritance;
/**
* Demonstrates the three ideas from the inheritance block:
* 1. extends + super(...) constructor handoff
* 2. toString override (dispatched at runtime)
* 3. equals override vs ==
*/
public class InheritanceMain {
public static void main(String[] args) {
// A Point IS-A Geometry, so a Geometry-typed variable can hold a Point.
// When we print g, Java picks Point's toString at runtime, not Geometry's.
Geometry g = new Point("origin", 0, 0);
System.out.println(g);
// Two distinct Point objects with the same coordinates.
Point a = new Point("a", 3, 4);
Point b = new Point("b", 3, 4);
Point c = a;
// == compares object identity (memory address).
// .equals compares values, because we overrode it on Point.
System.out.println("a == b: " + (a == b)); // false: different objects
System.out.println("a.equals(b): " + a.equals(b)); // true: same coordinates
System.out.println("a == c: " + (a == c)); // true: same reference
}
}
2. polyline/ — ArrayList + delegation
Point.java — A lightweight 2D point used by PolyLine. Deliberately independent from the inheritance package so this example stays self-contained — two classes named Point can coexist in different packages.
package at.ac.univie.gis.week3.polyline;
/**
* A simple 2D point used by PolyLine. Kept independent from the
* inheritance package so the delegation example stays self-contained.
* (Two classes named Point can coexist because they live in different
* packages — that's exactly what packages buy you.)
*/
public class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double distanceTo(Point other) {
double dx = x - other.x;
double dy = y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
PolyLine.java — HAS-A relationship: a PolyLine holds a private ArrayList<Point>. Note we do not write extends ArrayList — a polyline is not a kind of list, it just uses one.
package at.ac.univie.gis.week3.polyline;
import java.util.ArrayList;
/**
* PolyLine HAS-A list of points (delegation), it is NOT-A list.
* We do not write "class PolyLine extends ArrayList" — a polyline is
* not a kind of list, it just uses one internally to store its vertices.
*
* Outside callers only see the methods we choose to expose
* (addPoint, size, get, length). The ArrayList itself stays private.
*/
public class PolyLine {
private ArrayList<Point> vertices;
public PolyLine() {
vertices = new ArrayList<Point>();
}
public void addPoint(Point p) {
vertices.add(p);
}
public int size() {
return vertices.size();
}
public Point get(int index) {
return vertices.get(index);
}
/**
* Total length: sum of distances between consecutive vertices.
* A two-vertex polyline reduces to one segment; a one-vertex or
* empty polyline has length 0.
*/
public double length() {
double total = 0;
for (int i = 1; i < vertices.size(); i++) {
total += vertices.get(i - 1).distanceTo(vertices.get(i));
}
return total;
}
}
PolyLineMain.java — Adds three points, iterates, prints each vertex, and prints the total length.
package at.ac.univie.gis.week3.polyline;
/**
* Builds a small polyline, iterates over its vertices, prints each one,
* and finally prints the total length. Demonstrates how an ArrayList
* makes "I do not know yet how many points there will be" a non-issue.
*/
public class PolyLineMain {
public static void main(String[] args) {
PolyLine line = new PolyLine();
line.addPoint(new Point(0, 0));
line.addPoint(new Point(3, 0));
line.addPoint(new Point(3, 4));
for (int i = 0; i < line.size(); i++) {
System.out.println("vertex " + i + ": " + line.get(i));
}
System.out.println("total length: " + line.length());
}
}
3. zombies/ — the corridor simulation
Corridor.java — A row of cells. Each step() snapshots the current state, then for every cell with more than one zombie, removes two and adds one to the cell on its left. The leftmost cell’s outgoing zombie just disappears.
package at.ac.univie.gis.week3.zombies;
import java.util.Arrays;
/**
* A single linear corridor of cells. Each cell holds a zombie count.
*
* Movement rule (slide 33): if a cell holds more than one zombie,
* one moves to the cell on its left and one disappears. The leftmost
* cell cannot move further left, so its outgoing zombie just vanishes.
*
* The rule is applied to every cell based on its state at the *start*
* of the step. We achieve that by writing into a copy.
*/
public class Corridor {
private int[] cells;
public Corridor(int[] initial) {
this.cells = initial.clone();
}
/**
* The simulation has stabilised when no cell has more than one zombie.
*/
public boolean isStable() {
for (int c : cells) {
if (c > 1) return false;
}
return true;
}
public void step() {
int[] next = cells.clone();
for (int i = 0; i < cells.length; i++) {
if (cells[i] > 1) {
next[i] -= 2;
if (i > 0) {
next[i - 1] += 1;
}
}
}
cells = next;
}
@Override
public String toString() {
return Arrays.toString(cells);
}
}
ZombiesMain.java — Starts with [0, 0, 0, 0, 4] and steps until the corridor is stable, printing each step.
package at.ac.univie.gis.week3.zombies;
/**
* Runs the zombie corridor simulation from the slide:
* start with [0, 0, 0, 0, 4], step until every cell holds at most one.
*/
public class ZombiesMain {
public static void main(String[] args) {
Corridor corridor = new Corridor(new int[]{0, 0, 0, 0, 4});
int step = 0;
System.out.println("step " + step + ": " + corridor);
while (!corridor.isStable()) {
corridor.step();
step++;
System.out.println("step " + step + ": " + corridor);
}
System.out.println("stable after " + step + " steps");
}
}
Assignment (Optional)
Week 3 Assignment
Reading: Chapters on the static keyword and ArrayList. Explore the official Java API — in particular the Arrays class.
Coding: Start building a simple epidemic simulation.
- Create a
Personclass with a health state (SUSCEPTIBLE,INFECTIOUS,RECOVERED) and a random, static location (no movement yet) - Define a rectangular study area and write a method that selects all people located inside it
- Implement infection logic based on a distance radius and a probability
- Validate by printing state changes to the console — do not run a continuous simulation yet
Submission: Upload FirstNameLastNameW3.zip with your .java files
Deadline: Sunday at 5:00 PM (Vienna Time)