Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien zum Buch
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichen und Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Schnittstellen, Aufzählungen, versiegelte Klassen, Records
9 Ausnahmen müssen sein
10 Geschachtelte Typen
11 Besondere Typen der Java SE
12 Generics<T>
13 Lambda-Ausdrücke und funktionale Programmierung
14 Architektur, Design und angewandte Objektorientierung
15 Java Platform Module System
16 Die Klassenbibliothek
17 Einführung in die nebenläufige Programmierung
18 Einführung in Datenstrukturen und Algorithmen
19 Einführung in grafische Oberflächen
20 Einführung in Dateien und Datenströme
21 Einführung ins Datenbankmanagement mit JDBC
22 Bits und Bytes, Mathematisches und Geld
23 Testen mit JUnit
24 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 7 Objektorientierte Beziehungsfragen
Pfeil 7.1 Assoziationen zwischen Objekten
Pfeil 7.1.1 Unidirektionale 1:1-Beziehung
Pfeil 7.1.2 Zwei Freunde müsst ihr werden – bidirektionale 1:1-Beziehungen
Pfeil 7.1.3 Unidirektionale 1:n-Beziehung
Pfeil 7.2 Vererbung
Pfeil 7.2.1 Vererbung in Java
Pfeil 7.2.2 Ereignisse modellieren
Pfeil 7.2.3 Die implizite Basisklasse java.lang.Object
Pfeil 7.2.4 Einfach- und Mehrfachvererbung *
Pfeil 7.2.5 Sehen Kinder alles? Die Sichtbarkeit protected
Pfeil 7.2.6 Konstruktoren in der Vererbung und super(…)
Pfeil 7.3 Typen in Hierarchien
Pfeil 7.3.1 Automatische und explizite Typumwandlung
Pfeil 7.3.2 Das Substitutionsprinzip
Pfeil 7.3.3 Typen mit dem instanceof-Operator testen
Pfeil 7.3.4 Pattern-Matching bei instanceof
Pfeil 7.4 Methoden überschreiben
Pfeil 7.4.1 Methoden in Unterklassen mit neuem Verhalten ausstatten
Pfeil 7.4.2 Mit super an die Eltern
Pfeil 7.5 Drum prüfe, wer sich dynamisch bindet
Pfeil 7.5.1 Gebunden an toString()
Pfeil 7.5.2 Implementierung von System.out.println(Object)
Pfeil 7.6 Finale Klassen und finale Methoden
Pfeil 7.6.1 Finale Klassen
Pfeil 7.6.2 Nicht überschreibbare (finale) Methoden
Pfeil 7.7 Abstrakte Klassen und abstrakte Methoden
Pfeil 7.7.1 Abstrakte Klassen
Pfeil 7.7.2 Abstrakte Methoden
Pfeil 7.8 Weiteres zum Überschreiben und dynamischen Binden
Pfeil 7.8.1 Nicht dynamisch gebunden bei privaten, statischen und finalen Methoden
Pfeil 7.8.2 Kovariante Rückgabetypen
Pfeil 7.8.3 Array-Typen und Kovarianz *
Pfeil 7.8.4 Dynamisch gebunden auch bei Konstruktoraufrufen *
Pfeil 7.8.5 Keine dynamische Bindung bei überdeckten Objektvariablen *
Pfeil 7.9 Zum Weiterlesen und Programmieraufgabe
 

Zum Seitenanfang

7.2    Vererbung Zur vorigen ÜberschriftZur nächsten Überschrift

Schon von Kindheit an lernen wir, Objekte in Beziehung zu setzen. Assoziationen bilden dabei die Hat-Beziehung zwischen Objekten ab: Ein Teddy hat (direkt nach dem Kauf) zwei Arme, der Tisch hat vier Beine, der Wauwau hat ein Fell.

Neben der Assoziation von Objekten gibt es eine weitere Form der Beziehung, die Ist-eine-Art-von-Beziehung. Auch das ist uns aus dem Alltag bekannt:

  • Apfel und Birne sind Obstsorten.

  • Menschen und Möwen sind Lebewesen.

  • Menschen und Fledermäuse sind Säugetiere.

  • Lotad, Seedot und Wingull sind verschiedene Pokémon.

Beispiele zur VererbungVererbung und Assoziation

Abbildung 7.7     Beispiele zur Vererbung und Assoziation

Das Besondere bei der Ist-eine-Art-von-Beziehung ist die Tatsache, dass die Gruppe gewisse Merkmale für alle Elemente der Gruppe vorgibt.[ 158 ](Semantische Netzwerke sind in der kognitiven Psychologie ein Erklärungsmodell zur Wissensrepräsentation. Eigenschaften gehören zu Kategorien, die durch Ist-eine-Art-von-Beziehungen hierarchisch verbunden sind. Informationen, die nicht bei einem speziellen Konzept abgespeichert sind, lassen sich von einem übergeordneten Konzept abrufen. ) Obst ist roh essbar, Gebäude haben eine Fläche, Säugetiere haben eine gleichwarme Körpertemperatur, und so weiter. Wir sprechen hier von Generalisierung[ 159 ](»All generalizations are false, including this one.« (Mark Twain) ) und Spezialisierung.[ 160 ](So etwas gibt es auch in der Linguistik; dort heißt der Oberbegriff eines Begriffs Hyperonym und der Unterbegriff eines Begriffs Hyponym. )

Programmiersprachen drücken Gruppierung und Hierarchiebildung über die Vererbung aus. Vererbung basiert auf der Vorstellung, dass Eltern ihren Kindern Eigenschaften mitgeben. Vererbung bindet die Klassen sehr dicht aneinander. Mittels dieser engen Verbindung können wir später sehen, dass Klassen in gewisser Weise austauschbar sind. Ein Programm kann ausdrücken: »Gib mir irgendein Obststück«, und es bekommt dann vielleicht einen Apfel oder eine Birne.

 

Zum Seitenanfang

7.2.1    Vererbung in Java Zur vorigen ÜberschriftZur nächsten Überschrift

Java ordnet Typen in hierarchischen Relationen an, in denen sie Ist-eine-Art-von-Beziehungen bilden. Eine neu deklarierte Klasse erweitert durch das Schlüsselwort extends eine andere Klasse. Sie wird dann zur Unterklasse (auch Subklasse, Kindklasse oder Erweiterungsklasse genannt). Die Klasse, von der die Unterklasse erbt, heißt Oberklasse (auch Superklasse oder Elternklasse). Auch die Begriffe Vorfahre und Nachkomme werden von manchen Autoren verwendet.

Durch den Vererbungsmechanismus werden alle sichtbaren Eigenschaften der Oberklasse auf die Unterklasse übertragen. Eine Oberklasse vererbt also Eigenschaften, und die Unterklasse erbt sie.

[»]  Hinweis

In Java können nur Untertypen von Klassen deklariert werden. Einschränkungen von primitiven Typen – etwa im Wertebereich oder in der Anzahl der Nachkommastellen – sind nicht möglich. Die Programmiersprache Ada erlaubt das zum Beispiel, und Untertypen sind beim XML-Schema üblich, wo etwa xs:short oder xs:unsignedByte Untertypen von xs:integer sind.

 

Zum Seitenanfang

7.2.2    Ereignisse modellieren Zur vorigen ÜberschriftZur nächsten Überschrift

Bei unserem Spiel soll der Spieler in eine andere Stadt reisen können, und dabei kann zufällig etwas passieren. Diese Ereignisarten wollen wir in einer Klassenhierarchie aufbauen, bei der es eine allgemeine Oberklasse für ein Ereignis – das können wir auch Aktivität nennen – gibt und dann diverse Unterklassen für spezielle Aktivitäten.

Basisklasse für alle Gemeinsamkeiten

Die Basisklasse (Oberklasse) soll Event heißen, und da jedes Ereignis eine Kennung und eine Dauer hat, bekommt die Klasse die Objektvariablen about und duration.

Listing 7.11     src/main/java/com/tutego/insel/game/c/vl/Event.java, Event

class Event {

String about;

int duration;

}

Zwei Unterklassen

Ein schönes Schläfchen ist ebenfalls ein Ereignis und soll als Unterklasse modelliert werden. Die Klasse Nap erweitert Event und fügt nichts hinzu:

Listing 7.12     src/main/java/com/tutego/insel/game/c/vl/Nap.java, Nap

class Nap extends Event { }

Syntaktisch wird die Vererbung durch das Schlüsselwort extends beschrieben. Die Deklaration der Klasse Nap trägt den Anhang extends Event.

Neben Nap soll es eine weitere Unterklasse von Event geben: Workout. In diese Klasse kommt eine eigene Objektvariable hinzu:

Listing 7.13     src/main/java/com/tutego/insel/game/c/vl/Workout.java, Workout

public class Workout extends Event {

int caloriesBurned;

}

Die drei Klassen Event, Nap und Workout lassen sich in einem UML-Diagramm darstellen, wobei die Vererbung durch einen Pfeil in Richtung der Oberklasse angegeben ist.

»Nap« und »Workout« sind zwei Unterklassen von »Event«.

Abbildung 7.8     »Nap« und »Workout« sind zwei Unterklassen von »Event«.

Unterklassen erben Eigenschaften und haben enge Kopplung

Die Klassen Nap und Workout erben aus der Oberklasse die Objektvariablen about und duration und können in ihren eigenen Methoden und Konstruktoren problemlos darauf zugreifen. Die vererbten Eigenschaften behalten ihre Sichtbarkeit, sodass eine Eigenschaft public weiterhin public bleibt. Private Eigenschaften sind für andere Klassen nicht sichtbar, also auch nicht für die Unterklassen; sie erben somit private Eigenschaften nicht. Wenn sich in der Oberklasse der Typ der Variablen oder die Implementierung einer Methode ändert, wird auch die Unterklasse diese Änderung zu spüren bekommen. Daher ist die Kopplung mittels Vererbung sehr eng, denn die Unterklassen sind Änderungen der Oberklassen ausgeliefert, da ja Oberklassen nichts von Unterklassen wissen.

Ein kleines Beispielprogramm zeigt, dass der Client im Grunde nicht weiß, warum ein Typ etwas »hat« und aus welcher (Basis-)Klasse die Eigenschaften kommen.

Listing 7.14     src/main/java/com/tutego/insel/game/c/vl/Application.java, main

Workout walking = new Workout();

walking.about = "Laufen gehen"; // Zugriff auf geerbte Objektvariable

walking.duration = 30; // Zugriff auf geerbte Objektvariable

walking.caloriesBurned = 200; // Zugriff auf eigene Objektvariable



Nap sleeping = new Nap();

sleeping.about = "Erholungsschlaf"; // Zugriff auf geerbte Objektvariable

sleeping.duration = 60; // Zugriff auf geerbte Objektvariable

Die Ist-eine-Art-von-Hierarchie muss nicht auf einer Ebene aufhören. Wir könnten uns unter Nap auch noch eine Unterklasse PowerNap vorstellen, als Spezialisierung von Nap. PowerNap kann vielleicht zusätzlich Dinge enthalten, die ein normaler Schlaf nicht hat. Und da Nap ein Event ist, würde bei der Unterklasse PowerNap von Nap transitiv gelten, dass ein PowerNap ebenso eine Art von Event ist.

 

Zum Seitenanfang

7.2.3    Die implizite Basisklasse java.lang.Object Zur vorigen ÜberschriftZur nächsten Überschrift

Steht keine ausdrückliche extends-Anweisung hinter einem Klassennamen – wie in dem Beispiel Event –, so erbt die Klasse automatisch von java.lang.Object, einer impliziten Basisklasse. Steht also keine ausdrückliche Oberklasse, wie bei

class Event

so ist das gleichwertig mit:

class Event extends Object

Alle Klassen haben somit direkt oder indirekt die Klasse java.lang.Object als Basisklasse und erben so eine Reihe von Methoden, wie toString(). Daher tauchen in der Tastaturvervollständigung einer IDE auch immer Methoden auf, die nicht von den eigenen Klassen stammen (siehe Abbildung 7.9).

Methoden aus der absoluten Oberklasse »java.lang.Object«

Abbildung 7.9     Methoden aus der absoluten Oberklasse »java.lang.Object«

 

Zum Seitenanfang

7.2.4    Einfach- und Mehrfachvererbung * Zur vorigen ÜberschriftZur nächsten Überschrift

In Java ist auf direktem Weg nur die Einfachvererbung (engl. single inheritance) erlaubt, sodass hinter dem Schlüsselwort extends lediglich eine einzige Klasse steht. Andere objektorientierte Programmiersprachen (wie C++[ 161 ](Bjarne Stroustrup führte Mehrfachvererbung erst in C++ 2.0 (1985–1987) ein. ), Python, Perl oder Eiffel) erlauben Mehrfachvererbung und können mehrere Klassen zu einer neuen verbinden. Doch warum bietet Java neben anderen Sprachen wie C#, Objective-C, Simula, Ruby oder Delphi keine Mehrfachvererbung auf Klassenebene?

Nehmen wir an, die Klassen O1 und O2 deklarieren beide eine öffentliche Methode f(), und U ist eine Klasse, die von O1 und O2 erbt. Steht in U ein Methodenaufruf f(), ist nicht klar, welche der beiden Methoden gemeint ist. In C++ löst der Scope-Operator (::) das Problem, indem der Entwickler immer angibt, aus welcher Oberklasse die Funktion anzusprechen ist.

Dazu gesellt sich das Diamanten-Problem (auch Rauten-Problem genannt). Zwei Klassen, K1 und K2, erben von einer Oberklasse O eine Eigenschaft x. Eine Unterklasse U erbt von den Klassen K1 und K2. Lässt sich in U auf die Eigenschaft x zugreifen? Eigentlich existiert die Eigenschaft ja nur einmal, und es dürfte keinen Grund zur Sorge geben. Dennoch stellt dieses Szenario ein Problem dar, weil der Compiler »vergessen« hat, dass sich x in den Unterklassen K1 und K2 nicht verändert hat. Mit der Einfachvererbung kommt es erst gar nicht zu diesem Dilemma.

Immer wieder wird diskutiert, ob das Fehlen der Mehrfachvererbung Java einschränkt. Nein, das tut es nicht wirklich. Java erlaubt zwar keine multiplen Oberklassen, es erlaubt aber immer noch, mehrere Schnittstellen (Interfaces) zu implementieren und so unterschiedliche Typen anzunehmen. Mit Schnittstellen beschäftigen wir uns im nächsten Kapitel.

 

Zum Seitenanfang

7.2.5    Sehen Kinder alles? Die Sichtbarkeit protected Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Unterklasse erbt alle sichtbaren Eigenschaften. Wir kennen schon public, paketsichtbar und private. Daraus folgt:

  • Sind in der Oberklasse die Eigenschaften public, so sehen auch die Unterklassen die Eigenschaften. Überhaupt sieht sie jeder.

  • Hat die Oberklasse paketsichtbare Eigenschaften, sieht die Unterklasse die Eigenschaften nur dann, wenn die Klassen sich im gleichen Paket befinden. Paketsichtbare Eigenschaften bleiben also auch für Unterklassen privat, wenn sich die Klassen in einem anderen Paket befinden.

  • Die Vererbung kann durch private eingeschränkt werden. Dann sieht keine andere Klasse die Eigenschaften: weder fremde Klassen noch Unterklassen.

Bei öffentlichen, paketsichtbaren und privaten Eigenschaften haben Unterklassen also keine Sonderstellung; sie sehen dadurch nicht »mehr«. Nur protected gibt Unterklassen »mehr«.

[»]  Sprachvergleich

Die Programmiersprache Eiffel hat ein interessantes Feature: Steht an einer neuen Klasse inherit {NONE} Oberklasse, so erbt die Klasse von der genannten Oberklasse, aber die Eigenschaften sind in der neuen Klasse privat und stehen weiteren Unterklassen dieser neuen Klasse nicht zur Verfügung.

Das Schlüsselwort protected

Neben diesen drei Sichtbarkeiten kommt eine vierte hinzu: protected. Diese Sichtbarkeit umfasst (seltsamerweise) zwei Eigenschaften:

  • protected-Eigenschaften werden an alle Unterklassen vererbt.

  • Klassen, die sich im gleichen Paket befinden, können alle protected-Eigenschaften sehen, denn protected ist eine Erweiterung der Paketsichtbarkeit.

Sind also weitere Klassen im gleichen Paket und Eigenschaften protected, ist die Sichtbarkeit für sie public. Für andere Nicht-Unterklassen in anderen Paketen sind die protected-Eigenschaften private. Damit lassen sich die Sichtbarkeiten so ordnen:

public > protected > paketsichtbar > private

[+]  Designtipp

Ist in einer Klasse eine Eigenschaft protected, so ist sie in allen Unterklassen sichtbar, egal, in welchem Paket sich die Unterklasse befindet. Wenn etwa A eine protected-Variable hat und B von A erbt und C von B, dann sieht C ebenfalls die protected-Variable. Das ist in der Regel ein Problem für Objektvariablen, weil schnell ein Implementierungsdetail nach außen dringt und der Code fragil wird. Folglich sollte auf protected-Variablen verzichtet werden.

 

Zum Seitenanfang

7.2.6    Konstruktoren in der Vererbung und super(…) Zur vorigen ÜberschriftZur nächsten Überschrift

Obwohl Konstruktoren Ähnlichkeit mit Methoden haben, etwa in der Eigenschaft, dass sie überladen werden oder Ausnahmen erzeugen können, werden sie im Gegensatz zu Methoden nicht vererbt. Das heißt, eine Unterklasse muss ganz neue Konstruktoren angeben, denn mit den Konstruktoren der Oberklasse kann ein Objekt der Unterklasse nicht erzeugt werden. Ob das nun reine Objektorientierung ist – darüber lässt sich streiten; in der Skriptsprache Python etwa werden auch Konstruktoren vererbt. In Java gehören Konstruktoren eigentlich zum statischen Teil einer Klasse. Die Klasse selbst weiß, wie neue Objekte konstruiert werden. Würden wir Konstruktoren eher als Initialisierungsmethoden ansehen, läge es natürlich näher, sie wie Objektmethoden zu behandeln. Dagegen spricht jedoch, dass eine Unterklasse mehr Eigenschaften hat und der Konstruktor der Oberklasse dann nur einen Teil initialisieren würde.

In Java sammelt eine Unterklasse zwar automatisch alle sichtbaren Eigenschaften der Oberklasse, aber die Initialisierung der einzelnen Eigenschaften pro Hierarchie ist immer noch Aufgabe der jeweiligen Konstruktoren in der Hierarchie. Um diese Initialisierung sicherzustellen, ruft Java im Konstruktor einer jeden Klasse (ausgenommen java.lang.Object) automatisch den parameterlosen Konstruktor der Oberklasse auf, damit die Oberklasse »ihre« Objektvariablen initialisieren kann. Es ist dabei egal, ob der Konstruktor in der Unterklasse parametrisiert ist oder nicht; jeder Konstruktor der Unterklasse muss einen Konstruktor der Oberklasse aufrufen.

Ein Beispiel mit Konstruktorweiterleitung

Sehen wir uns noch einmal die Konstruktorverkettung an:

class Event { }

class Nap extends Event { }

Da wir keine expliziten Konstruktoren haben, fügt der Compiler sie ein, und da Event von java.lang.Object erbt, sieht die Laufzeitumgebung die Klassen so:

class Event {

Event() { }

}



class Nap extends Event {

Nap() { }

}

Deutschland sucht den super-Aufruf

Dass automatisch jeder Konstruktor einer Klasse den parameterlosen Konstruktor der Oberklasse aufruft, lässt sich auch explizit formulieren – das nötige Schlüsselwort ist super und formt den Aufruf super(); die Klammern erinnern an einen Methodenaufruf. Da der Compiler automatisch super() als erste Anweisung in den Konstruktor einfügt, müssen wir das nicht manuell hinschreiben und sollten es uns auch sparen – unsere Fingerkraft ist für andere Dinge wichtig! Ob wir also nun von Hand super(…) im Konstruktor platzieren oder es vom Compiler einsetzen lassen, für die Laufzeitumgebung sind die vorangehende Schreibweise und die folgende völlig gleich:

class Event extends Object {

Event() {

super(); // Ruft parameterlosen Konstruktor von Object auf

}

}



class Nap extends Event {

Nap() {

super(); // Ruft parameterlosen Konstruktor von Event auf

}

}
[»]  Hinweis

super(…) muss immer die erste Anweisung im Konstruktor sein. Beim Aufbau neuer Objekte läuft die Laufzeitumgebung im Konstruktor daher als Erstes die Hierarchie nach java.lang.Object ab und beginnt dort von oben nach unten mit der Initialisierung. Kommt die JVM nach der Initialisierung der Oberklasse durch den Aufruf von super() zurück zum eigenen Konstruktor, haben alle Konstruktoren der Oberklassen ihre Zustände schon initialisiert, und wir können später im eigenen Konstruktor von vollständig initialisierten Variablen aller Basistypen ausgehen.

super() auch bei parametrisierten Konstruktoren

Alle Konstruktoren (also die parameterlosen und parametrisierten) rufen mit super(…) standardmäßig den parameterlosen Konstruktor der Oberklasse auf. Nehmen wir eine Klasse fürs Musizieren, die im parametrisierten Konstruktor das Musikinstrument annimmt:

Listing 7.15     src/main/java/com/tutego/insel/game/c/vl/MusicMaking.java, MusicMaking

public class MusicMaking extends Event {

public final String instrument;

public MusicMaking( String instrument ) { this.instrument = instrument; }

}

Auch wenn es hier keinen parameterlosen Konstruktor gibt, sondern nur einen parametrisierten, ruft auch dieser automatisch den parameterlosen Konstruktor der Basisklasse Event auf. Explizit ausgeschrieben heißt das:

public MusicMaking( String instrument ) {

super(); // Ruft automatisch den parameterlosen Konstruktor von Event auf

this.instrument = instrument;

}

Natürlich muss super(…) wieder als Erstes stehen.

super(…) mit Argumenten füllen

Mitunter ist es nötig, aus der Unterklasse nicht nur den parameterlosen Konstruktor anzusteuern, sondern einen anderen (parametrisierten) Konstruktor der Oberklasse anzusprechen. Dazu gibt es das super(…) mit Argumenten.

Der Aufruf von super(…) kann parametrisiert erfolgen, sodass nicht der parameterlose Konstruktor, sondern ein parametrisierter Konstruktor aufgerufen wird. Gründe dafür könnten sein:

  • Ein parametrisierter Konstruktor der Unterklasse leitet die Argumente an die Oberklasse weiter; es soll nicht der parameterlose Konstruktor aufgerufen werden, da der Oberklassen-Konstruktor die Objektvariablen annehmen und verarbeiten soll.

  • Wenn wir keinen parameterlosen Konstruktor in der Oberklasse vorfinden, müssen wir in der Unterklasse mittels super(Argument) einen speziellen, parametrisierten Konstruktor aufrufen.

Gehen wir Schritt für Schritt eine Vererbungshierarchie durch, um zu verstehen, dass ein super(…) mit Parameter nötig ist.

Kommen wir noch einmal zurück auf die Klasse MusicMaking und ihren parametrisierten Konstruktor:

Listing 7.16     src/main/java/com/tutego/insel/game/c/vl/MusicMaking.java, MusicMaking

public class MusicMaking extends Event {

public final String instrument;

public MusicMaking( String instrument ) { this.instrument = instrument; }

}

Erweitert eine Klasse MusicMakingAndRecording für eine besondere Art von Musik-Jam die Klasse MusicMaking, kommt es zu einem Compilerfehler:

public class MusicMakingAndRecording extends MusicMaking {} // inline image Compilerfehler

Die Fehlermeldung des Compilers lautet: »There is no default constructor available in 'com.tutego.insel.game.vl.MusicMaking'«

Der Grund ist simpel: MusicMakingAndRecording enthält einen vom Compiler generierten Standard-Konstruktor, der mit super(…) nach einem parameterlosen Konstruktor in MusicMaking sucht – den gibt es aber nicht. Wir müssen daher entweder einen parameterlosen Konstruktor in der Oberklasse anlegen (was bei nicht modifizierbaren Klassen natürlich nicht geht) oder das super(…) in MusicMakingAndRecording so einsetzen, dass es mit einem Argument den parametrisierten Konstruktor der Oberklasse aufruft. Das kann so aussehen:

Listing 7.17     src/main/java/com/tutego/insel/game/c/vl/MusicMakingAndRecording.java, Ausschnitt

public class MusicMakingAndRecording extends MusicMaking {

public MusicMakingAndRecording() {

super( "Guitar" );

}

// ...

}

Es spielt dabei keine Rolle, ob MusicMakingAndRecording einen parameterlosen Konstruktor oder einen parametrisierten Konstruktor besitzt: In beiden Fällen müssen wir mit super(…) einen Wert an den Konstruktor der direkten Oberklasse übergeben. Oftmals leiten Unterklassen einfach nur das übergebene Konstruktorargument an den Konstruktor der Oberklasse weiter:

Listing 7.18     src/main/java/com/tutego/insel/game/c/vl/MusicMakingAndRecording.java, MusicMakingAndRecording

public class MusicMakingAndRecording extends MusicMaking {

public MusicMakingAndRecording() {

super( "Guitar" );

}



public MusicMakingAndRecording( String instrument ) {

super( instrument );

}

}

Der this(…)-und-super(…)-Konflikt *

this(…) und super(…) haben eine Gemeinsamkeit: Beide wollen die erste Anweisung eines Konstruktors sein. Es kommt vor, dass es mit super(…) einen parametrisierten Aufruf des Konstruktors der Basisklasse gibt, aber gleichzeitig ein this(…) mit Parametern, um in einem zentralen Konstruktor alle Initialisierungen vornehmen zu können. Beides geht aber leider nicht. Die Lösung besteht darin, auf das this(…) zu verzichten und den gemeinsamen Programmcode in eine private Methode zu setzen, die dann nach dem super-Aufruf aufgerufen wird.

Zusammenfassung: Konstruktoren und Methoden

Methoden und Konstruktoren haben einige Gemeinsamkeiten in der Signatur, weisen aber auch einige wichtige Unterschiede auf, wie den Rückgabewert oder den Gebrauch von this und super. Tabelle 7.1 fasst die Unterschiede und Gemeinsamkeiten zusammen:[ 162 ](Schon seltsam, dass synchronized nicht erlaubt ist, aber ein Konstruktor implizit synchronized ist. )

Benutzung

Konstruktoren

Methoden

Modifizierer

Sichtbarkeit public, protected, paketsichtbar und private. Können nicht abstract, final, native, static oder synchronized sein.

Sichtbarkeit public, protected, paketsichtbar und private. Können abstract, final, native, static oder synchronized sein.

Rückgabe

kein Rückgabetyp, auch nicht void

Rückgabetyp oder void

Bezeichnername

Gleicher Name wie die Klasse. Beginnt mit einem Großbuchstaben.

Beliebig. Beginnt mit einem Kleinbuchstaben.

this

this ist eine Referenz in Objektmethoden und Konstruktoren, die sich auf das aktuelle Exemplar bezieht.

this(…) bezieht sich auf einen anderen Konstruktor der gleichen Klasse. Wird this(…) benutzt, muss es in der ersten Zeile stehen.

super

super ist eine Referenz mit dem Namensraum der Oberklasse. Damit lassen sich überschriebene Objektmethoden aufrufen.

super(…) ruft einen Konstruktor der Oberklasse auf. Wird es benutzt, muss es die erste Anweisung sein.

Vererbung

Konstruktoren werden nicht vererbt.

Sichtbare Methoden werden vererbt.

Tabelle 7.1     Gegenüberstellung von Konstruktoren und Methoden

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Spring Boot 3 und Spring Framework 6

Spring Boot 3 und Spring Framework 6




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2024

Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.

Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern