Einführung in die objektorientierte Programmierung Teil 3 Vererbung Modul WI111: Objektorientierte Programmierung Fachrichtung Wirtschaftsinformatik Prof. Dr. Gert Faustmann Fachbereich Berufsakademie der FHW Berlin
Abgeleitete Klassen Durch Vererbung können aus bereits existierenden Klassen neue Klassen konstruiert werden. Die neue, abgeleitete Klasse erbt die Daten und Methoden der sog. Basisklasse. Sie kann um weitere Eigenschaften und Fähigkeiten erweitert werden. Kfz Eigenschaften und Methoden der Klasse KFZ PKW Eigenschaften und Methoden der Klasse Kfz Zusätzliche Eigenschaften und Methoden der Klasse PKW Eigenschaften und Methoden der Klasse Kfz LKW Zusätzliche Eigenschaften und Methoden der Klasse LKW
Umsetzung der Vererbung in va Definition einer abgeleiteten Klasse: class C extends B { // Deklaration der zusätzlichen privaten // Datenelemente und Methoden private... // Deklaration der zusätzlichen oeffentlichen // Datenelemente und Methoden public... Die Klasse C erbt alle Elemente der Basisklasse B. Auf die privaten Elemente einer Basisklasse kann aber auch eine abgeleitete Klasse nicht zugreifen.
Vorteile der Vererbung Datenabstraktion Allgemeine Eigenschaften und Vorgänge können mit Oberbegriffen versehen werden (Basisklassen) und durch Spezialisierungen (abgeleitete Klassen) in hierarchischen Beziehungen geordnet werden. Wiederverwendbarkeit Bereits definierte und getestete Klassen können weiterhin verwendet und an neue Anforderungen angepasst werden. Dazu braucht nicht die Implementierung der Basisklasse, sondern nur ihre öffentliche Schnittstelle bekannt sein.
Vererbung von Konstruktoren Wird ein Objekt einer abgeleiteten Klasse mit new erzeugt, so wird auch ein Konstruktor der Basisklasse aufgerufen. Dafür gibt es zwei Möglichkeiten: Expliziter Aufruf Wird im Konstruktor der abgeleiteten Klasse als erstes die Anweisung super() aufgerufen, so wird ein entsprechender Konstruktor der Basisklasse aufgerufen. Impliziter Aufruf Im anderen Fall wird automatisch als erstes der Default-Konstruktor der Basisklasse aufgerufen. Der Default-Konstruktor ist parameterlos. Achtung: Wurden eigene Konstruktoren definiert, so existiert der Default-Konstruktor nicht mehr und muss auch selbst definiert werden! Bsp: super(nr, hersteller) ruft den Basisklassen-Konstruktor Kfz(nr, hersteller) auf.
Beispiel: Kfz class Kfz{ private long nr; private String hersteller; // Konstruktor public Kfz(long nr, String hersteller){ this.nr = nr; this.hersteller = hersteller; // Zugriffsmethoden long getnr(void) { return nr; void setnr(long nr) { this.nr = nr; String getherst() { return hersteller; void setherst(string hersteller) { this.hersteller = hersteller; class Pkw extends Kfz{ private string pkwtyp; private boolean automatik; // Konstruktor Pkw(String pkwtyp, boolean automatik, int nr, String hersteller){ super(nr, hersteller); this.pkwtyp = pkwtyp; this.automatik = automatik; // Zugriffsmethoden String gettyp(){ return pkwtyp; void settyp( String pkwtyp) { this.pkwtyp = pkwtyp; boolean getautomatik(){ return automatik; void setautomatik( boolean automatik){ this.automatik = automatik;
Überlagerung Wird ein Element der Basisklasse in der abgeleiteten Klasse neu definiert, so kann durch diese Überlagerung die Funktionalität spezialisiert werden. Normalerweise werden Methoden überlagert. Die Signatur muss dabei nicht mit der Methode der Basisklasse übereinstimmen. Entdeckt der Compiler einen klassenbezogenen Methodenaufruf, sucht er diese Methode zunächst in der Klasse selbst. Kann er die Methode nicht finden, so wechselt er zu der Basisklasse auf der darüberliegenden Vererbungsstufe. Auf die Methode der Basisklasse kann auch direkt mit dem Ausdruck super. zugegriffen werden: public display(void) { super.display(); // display von Pkw // display von Kfz... // alle Pkw-spezifischen Ausgaben
Elementzugriffe Methoden abgeleiteter Klassen können auf alle Elemente zugreifen, die in der abgeleiteten Klasse zusätzlich definiert sind. Bsp.: String gettyp() greift auf einen privaten Wert der Klasse PKW zu Ein Zugriff auf private Elemente der Basisklasse kann nur über öffentliche Zugriffsmethoden der Basisklasse erfolgen: public display(){ // in abgeleiteter Klasse PkW System.out.println( Hersteller: +hersteller ); // Fehler! public display(){ // in abgeleiteter Klasse Pkw System.out.println( Hersteller: +getherst() ); // Ok Privates Datum der Basisklasse Öffentliche Methode der Basisklasse
Zugriff auf geschützte Elemente (protected) Der Zugriff auf private Elemente einer Basisklasse ist auch für Methoden einer abgeleiteten Klasse nicht zulässig. In manchen Fällen sollen aber abgeleitete Klassen Zugriff auf diese Elemente haben (z.b. abgeleitete Fensterklassen auf die Fenstergröße einer allgemeinen Klasse). In diesem Fall wird die Zugriffskontrolle um eine Stufe zwischen private und public erweitert: protected-elemente sind vor dem Zugriff von außen 1 geschützt, können aber von Methoden abgeleiteter Klassen aufgerufen werden. 1 außerhalb des eigenen Pakets
Zugriff auf geschützte Elemente (protected): Beispiel public class GeoObj { private int groesse; protected int farbe; public void setgroesse(int n){ groesse = n; Kreis meinkreis = new Kreis(); meinkreis.groesse = 5; // FEHLER meinkreis.farbe = 10; // FEHLER meinkreis.setgroesse(5); // Ok meinkreis.faerben(10); // Ok class Kreis extends GeoObj { public faerben(int farbe){ this.farbe = farbe;
Exkurs: Pakete einsetzen Ein Paket ist eine Sammlung von Klassen, die zusammengefasst werden sollen. Jede Klasse in va ist Bestandteil genau eines Pakets. Der Name einer Methode oder einer Variablen besteht aus drei Elementen: Paketname Klassen-/Objektname java.lang.math.sqrt Damit eine Klasse verwendet werden kann, muss angegeben werden, in welchem Paket sie liegt. Hierzu gibt es zwei Möglichkeiten: Die Klasse wird über ihren vollen (qualifizierten) Namen angesprochen: java.util.date d = new java.util.date(); Am Anfang des Programms werden die gewünschten Klassen mit Hilfe einer import-anweisung eingebunden: import java.util.date;... Date d = new Date(); Methoden-/Variablenname
Exkurs: Eigene Pakete erstellen Der Paketname beschreibt die Verzeichnishierarchie der Klassen. Für eigene Pakete müssen dementsprechend geeignete Verzeichnisse angelegt werden. Das aktuelle Verzeichnis wird als Default-Package angesehen. In Eclipse kann dazu ein neues Package (Unterverzeichnis) bzw. weitere Folder (darunterliegende Packages) angelegt werden. Beispiel File->New->Package Paket demo anlegen File->New->Folder Paket demo auswählen Paket demo.tools anlegen Achtung: Soll eine Klasse eines fremden Pakets genutzt werden, so muss diese als public deklariert sein! In den neuen Paketen können dann wie gewohnt neue Klassen angelegt werden. Eclipse ergänzt in den Klassendefinitionen automatisch die Deklarationen package demo; bzw. package demo.tools;
Übersicht Klassenzugriffsbeschränkungen Sichtbar für: public Sichtbarkeit des Klassenelements protected standard private Eigene Klasse Klasse im selben Paket Nein Abgeleitete Klasse im fremden Paket Nein Nein Nichtabgeleitete Klasse im fremden Paket Nein Nein Nein
Übung Leiten Sie von der Klasse Konto zwei Klassen - GiroKonto und SparKonto - ab. GiroKonto erhält zusätzlich ein Überziehungslimit und einen Soll-Zinssatz. SparKonto erhält nur einen Haben-Zinssatz zusätzlich. Legen Sie die Konto-Klasse in das Paket de.baberlin.konto und die anderen Klassen in das Paket de.baberlin.konto.spezial. Definieren Sie beide Klassen mit Konstruktoren, mit Zugriffsmethoden zur Änderung aller Werte und mit je einer display-methode. Testen Sie die neuen Klassen mit einer Klasse KontoTest, die sie im Default-Paket anlegen. Ablauf des Tests: Definition und gleichzeitige Initialisierung eines Kontos vom jeweiligen Typ mit anschliessender Ausgabe der Kontodaten. Darauf Änderung beider Konten mit erneuter Ausgabe der Kontodaten.
Modifier für Klassen und Klassenelemente public private protected standard static final transient volatile Membervariablen und Methoden sind überall sichtbar. Klassen sind auch außerhalb des Pakets sichtbar. Nur eine public-klasse pro Datei! Methoden oder Variablen sind nur in der Klasse sichtbar. Elemente dürfen auf andere Instanzen derselben Klasse zugreifen! Elemente sind in der Klasse, in abgeleiteten Klassen und in Klassen des eigenen Pakets sichtbar. Sie sind jedoch nicht für Aufrufer aus Klassen anderer Pakete sichtbar. Klassen, Methoden und Variablen sind nur innerhalb des Pakets sichtbar, in dem sie definiert wurden. Keine Bindung an die Existenz eines Objekts. Variablen dürfen nicht verändert werden. Keine dynamische Bindung bei Methoden oder Klassen. Parameter können nicht mehr verändert werden. Variablen werden beim Serialisieren nicht berücksichtigt. Membervariablen können asynchron modifiziert werden.
Die Klasse Object Enthält eine Klasse keine extends-klausel, so besitzt sie die implizite Vaterklasse Object. Jede Klasse, die keine extends-klausel besitzt, wird direkt aus Object abgeleitet. Jede explizit abgeleitete Klasse stammt am oberen Ende ihrer Vererbungslinie von einer Klasse ohne explizite Vaterklasse ab und ist damit ebenfalls aus Object abgeleitet. Object ist Basisklasse aller anderen Klassen. Die Klasse Object definiert einige elementare Methoden, die für alle Arten von Objekten nützlich sind: boolean equals(object obj) testet auf inhaltliche Gleichheit protected Object clone() String tostring() int hashcode() kopiert ein Objekt erzeugt String-Repräsentation eines Objekts berechnet numerischen Wert
Übung Verändern Sie Ihre Kontoklassen folgendermaßen: Überlagern Sie die Methode equals, so dass sie für verschiedene Kontoobjekte, die gleiche Inhalte haben, korrekt arbeitet. Führen Sie die bisherige display-methode in die tostring- Methode über und testen Sie das Verhalten, in dem Sie Kontoobjekte mit System.out.println ausgeben.