Hoofdstuk 11 — OOP: Klassen en Objecten (basis van objectgeoriënteerd denken)
In dit hoofdstuk maak je de stap van losse functies en gegevens naar samenhangende eenheden: objecten. Je leert wat klassen en objecten zijn, hoe je velden en methoden definieert, hoe constructors werken, wat this doet, en waarom inkapseling (encapsulation) met getters/setters nuttig is. We bekijken ook toString, equals/hashCode en geven praktische tips.
Voorbeeld 1 — Een eenvoudige klasse met veld en methode
class Persoon {
String naam; // veld (instantievariabele)
void groet() { // instantie-methode
System.out.println("Hallo, " + naam);
}
}
public class Demo1 {
public static void main(String[] args) {
Persoon p = new Persoon(); // object maken
p.naam = "Saar"; // veld rechtstreeks zetten (later: encapsuleren)
p.groet(); // methode aanroepen
}
}
Voorbeeld 2 — Constructor voor verplichte initialisatie
class Punt {
int x, y;
Punt(int x, int y) { // constructor
this.x = x; // this verwijst naar het huidige object
this.y = y;
}
}
public class Demo2 {
public static void main(String[] args) {
Punt p = new Punt(3, 4);
System.out.println("(" + p.x + ", " + p.y + ")");
}
}
Voorbeeld 3 — Encapsulation met private velden en getters/setters
class BankRekening {
private String iban; // afschermen voor directe toegang
private double saldo;
public BankRekening(String iban) {
this.iban = iban;
}
public String getIban() { return iban; }
public double getSaldo() { return saldo; }
public void stort(double bedrag) {
if (bedrag <= 0) throw new IllegalArgumentException("Bedrag moet > 0");
saldo += bedrag;
}
public void neemOp(double bedrag) {
if (bedrag <= 0 || bedrag > saldo) throw new IllegalArgumentException("Ongeldig bedrag");
saldo -= bedrag;
}
}
public class Demo3 {
public static void main(String[] args) {
BankRekening r = new BankRekening("NL00BANK0123456789");
r.stort(100);
r.neemOp(30);
System.out.println("Saldo: " + r.getSaldo());
}
}
Voorbeeld 4 — toString() voor leesbare weergave
class Product {
private final String naam;
private final double prijs;
Product(String naam, double prijs) {
this.naam = naam; this.prijs = prijs;
}
@Override public String toString() {
return "Product{" + "naam='" + naam + '\'' + ", prijs=" + prijs + '}';
}
}
public class Demo4 {
public static void main(String[] args) {
System.out.println(new Product("Mok", 7.95));
}
}
Voorbeeld 5 — equals en hashCode voor waardevergelijking
import java.util.Objects;
class Kaart {
private final String soort; // bijv. harten, schoppen
private final String rang; // bijv. boer, vrouw, aas
Kaart(String soort, String rang) {
this.soort = soort; this.rang = rang;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Kaart kaart = (Kaart) o;
return Objects.equals(soort, kaart.soort) && Objects.equals(rang, kaart.rang);
}
@Override public int hashCode() {
return Objects.hash(soort, rang);
}
}
public class Demo5 {
public static void main(String[] args) {
System.out.println(new Kaart("harten", "aas").equals(new Kaart("harten", "aas"))); // true
}
}
Voorbeeld 6 — Statische leden vs. instantieleden
class Teller {
static int aantalObjecten = 0; // gedeeld door alle instanties
int waarde; // per object verschillend
Teller(int waarde) {
this.waarde = waarde;
aantalObjecten++;
}
}
public class Demo6 {
public static void main(String[] args) {
Teller a = new Teller(1);
Teller b = new Teller(2);
System.out.println(Teller.aantalObjecten); // 2
System.out.println(a.waarde + ", " + b.waarde);
}
}
Voorbeeld 7 — Samenspel van objecten (compositie)
class Adres { String straat; String stad; Adres(String straat, String stad){this.straat=straat;this.stad=stad;} }
class Klant {
String naam;
Adres adres; // Klant heeft een Adres
Klant(String naam, Adres adres) { this.naam = naam; this.adres = adres; }
}
public class Demo7 {
public static void main(String[] args) {
Adres a = new Adres("Laan 1", "Utrecht");
Klant k = new Klant("Kim", a);
System.out.println(k.naam + " uit " + k.adres.stad);
}
}
Voorbeeld 8 — Method chaining en builder-achtig patroon
class BerichtBuilder {
private final StringBuilder sb = new StringBuilder();
BerichtBuilder voegToe(String s) { sb.append(s); return this; }
String build() { return sb.toString(); }
}
public class Demo8 {
public static void main(String[] args) {
String bericht = new BerichtBuilder().voegToe("Hallo").voegToe(", ").voegToe("wereld").build();
System.out.println(bericht);
}
}
Veelgemaakte fouten en tips:
- Gebruik
privatevoor velden en exposeer gedrag via methoden; vermijd publieke velden tenzij goede reden. - Vergeet
thisniet wanneer parameternaam gelijk is aan veldnaam. - Herdefinieer
toStringvoor debugbaarheid; overweegequals/hashCodevoor waardeobjecten. - Maak onveranderlijke (immutable) objecten waar mogelijk: gebruik
finalvelden en geen setters.
Koppeling met oefeningen:
- Zie
java-workbook/src/chapter_11.mdvoor opdrachten over klassen/objecten, constructors en encapsulation. - Uitwerkingen staan in
java-solutions/src/chapter_11.mden bijbehorende .java-bestanden.