Vererbung mit extends
Eine Unterklasse übernimmt Felder und Methoden der Oberklasse und kann sie ergänzen oder überschreiben:
public class Tiere {
static class Tier {
protected String name;
Tier(String name) { this.name = name; }
String laut() { return "..."; }
String vorstellen() { return name + " macht " + laut(); }
}
static class Hund extends Tier {
Hund(String name) { super(name); } // Konstruktor der Oberklasse
@Override String laut() { return "Wuff"; }
}
static class Katze extends Tier {
Katze(String name) { super(name); }
@Override String laut() { return "Miau"; }
@Override String vorstellen() { return super.vorstellen() + " (und schnurrt)"; }
}
public static void main(String[] args) {
Tier[] tiere = { new Hund("Rex"), new Katze("Mimi"), new Tier("Etwas") };
for (Tier t : tiere) System.out.println(t.vorstellen()); // Polymorphie
}
}Rex macht Wuff Mimi macht Miau (und schnurrt) Etwas macht ...
super(...)ruft den Konstruktor der Oberklasse auf (erste Anweisung)@Overridesagt dem Compiler: "Ich überschreibe bewusst." Er meldet Tippfehler- Polymorphie: Eine Variable vom Typ
Tierkann einenHundhalten; beim Aufruf gilt die Methode des tatsächlichen Objekts - Java erlaubt nur eine Oberklasse (keine Mehrfachvererbung von Klassen)
final classlässt sich nicht erweitern,finalbei Methoden nicht überschreiben
Abstrakte Klassen
Eine abstrakte Klasse ist nur Vorlage. Sie darf nicht instanziiert werden und kann abstrakte Methoden enthalten:
public class Formen {
static abstract class Form {
abstract double flaeche();
String info() { return getClass().getSimpleName() + " mit Fläche " + String.format("%.2f", flaeche()); }
}
static class Kreis extends Form {
double r; Kreis(double r) { this.r = r; }
double flaeche() { return Math.PI * r * r; }
}
static class Quadrat extends Form {
double a; Quadrat(double a) { this.a = a; }
double flaeche() { return a * a; }
}
public static void main(String[] args) {
for (Form f : new Form[] { new Kreis(1), new Quadrat(3) }) System.out.println(f.info());
}
}Kreis mit Fl?che 3.14 Quadrat mit Fl?che 9.00
Interfaces
Ein Interface beschreibt einen Vertrag: welche Methoden eine Klasse anbieten muss. Eine Klasse kann mehrere Interfaces umsetzen:
public class Fahrzeuge {
interface Fahrbar { void fahren(); default String art() { return "Fahrzeug"; } }
interface Ladbar { void laden(int prozent); }
static class ElektroAuto implements Fahrbar, Ladbar {
private int akku = 20;
public void fahren() { System.out.println("surr, Akku " + akku + "%"); }
public void laden(int p) { akku = Math.min(100, akku + p); }
@Override public String art() { return "Elektroauto"; }
}
static class Fahrrad implements Fahrbar {
public void fahren() { System.out.println("tret tret"); }
}
public static void main(String[] args) {
ElektroAuto e = new ElektroAuto();
e.laden(50);
Fahrbar[] alle = { e, new Fahrrad() };
for (Fahrbar f : alle) { f.fahren(); System.out.println(f.art()); }
}
}surr, Akku 70% Elektroauto tret tret Fahrzeug
Seit Java 8 dürfen Interfaces default-Methoden mit Standardverhalten und static-Methoden enthalten.
Interface oder abstrakte Klasse?
| Interface | Abstrakte Klasse | |
|---|---|---|
| Anzahl pro Klasse | beliebig viele | eine |
| Felder mit Zustand | nein (nur Konstanten) | ja |
| Konstruktor | nein | ja |
| Gedacht für | Fähigkeiten ("kann fahren") | gemeinsame Basis ("ist ein Tier") |
Programmieren gegen Interfaces
Deklariere Variablen und Parameter möglichst mit dem Interface-Typ, nicht mit der konkreten Klasse. Dann lässt sich die Umsetzung später austauschen:
import java.util.*;
public class Schnittstelle {
interface Rabatt { double anwenden(double preis); }
static double endpreis(double preis, Rabatt r) { return r.anwenden(preis); }
public static void main(String[] args) {
List<String> liste = new ArrayList<>(); // Variable: List (Interface), Objekt: ArrayList
liste.add("a");
Rabatt zehnProzent = p -> p * 0.9; // Lambda als Implementierung
Rabatt festbetrag = p -> p - 5;
System.out.println(endpreis(100, zehnProzent) + " " + endpreis(100, festbetrag));
}
}90.0 95.0
Ein Interface mit genau einer abstrakten Methode heißt funktionales Interface und lässt sich mit einem Lambda ausdrücken (siehe Streams).
Komposition statt Vererbung
Vererbung koppelt Klassen eng. Oft ist es besser, ein Objekt zu haben, statt eins zu sein: Ein Auto hat einen Motor, es ist keiner.
public class Komposition {
interface Motor { String start(); }
static class Benzin implements Motor { public String start() { return "brumm"; } }
static class Elektro implements Motor { public String start() { return "surr"; } }
static class Auto {
private final Motor motor;
Auto(Motor motor) { this.motor = motor; } // Motor wird hereingegeben
String starten() { return motor.start(); }
}
public static void main(String[] args) {
System.out.println(new Auto(new Benzin()).starten() + " " + new Auto(new Elektro()).starten());
}
}brumm surr
Object: die Mutter aller Klassen
Jede Klasse erbt von Object: toString(), equals(), hashCode(), getClass().
Merke
class B extends Aerbt;super(...)ruft den Elternkonstruktor,@Overrideüberschreibt bewusst- Polymorphie: Es gilt die Methode des tatsächlichen Objekts
abstractfür Vorlagen;interfacefür Verträge und Fähigkeiten (mehrere möglich)- Programmiere gegen Interfaces, bevorzuge Komposition
- Jede Klasse erbt von
Object
Aufgabe
Modelliere Mitarbeiter (abstrakt, mit gehalt()) und zwei Unterklassen. Berechne die Gehaltssumme einer gemischten Liste.