Q1 OOP in Java

Konstruktoren überladen

Lösung geprüft

Die Aufgabe der heutigen Stunde ist das Überladen von Konstruktoren! Beim Dreieck haben wir das eben schon nebenbei gemacht, jetzt schauen wir uns an, warum das überhaupt geht und wo die Fallstricke liegen.

Die Idee dahinter ist simpel: eine Klasse darf mehrere Konstruktoren haben, solange sich deren Parameterlisten unterscheiden – in der Anzahl, in den Typen oder in der Reihenfolge. Java sucht sich beim new selbst den passenden raus.

Die Aufgabenstellung lautet

a) Beschreiben (nicht programmieren) Sie ein weiteres sinnvolles Beispiel zur Konstruktor-Überladung mit Datentypen.

b) Programmieren Sie das sinnvolle Beispiel für die Überladung von einem Konstruktor.

Was vorgegeben ist

Als Beispiel dient ein Rechteck mit drei Konstruktoren:

Rechteck.java (vorgegeben)
/* meininfokurs.cmrg.site */
public class Rechteck {
    // Defaultwerte
    private double breite = 1;
    private double hoehe  = 1;

    // Konstuktor 1 Parameter: double, double
    public Rechteck(double breite, double hoehe) {
        if (breite >= 0 && hoehe >= 0) {
            this.breite = breite;
            this.hoehe  = hoehe;
        }
    }

    // Konstuktor 2 Parameter: double, double
    public Rechteck(int breite, int hoehe) {
        if (breite >= 0 && hoehe >= 0) {
            this.breite = breite;
            this.hoehe  = hoehe;
        }
    }

    // Konstuktor 3 Parameter: double
    public Rechteck(double seite) {
        if (seite >= 0) {
            this.breite = seite;
            this.hoehe  = seite;
        }
    }
}

Konstruktor 3 ist der interessanteste: ein Rechteck mit nur einer Seitenangabe ist ein Quadrat. Man spart sich also eine eigene Klasse.

classDiagram
    class Rechteck {
        -double breite = 1
        -double hoehe = 1
        +Rechteck(double, double)
        +Rechteck(int, int)
        +Rechteck(double)
    }
Drei Konstruktoren, drei Parameterlisten

Alle drei heißen Rechteck, und trotzdem kann Java sie auseinanderhalten: der erste nimmt zwei double, der zweite zwei int, der dritte nur einen Wert. Die Parameterliste ist das einzige Unterscheidungsmerkmal.

Lösungsprozess der Aufgabe

Konto.java
/* meininfokurs.cmrg.site */
/**
 *
 * Konstruktor-Ueberladung am Beispiel eines Bankkontos
 *
 * @version 1.0 vom 25.08.2025
 * @meininfokurs.cmrg.site
 */

public class Konto {

    // Defaultwerte, falls ein Konstruktor nichts setzt
    private String inhaber = "Unbekannt";
    private double kontostand = 0;
    private double dispo = 0;

    // Konstruktor 1 - Parameter: String
    // Neues Konto, nur der Name ist bekannt. Startet bei 0 Euro.
    public Konto(String inhaber) {
        if (inhaber != null && !inhaber.equals("")) {
            this.inhaber = inhaber;
        }
    }

    // Konstruktor 2 - Parameter: String, double
    // Konto mit Startguthaben, zum Beispiel bei einem Bankwechsel.
    public Konto(String inhaber, double kontostand) {
        if (inhaber != null && !inhaber.equals("")) {
            this.inhaber = inhaber;
        }
        this.kontostand = kontostand;
    }

    // Konstruktor 3 - Parameter: String, double, double
    // Konto mit Startguthaben und eingeraeumtem Dispo.
    public Konto(String inhaber, double kontostand, double dispo) {
        if (inhaber != null && !inhaber.equals("")) {
            this.inhaber = inhaber;
        }
        this.kontostand = kontostand;
        if (dispo >= 0) {
            this.dispo = dispo;
        }
    }

    public double getKontostand() {
        return kontostand;
    }

    public void einzahlen(double betrag) {
        if (betrag <= 0) {
            System.out.println("Fehler: Der Betrag muss positiv sein.");
            return;
        }
        kontostand += betrag;
    }

    public void abheben(double betrag) {
        if (betrag <= 0) {
            System.out.println("Fehler: Der Betrag muss positiv sein.");
            return;
        }
        if (kontostand - betrag < -dispo) {
            System.out.println("Fehler: Das ueberzieht den Dispo.");
            return;
        }
        kontostand -= betrag;
    }

    public void ausgabe() {
        String info = "Konto von " + inhaber + "\n"
                    + "  Kontostand: " + InOut.format2(kontostand) + " Euro\n"
                    + "  Dispo: " + InOut.format2(dispo) + " Euro";
        System.out.println(info);
    }

} // end of class Konto

Teil a) – das Beispiel beschreiben

Gefragt ist erstmal Text, kein Code. Mein Beispiel ist ein Bankkonto, und zwar aus folgendem Grund: es gibt wirklich drei verschiedene Situationen, in denen ein Konto entsteht, und in jeder weiß man unterschiedlich viel.

KonstruktorParameterWann man ihn braucht
1StringKonto frisch eröffnet, es liegt noch kein Geld drauf
2String, doubleBankwechsel – das Guthaben kommt mit
3String, double, doubleKonto mit eingeräumtem Dispo

Alle drei unterscheiden sich in der Anzahl der Parameter. Das ist die einfachste und sicherste Art zu überladen, da kann sich Java nicht vertun.

Die Defaultwerte oben

Der Trick aus dem Rechteck-Beispiel funktioniert hier genauso: die Attribute bekommen schon bei der Deklaration einen sinnvollen Wert.

private String inhaber = "Unbekannt";
private double kontostand = 0;
private double dispo = 0;

Dadurch muss nicht jeder Konstruktor jedes Attribut setzen. Konstruktor 1 kümmert sich nur um den Namen, Kontostand und Dispo bleiben automatisch bei 0. Ohne Defaultwerte müsstest du in jedem Konstruktor alles nochmal hinschreiben – und vergisst dann garantiert eins.

Die zwei Regeln, die man wissen muss

Erstens: der Rückgabetyp zählt nicht. Zwei Methoden, die sich nur im Rückgabetyp unterscheiden, sind für Java dieselbe Methode und das ist ein Fehler. Bei Konstruktoren ist das sowieso egal, die haben gar keinen – bei normalen Methoden ist es aber eine beliebte Falle.

Zweitens: sobald du selbst einen Konstruktor schreibst, ist der automatische weg. Solange eine Klasse gar keinen Konstruktor hat, spendiert Java stillschweigend einen parameterlosen:

public Rechteck() {}   // macht Java selbst - aber nur, solange du keinen eigenen schreibst

Der erzeugt nur das Objekt und initialisiert nichts. Schreibst du einen eigenen Konstruktor, verschwindet der. Wenn du dann irgendwo new Konto() ohne Argumente schreibst, meckert der Compiler – und die Fehlermeldung ist ziemlich unverständlich, wenn man nicht weiß woran es liegt. Willst du beides haben, musst du den leeren Konstruktor selbst dazuschreiben.

Vorsicht bei int und double

Im vorgegebenen Rechteck stehen Konstruktor 1 mit (double, double) und Konstruktor 2 mit (int, int). Das ist erlaubt, aber es ist auch das Beispiel, bei dem man am ehesten ins Grübeln kommt. Was passiert bei new Rechteck(3, 4)?

Da 3 und 4 Ganzzahlen sind, nimmt Java Konstruktor 2. Erst wenn kein int-Konstruktor da wäre, würde Java die Werte automatisch in double umwandeln und Konstruktor 1 nehmen. Schreibst du dagegen new Rechteck(3.0, 4.0), ist Konstruktor 1 dran.

Deshalb habe ich das in meinem Konto-Beispiel bewusst nicht gemacht. Überladen über die Anzahl der Parameter ist eindeutig; überladen über ähnliche Zahlentypen sieht clever aus, sorgt aber für Code, bei dem man zweimal hinschauen muss. Und der Kommentar über Konstruktor 2 im Rechteck ist übrigens falsch – da steht „Parameter: double, double", obwohl int, int gemeint ist. Genau so entstehen Missverständnisse.

Aufgabe suchen

Tippe los. Strg+K öffnet die Suche von überall.

Zuletzt angesehen

Werbung