Programmierkurs Java Abstrakte Klassen und Methoden & Interfaces Prof. Dr. Stefan Fischer Institut für Telematik, Universität zu Lübeck http://www.itm.uni-luebeck.de/people/fischer Vererbungshierarchie Obst double getPreisInEuro(); Apfel Birne Kiwi double getPreisInEuro(); double getPreisInEuro(); double getPreisInEuro(); #2 Problem dieser Lösung • Methode „double getPreisInEuro();“ – In den Klassen Apfel, Birne und Kiwi implementiert – Aber auch in der Klasse Obst • Welchen Sinn hat die Implementierung in Obst? #3 Oberklasse Obst: getPreisInEuro() • Bisherige Implementierung komplett sinnlos – Die Methode wird sowieso in den Unterklassen überschrieben – Macht sogar Probleme, wenn man Instanzen von Obst verwendet (Negativer Preis) • Eigentlich brauchen wir die Klasse nur, damit wir die Methode double getPreisInEuro() in Obst haben #4 Weiteres Problem dieser Lösung • Wer erzwingt eigentlich, dass man in Unterklassen die Methode getPreisInEuro() überschreibt? • Der Compiler tut es nicht (siehe Beispiel unten) – Erstellt man eine Instanz von Apfel, wird die Methode aus Obst aufgerufen – Die Methode wurde ja nicht überschrieben #5 Lösung: Abstrakte Klassen und Methoden • Man kann Klassen und Methoden als abstrakt kennzeichnen • Bedeutung: Von abstrakten Klassen können keine Instanzen erzeugt werden • Ist mindestens eine Methode einer Klasse abstrakt, so ist auch die Klasse abstrakt #6 Beispiel: Abstrakte Klasse „Obst“ • Abstrakte Klassen: Keyword abstract – Syntax: abstract class XXX {...} • Beispiel: #7 Beispiel: Abstrakte Klasse „Obst“ • Von abstrakten Klassen können keine Instanzen erzeugt werden • Löst das erste der beiden Probleme – Erzeugen von Instanzen wird vom Compiler verhindert #8 Erzwingen der Implementierung von Methoden • Wie kann man nun erzwingen, dass in Unterklassen bestimmte Methoden implementiert werden? • Lösung: durch abstrakte Methoden – public abstract double getPreisInEuro(); – Nur Signatur (wg. ; am Ende) aber keine Implementierung • Enthält eine Klasse mindestens eine abstrakte Methode, so muss die Klasse auch abstrakt sein – D.h. es muss abstract class Obst heißen – Existenz mindestens einer abstrakten Methode: es können von dieser Klasse auch keine Instanzen erzeugt werden #9 Beispiel: Abstrakte Methode in Obst • Obst enthält nun eine abstrakte Methode – Die Signatur der Methode ist für alle Unterklassen definiert • Signatur reicht aus, um Methode aufzurufen – Wie sie intern funktioniert, ist egal #10 Beispiel: Abstrakte Methode in Obst • Unterklassen erben die abstrakte Methode – Daher: Compilerfehler • Unterklasse soll nicht abstrakt sein: – Sie muss alle abstrakten Methoden implementieren #11 Abstract und Vererbung • Abstrakte Methoden werden vererbt • Damit eine Klasse instanziiert werden kann (also nicht abstrakt ist), müssen in der Vererbungshierarchie alle abstrakten Methoden mit Implementierungen überschrieben werden • Wo dies geschieht ist dabei egal #12 Abstract und die Früchte • Klassen Apfel, Birne und Kiwi sind nicht abstrakt – Können dies nur sein, weil sie die abstrakte Methode aus Obst implementieren • Darüber kann man erzwingen, dass Programmierer bestimmte Methoden implementieren – Damit realisiert man eine Schnittstelle – Auch API (Application Programming Interface) genannt #13 Abstract und nicht-abstract mischen • Nicht abstrakte Methoden können abstrakte Methoden verwenden – Möglich, da bei nicht-abstrakten Instanzen von Unterklassen die Methode ja implementiert sein muss – Damit können bestimmte Elemente der Implementierung offen gelassen werden • Vorteil: Verhalten, das bei allen Unterklassen sehr ähnlich ist, kann in die Oberklasse verschoben werden #14 Beispiel • Beide Klassen implementieren die Methode getName unterschiedlich • Methode tueWasMit(GutenTag g) in der Klassen Main kennt nur das Interface von „GutenTag“ • Kann damit getName() oder stellDichVor() aufrufen – stellDichVor() ruft getName der jeweiligen Instanz auf #15 Interfaces Interfaces • Können Klassen auch von mehreren Oberklassen erben? – Sogenannte Mehrfachvererbung – Prinzipiell ja (z.B. in C++), in Java jedoch nicht – Es können Konflikte entstehen, deren Auflösung kompliziert sein kann • Java bietet ähnliche Funktionalität über einen Trick – Neben „echten“ Oberklassen gibt es sog. Interfaces • Ein Interface enthält lediglich Methodensignaturen – D.h. keine Methodenimplementierung / kein Code – Vergleichbar mit Klassen, die nur abstrakte Methoden enthalten #17 Abstrakte Klasse vs. Interface • Abstrakte Klasse • abstract class Obst { public abstract double getPreisInEuro(); } • Interface • interface Obst { double getPreisInEuro(); } • Abstract wird implizit für Klasse und Methoden angenommen und muss daher nicht explizit auftauchen • Methoden eines Interfaces sind immer public #18 Abstrakte Klasse vs. Interface • Abstrakte Klassen können auch „normale“ Methoden enthalten (mit Implementierung) – abstract class Obst { public void gebeAus() { ... } OK public abstract double getPreisInEuro(); } • Bei Interfaces ist dies nicht erlaubt – interface Obst { void gebeAus() { ... } nicht möglich double getPreisInEuro(); } #19 Implementieren von Interfaces • Von einem Interface wird nicht geerbt, sondern es wird implementiert – Schlüsselwort: implements • Eine Klasse kann von max. einer Klasse erben – Aber sie kann beliebig viele Interfaces implementieren – Wenn mehrere Klassen ein Interface implementieren, besitzen sie Methoden mit identischen Signaturen • Beispiel: siehe nächste Folie #20 Interfaces: Beispiel • class PKW extends Fahrzeug implements Gebrauchsgegenstand, CoolesMaennerspielzeug { //alle Interface-Methoden müssen implementiert werden } • Ein PKW „ist-ein“ Fahrzeug, GebrauchsGegenstand und CoolesMaennerspielzeug Fahrzeug Gebrauchs Gegenstand CoolesMaenner spielzeug PKW #21 Interfaces: Obstbeispiel • Bei manchen Obstsorten ist Herkunftsland wichtig – Methode „String getHerkunftsland();“ – Soll (wenn bekannt) von Obstsorten implementiert werden • Beispiel Kiwi – Klasse Kiwi erbt schon von Obst – Kann daher keine weitere Klasse „extenden“ #22 Interfaces: Obstbeispiel • Daher: Neues Interface „Herkunftsland “ – public interface Herkunftsland { String getHerkunftsland(); } • Klasse Kiwi implementiert das Interface – class Kiwi extends Obst implements Herkunftsland { String getHerkunftsland() { return “Neuseeland“; } } #23 Vererbungshierarchie • Kiwi „ist-ein“ – Obst – Herkunftsland Obst • Instanzen vom Typ Kiwi können per Typecast auf Obst und Herkunftsland abgebildet werden • Beispiel Herkunftsland Kiwi – Obst obst = new Kiwi(); – Herkunftsland land = new Kiwi(); – Obst obst2 = (Obst) land; – Herkunftsland land2 = (Herkunftsland) obst; #24 Beispiel: instanceof • Obst o = new Obst(); – • a instanceof Obst a instanceof Apfel a instanceof Herkunftsland Obst k = new Kiwi(); – – – – • true Apfel a = new Apfel(); – – – • o instanceof Obst k k k k instanceof instanceof instanceof instanceof Obst Herkuntsland Kiwi Apfel true true false // ok, da: Kiwi ist ein Obst (upcast) true true true false Obstkorb korb = new Obstkorb(); – – korb instanceof Obst korb instanceof Obstkorb false true #25 Zusammenfassung • Attribut „abstract“ an Klassen verhindert deren Instanziierung • Abstrakte Methoden – Machen die gesamte Klasse abstrakt – Erzwingen, dass in Unterklassen diese Methode implementiert werden muss, damit diese nicht mehr abstrakt sein müssen – Resultat: Gemeinsame Schnittstelle bzw. Interface • Interfaces – Interfaces sind wie abstrakte Klassen mit ausschließlich abstrakten Methoden – In Java kann eine Klasse nur von einer Oberklasse erben aber von beliebig vielen Interfaces – Ein Interface implementiert man, von Oberklassen erbt man #26