Einführung in die Objektorientierung Teil 4 Interfaces, Polymorphie und innere Klassen
2 Vererbung im Klassendiagramm (Wiederholung) Vererbung repräsentiert eine ist ein Beziehung zwischen Klassen Object Ware farbe: String marke: String neupreis: float warennummer: int zustand: Zustand Vererbung Handtasche breite: float hoehe: float Jacke groesse: Groesse Schuhpaar groesse: int Eine Handtasche ist eine Ware Eine Jacke ist eine Ware Ein Schuhpaar ist eine Ware
3 Vererbung in Java I (Wiederholung) Das Schlüsselwort zu Deklaration von Vererbung ist extends public class BEZEICHNER extends KLASSEN-BEZEICHNER { public class Ware { private float neupreis; public class Handtasche extends Ware { private float breite; private float hoehe; public class Schuhpaar extends Ware { Java kennt nur einfache Vererbung, d.h. eine Klasse kann maximal von einer anderen Klasse erben Die Hierarchietiefe ist allerdings beliebig, d.h. die Elternklasse (oben Ware) kann wieder von einer anderen Klasse erben
4 Vererbung in Java II (Wiederholung) Sprachgebrauch: Elternklasse: Klasse von der geerbt wird Kindklasse: Alle von einer Elternklasse erbenden Klassen Eine Kindklasse erbt: Alle Attribute der Elternklasse Alle Methoden der Elternklasse Alle Konstruktoren der Elternklasse Zugriff auf Elemente (Attribut, Methode, Konstruktor) zur Laufzeit: Ist das Element in der Klasse der aktuellen Instanz definiert? Falls nein: Ist das Element ein der Elternklasse definiert? Falls nein: Hat die Elternklasse eine Elternklasse? Falls ja: Die Hierarchie durchlaufen, bis das Element gefunden wurde Ansonsten: Compiler-Fehler
5 Sichtbarkeit (Wiederholung) Es gibt vier Sichtbarkeitsmodifiktoren für Attribute und Methoden public: Zugriff von überall protected: Zugriff innerhalb des Packages und bei Vererbung [keine Angabe]: Zugriff innerhalb des Packages ( package private ) private: Zugriff nur innerhalb der eigenen Klasse/Instanz public class Ware { private float neupreis; Das Attribut neupreis ist nur innerhalb von Ware verwendbar Es gibt zwei Sichtbarkeitsmodifikatoren für Klassen: public: Zugriff von überall [keine Angabe]: Zugriff innerhalb des Packages ( package private ) Insbesondere: Nur die mit dem Dateinamen übereinstimmende Klasse kann public sein
6 Abstrakte Klassen/Methoden (Wiederholung) Klassen können mit abstract als abstrakt definiert werden Ist eine Klasse abstrakt, so kann keine Instanz der Klasse erzeugt werden SICHTBARKEIT abstract class KLASSEN-BEZEICHNER { public abstract class Ware { Ebenso können Methoden als abstract definiert werden SICHTBARKEIT abstract RÜCKGABETYP BEZEICHNER ( DATENTYP PARAM- BEZEICHNER, optional ); public abstract float getwarenwert(); Eine abstrakte Methode hat keinen Methodenrumpf (Implementierung) Lediglich die Signatur wird angegeben Existiert innerhalb einer Klasse mindestens eine abstrakte Methode, so muss auch die Klasse abstract sein Alle erbenden Klassen müssen entweder die Methode implementieren oder sind selbst wieder abstract
7 Interfaces Ein Interface (Schnittstelle) ist eine abstrakte Klasse, in der alle Methoden public sind (per default, eine Sichtbarkeit muss nicht angegeben werden) abstrakt sind (per default, abstract muss nicht angegeben werden) SICHTBARKEIT interface BEZEICHNER { RÜCKGABETYP BEZEICHNER ( DATENTYP PARAM-, ); BEZEICHNER public interface IForm { public double getflaeche(); public double getumfang(); Eine Klasse implementiert ein Interface Die Beziehung wird nicht per extends sondern mit implements angegeben public class BEZEICHNER implements INTERFACE-BEZEICHNER {
8 Interfaces (II) Innerhalb eines Interfaces können keine Instanz-Attribute definiert werden Klassenattribute sind möglich Eine implementierende Klasse muss entweder alle im Interface angegebenen Methoden definieren oder als abstract deklariert werden public abstract class Form implements IForm { public class Kreis extends Form { private double radius public Kreis(double radius){ this.radius = radius; Eine Klasse kann beliebig viele Interfaces implementieren (Komma als Trennzeichen) Dadurch gewinnt man eine Art Pseudo-Mehrfachvererbung Es können Variablen vom Typ eines Interfaces definiert werden: IForm form = new Kreis(5); System.out.print(form);
Objektorientierte Programmierung 9 Trennung von Schnittstelle und Implementierung Allgemeines Design-Prinzip: Programmiere gegen Schnittstellen, nicht gegen Implementierungen. (Quelle: http://openbook.galileocomputing.de/oop/oop_kapitel_03_005.htm) Trennung ermöglicht ein einfacheres Austauschen der Implementierungen Ermöglicht ein Aufteilen in mehrere Arbeitspakete, die von verschiedenen Personen parallel bearbeitet werden können. Hierfür werden im Vorfeld die Schnittstellen definiert
10 Klassendiagram mit Interface Interface IForm stellt der Verbindungsstück zwischen der Kiste und den Formen dar <<interface>> IForm getflaeche(): double getumfang(): double Form PI: double gerundet(): double tostring(): String Vererbung Kiste formen: IForm index: int Kiste(anzahl: int) formenauflisten(): String hinzufuegen(form IForm) getgroessteflaeche(): IForm getkleinsteflaeche(): IForm tostring(): String Aggregation Kreis radius: double Kreis(radius: double) getflaeche(): double getumfang(): double tostring(): String Quadrat laenge: double Quadrat(laenge: double) getflaeche(): double getumfang(): double tostring(): String Klasse Kiste kennt nur das Interface IForm Ein Arbeitspaket könnte die Implementierung der Kiste sein und pro geometrischer Figur ein weiteres Arbeitspaket
Objektorientierte Programmierung 11 Schnittstellen und abstrakte Klassen Gegenüberstellung von Unterschieden bei Interfaces und abstrakten Klassen: mögliche Elemente Regeln für Klassen Schnittstelle Konstanten Methodensignaturen ohne Rumpf Kann mehrere Schnittstellen implementieren Abstrakte Klasse Konstanten Variablen Methodensignaturen (mit oder ohne Rumpf) Kann maximal eine Elternklasse haben
Objektorientierte Programmierung 12 Polymorphie Polymorphie (Vielgestaltigkeit) ist eine wichtige Eigenschaft der OOP Polymorphie von Objekten gibt es nur bei Vererbungshierarchien Objekttyp einer Subklasse kann mit Objekttyp einer Basisklasse ausgetauscht werden, wenn die Basisklasse nur erweitert wird und nur der Basisklasse bekannte Elemente verwendet werden Überschriebene Methoden in der Subklasse müssen identisch zur ihrer Basisklassenmethode aufrufbar sein Einsatz von Polymorphie für flexiblere Programme public static void main(string[] args) { Ware ware; ware = new Handtasche(); System.out.println(ware); ware = new Schuhpaar(); System.out.println(ware); // Handtasche: // Schuhpaar:
13 Polymorphie Die getflaeche()-methode ist den Zugriffsrechten entsprechend aufrufbar Demnach auch von der definierenden Klasse selbst public abstract class Form { public abstract double getflaeche(); @Override public String tostring() { return + "-> Fläche: " + this.getflaeche() + ; Warum compiliert dies? Da Form abstract ist kann es keine Instanz der Klasse Form geben tostring kann nur von Instanzen aufgerufen werden D.h. es existiert eine Klasse in der Hierarchie des aufrufenden Objektes, die getflaeche implementiert Welche Klasse dies ist, steht erst zur Laufzeit fest Dieses Verhalten nennt sich spätes Binden (auch: dynamisches Binden ) Abstrakte Methoden werden daher als polymorph bezeichnet
14 Geschachtelte Klassen Jackengröße über eine Enum-Klasse abgebildet Enum-Klassen können in einer eigenen Java-Datei abgelegt werden Groesse-Enum existiert nur im direkten Zusammenhang mit der Klasse Jacke Um eine solche Abhängigkeit abzubilden bietet Java die Möglichkeit Klassen/Interfaces innerhalb von Klassen/Interfaces zu definieren MODIFIKATOREN KLASSEN-BEZEICHNER { class enum MODIFIKATOREN class enum KLASSEN-BEZEICHNER { public class Jacke extends Ware { public enum Groesse { S, M, L, XL, XXL, ;
15 Innere Klassen Innere Klasse wird in einer anderen Klasse definiert Beispiel: public class Schuhpaar { public class Schuh { private String farbe; private int groesse; Schuhpaar ist die äußere Klasse und Schuh als innere Klasse darin geschachtelt Schuh wird nur im Schuhpaar verwendet und kann darin gekapselt werden und ist nach außen nicht mehr sichtbar
16 Innere Klassen Der Zugriff auf innere Klassen erfolgt analog zu Klassenattributen über den umschließenden Klassennamen Jacke.Groesse groesse = Jacke.Groesse.XL; Nur bei inneren Klassen kann der Modifikator static genutzt werden: public class Schuhpaar { public static class Schuh { private String farbe; private int groesse; public class Schuhpaar { public class Schuh { private String farbe; private int groesse; Innerhalb eines Interfaces sind alle inneren Klassen automatisch static Geeignete Sichtbarkeit vorausgesetzt können von außen nur Instanzen von statischen inneren Klassen erzeugt werden: Schuhpaar.Schuh schuh = new Schuhpaar.Schuh(); Schuhpaar.Schuh schuh = new Schuhpaar.Schuh(); // Schuh statisch // Schuh nicht statisch
17 Anonyme innere Klassen Java bietet die Möglichkeit anonyme Klassen zu definieren D.h. Klassen, für die kein Name vergeben wird Da diese Klassen allerdings keinen Namen haben, kann man sie nicht wie gewohnt über class definieren Definition findet quasi ad hoc mit der Initialisierung einer Instanz statt Erweiterung einer bestehenden Klasse oder die Implementierung eines Interfaces IForm form = new Kreis(5) { @Override public String tostring() { return "[" + super.tostring() + "]" ; System.out.print(form); Anonyme Klassen sind nicht statische innere Klassen Zugriff innerhalb der Implementierung auf alle Attribute der umschließenden Klasse Können innerhalb einer Methode definiert werden: Insbesondere können so Parameter an die Klasse übergeben werden Allerdings müssen die Parameter dafür als final deklariert werden
18 Zusammenfassung Wozu dienen Interfaces? Was unterscheidet ein Interface von einer abstrakten Klasse? Was versteht man unter Polymorphie in der OOP bei Objekten? Was versteht man unter spätes Binden bzw. dynamisches Binden?
19 Aufgabe Aufgabe 1a: Kopieren Sie das Netbeans-Projekt zur 9. Vorlesung mit dem Paketnamen de.wwu.ziv.vorlesungen.java.vorlesung9.aufgabe und der Klasse Main an unter dem Projektnamen z. B. vl9_loesung. Erstellen Sie die Klasse Kreisring, die im Unterpaket formen liegt von der Klasse Form ableitet und das Interface IForm wie folgt ausimplementiert: Die Klasse enthält die Attribute radius_a und radius_i vom Typ double. Der Konstruktor Kreisring(double radius_a, double radius_i)setzt die Attribute radius_a und radius_i. Implementieren Sie die Methode getflaeche mit A = Pi * ((radius_a)² - (radius_i)²) und getumfang mit U = 2 * Pi * (radius_a + radius_i). Überschreiben Sie die tostring-methode, sodass die Attribute der Klasse Kreisring ausgegeben werden, wobei die tostring-methode der Oberklasse wiederverwendet werden soll.
20 Aufgabe Aufgabe 2: Erweitern Sie die Klasse Kiste um die Methoden getkleinstenumfang und getgroesstenumfang. Erweitern Sie die Klasse Main analog zu den Ausgaben zu der größten und kleinsten Fläche, sodass nun auch der kleinste und größte Umfang der Formen ermittelt wird. Instanziieren Sie in der Main-Klasse neben den Objekten aus der Vorlesung 9 zwei Kreisringe, sodass diese mit der folgenden Konsolenausgabe übereinstimmt.
21 Anhang: ZIVinteraktiv-Abstimmung QR-Code zur anonymen Abstimmung: https://www.uni-muenster.de/ziv/anw/zivinteraktiv/abstimmung.php?code=571dedcd