Learning By Doing Klassenhierarchien, Vererbung • Objekte werden in der Regel in Klassenhierarchien klassifiziert Beispiel: Europäische Säugetiere Säugetier Insektenfresser Nagetier Oberklasse, Superklasse, Basisklasse Raubtier Igel Spitzmaus Maulwurf Hörnchen Biber Marder Bär Katze Unterklasse, abgeleitete Klasse Huftier Pferd Rind Schwein • Einfachvererbung: nur eine Superklasse s. Buch S. 153ff • is-a-Relation: Ein Objekt der Unterklasse ist auch ein Objekt der Superklasse • Grundidee: Erweiterung der Eigenschaften und des Verhaltens durch Vererbung "Alle guten und schlechten Eigenschaften werden vererbt" • Manchmal auch: Veränderung des Verhaltens in der abgeleiteten Klasse (Überschreiben) • Aber nie: Entfernen von Eigenschaften und Verhalten in der abgeleiteten Klasse Learning By Doing Vererbung durch extends Wir vererben alle Eigenschaften des GPanels einer Klasse MoireIs // MoireIs.java MoireIs ist-ein GPanel import ch.aplu.util.*; class MoireIs extends GPanel { MoireIs() Konstruktor Superklasse { super(0, 10, 0, 10); int i, k; for (i = 0; i <= 10; i++) for (k = 0; k <= 10; k++) line(i, 0, k, 10); for (i = 0; i <= 10; i++) for (k = 0; k <= 10; k++) line(0, i, 10, k); } line() ist Methode von MoireIs public static void main(String[] args) { new MoireIs(); } } s. Buch S. 157 Learning By Doing Komposition statt Vererbung Wir konstruieren die Klasse MoireHas unter Verwendung eines GPanels // MoireHas.java MoireHas hat-ein GPanel import ch.aplu.util.*; class MoireHas { GPanel panel = new GPanel(0, 10, 0, 10); MoireHas() { int i, k; for (i = 0; i <= 10; i++) for (k = 0; k <= 10; k++) panel.line(i, 0, k, 10); for (i = 0; i <= 10; i++) for (k = 0; k <= 10; k++) panel.line(0, i, 10, k); } MoireHas verwendet das GPanel public static void main(String[] args) { new MoireHas(); } } s. Buch S. 156 Learning By Doing Klassendiagramme (UML, unified modeling language) • zur Dokumentation • zur besseren Übersicht und zum besseren Verständnis • zur automatischen Codegeneration (Wunsch) Vererbung (is-a) Pfeil zur Superklasse Komposition (has-a) Tasteninstrum ent K l a v i e r h a s a T a s t e n T a s t e s p i e l e n ( ) is-a Raute zur umgebenden Klasse K lavier • Typischer Klassenentwurf (Polygone) Polygon Point2D.Double[] corners show() uses has-a is-a Parallelogramm is-a Rechteck is-a GPanel s. Buch S. 160ff has-a PolyEx2 GPanel panel int size main() uses Quadrat Point2D.Double double x double y Dreieck is-a Gleichseitiges Dreieck Learning By Doing Zugriffsbezeichner (Package-Konzept) Semantische Fehler (Fehler zur Laufzeit des Programms) sind oft auf die fehlerhafte Veränderung von Daten zurückzuführen. Man muss die Daten vor dem unerlaubten Zugriff schützen (Datenkapselung). Schutzmechanismen: • Verwendung von Konstanten (Schlüsselwort final) • Verzicht auf globale Variablen (gibt es in Java nicht) • Verwendung von lokalen Variablen statt Instanzvariablen • Zugriffseinschränkungen von Instanzvariablen und Methoden durch Verwendung von Zugriffsbezeichner (access-specifiers) und durch einen Programmierstil "so privat wie möglich" • Zusammenfassung in Klassenbibliotheken (packages) s. Buch S. 172ff Learning By Doing Zugriffsbezeichner für Klassen, Instanzvariablen und Methoden s. Buch S. 172 Zugriffsbezeichner Zugriff von Klassen im gleichen Package Zugriff von Klassen in anderen Packages Zugriff von Subklassen im gleichen Package Zugriff von Subklassen in anderen Packages public ja ja ja ja protected ja nein ja ja default ja nein ja nein private nein nein nein nein Learning By Doing Musterbeispiel: package homeland Turtle Turtle() Turtle(Turtle t) forward() ... is-a package homeland TurtleKid setHomeland() getHomeland() shape() Neue Methode shape() is-a TurtleBoy shape() shape() überschrieben s. Buch S. 173 TurtleGirl shape() shape() überschrieben Learning By Doing // TurtleKid.java // TurtleBoy.java package homeland; package homeland; import ch.aplu.turtle.*; public class TurtleBoy extends extends TurtleKid TurtleKid { public void shape() { label(getHomeland()); for (int i = 0; i < 3; i++) { forward(50); left(120); } } } extends Turtle Turtle public class TurtleKid extends { private String homeland = ""; // Mutator public void setHomeland(String h) { homeland = h; } // Accessor public String getHomeland() { return homeland; } public void shape() { label(homeland); for (int i = 0; i < 4; i++) { forward(50); left(90); } } } // TurtleGirl.java package homeland; public class TurtleGirl extends extends TurtleKid TurtleKid { public void shape() { label(getHomeland()); for (int i = 0; i < 18; i++) { forward(10); left(20); } } } Learning By Doing // WbzEx7.java import homeland.*; public class WbzEx7 { public WbzEx7() { TurtleKid alois = new TurtleKid(); alois.setHomeland("Emmenthal"); alois.back(50); alois.shape(); Alois, das TurtleKid Petra, das TurtleGirl TurtleGirl petra = new TurtleGirl(); petra.setHomeland("Zürich"); petra.forward(100); petra.shape(); TurtleBoy marcel = new TurtleBoy(); marcel.setHomeland("Basel"); marcel.left(90).forward(100); marcel.shape(); } public static void main(String[] args) { new WbzEx7(); } } Marcel, der TurtleBoy Learning By Doing Objektorientierte Programmiersprache • Kapselung (Klassenbildung) • Vererbung (is-a-Hierarchie) • Polymorphie (Laufzeitbindung) Polymorphie (Vielgestaltigkeit) • Klassisch (statische Bindung): bereits zur Compilationszeit ist eindeutig, welche Methode (Prozedur, Funktion, Subroutine) aufgerufen wird • OOP (dynamische Bindung, virtuelle Methoden): bei überschriebenen Methoden wird erst zur Laufzeit ermittelt, welche der Methoden aufgerufen wird (in Java immer, d.h. alle Methoden sind virtuell) TurtleKid kid; ... kid.shape(); s. Buch S. 181ff Je nachdem, was in diesem Teil des Programms abläuft, kann hier shape() von TurtleKid, TurtleBoy oder TurtleGirl aufgerufen werden. Learning By Doing // WbzEx8.java So ... import homeland.*; public class WbzEx8 { public WbzEx8() { TurtleKid kid; if (Math.random() < 0.45) { kid = new TurtleGirl(); kid.setHomeland("Zürcher girl"); } else { kid = new TurtleBoy(); kid.setHomeland("Basler boy"); } kid.shape(); } public static void main(String[] args) { new WbzEx8(); } } oder so ... Learning By Doing Musterbeispiel zur Polymorphie Bird whistle() is-a Amsel whistle() Drossel whistle() Fink whistle() Star whistle() Voliere Vector cage creates create() whistleAll() class Voliere { Vector cage =cage new =Vector(); Vector<Bird> new Vector<Bird>(); public void create() {...} void whistleAll() { for (int i = 0; i < cage.size(); i++) cage.elementAt(i).whistle(); ((Bird)cage.elementAt()).whistle() } } s. Buch S. 192 Generischer Datentyp Typvariable <Bird> J2SE V1.4: keine Typvariablen Es pfeift der richtige Vogel dafür (unschöner) Cast Learning By Doing // Bird.java Abstrakte Klasse • Keine Instanzen erlaubt • Garantieerklärung (Contract) für Unterklassen public class Bird { public void whistle() abstract public class Bird { { System.out.println( abstract public void whistle(); "Fehler: Vogelvorlage"); } } } // Amsel.java // Drossel.java public class Amsel extends Bird { public void whistle() { System.out.println( "Amsel pfeift: uiuiii..."); } } public class Drossel extends Bird { public void whistle() { System.out.println( "Drossel pfeift: zwawaaa..."); } } // Fink.java // Star.java public class Fink extends Bird { public void whistle() { System.out.println( "Fink pfeift: zrzrrr..."); } } public class Star extends Bird { public void whistle() { System.out.println( "Star pfeift: kiukuu..."); } } Learning By Doing Interfaces • Klassengerüste (kein Code) // BirdIf.java • Garantieerklärung (Contract) für implementierende Klassen public interface BirdIf { public void whistle(); } • Ersatz für Mehrfachvererbung // AmselImp.java // DrosselImp.java public class AmselImp implements BirdIf { public void whistle() { System.out.println( "Amsel pfeift: uiuiii..."); } } public class DrosselImp implements BirdIf { public void whistle() { System.out.println( "Drossel pfeift: zwawaaa..."); } } // FinkImp.java // StarImp.java public class FinkImp implements BirdIf { public void whistle() { System.out.println( "Fink pfeift: zrzrrr..."); } } public class StarImp implements BirdIf { public void whistle() { System.out.println( "Star pfeift: kiukuu..."); } }