Algorithmen und Datenstrukturen II Alexander Goesmann Bioinformatics Resource Facility Center for Biotechnology Universität Bielefeld Vorlesung Sommer 2010 Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Teil I Objektorientierte Programmierung in Java Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Traditionelle Konzepte der Softwaretechnik Folgende traditionelle Konzepte des Software-Engineering werden u.a. im objektorientierten Ansatz verwendet: Datenabstraktion (bzw. Datenkapselung) und Information Hiding Die zentrale Idee der Datenkapselung ist, dass auf eine Datenstruktur nicht direkt zugegriffen wird, indem etwa einzelne Komponenten gelesen oder geändert werden, sondern, dass dieser Zugriff ausschließlich über Zugriffsoperatoren erfolgt. Es werden also die Implementierungen der Operationen und die Datenstrukturen selbst versteckt. Vorteil: Implementierungdetails können beliebig geändert werden, ohne Auswirkung auf den Rest des Programmes zu haben. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Traditionelle Konzepte der Softwaretechnik (II) abstrakte Datentypen (ADT) Realisiert wird die Datenabstraktion duch den Einsatz abstrakter Datentypen, die Liskov & Zilles (1974) folgendermaßen definierten: “An abstract data type defines a class of abstract objects which is completely characterized by the operations available on those objects. This means that an abstract data type can be defined by defining the characterizing operations for that type.” Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Oder etwas prägnanter: Datentyp Menge(n) von Werten + Operationen darauf abstrakter Datentyp Operationen auf Werten, deren Repräsentation nicht bekannt ist. Der Zugriff erfolgt ausschließlich über Operatoren. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Oder etwas prägnanter: Datentyp Menge(n) von Werten + Operationen darauf abstrakter Datentyp Operationen auf Werten, deren Repräsentation nicht bekannt ist. Der Zugriff erfolgt ausschließlich über Operatoren. Datenabstraktion fördert die Wiederverwendbarkeit von Programmteilen und die Wartbarkeit großer Programme. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel: Der ADT Stack Stack Eine Datenstruktur über einem Datentyp T bezeichnet man als Stack1 , wenn die Einträge der Datenstruktur als Folge organisiert sind und es die Operationen push, pop und peek gibt: 1 bedeutet soviel wie Keller oder Stapel Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel: Der ADT Stack Stack Eine Datenstruktur über einem Datentyp T bezeichnet man als Stack1 , wenn die Einträge der Datenstruktur als Folge organisiert sind und es die Operationen push, pop und peek gibt: push fügt ein Element von T stets an das Ende der Folge. pop entfernt stets das letzte Element der Folge. peek liefert das letzte Element der Folge, ohne sie zu verändern. 1 bedeutet soviel wie Keller oder Stapel Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel: Der ADT Stack Stack Eine Datenstruktur über einem Datentyp T bezeichnet man als Stack1 , wenn die Einträge der Datenstruktur als Folge organisiert sind und es die Operationen push, pop und peek gibt: push fügt ein Element von T stets an das Ende der Folge. pop entfernt stets das letzte Element der Folge. peek liefert das letzte Element der Folge, ohne sie zu verändern. Prinzip: last in first out (LIFO) 1 bedeutet soviel wie Keller oder Stapel Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Operatoren Typen der Operationen initStack: push: T × Stack pop: Stack peek: Stack empty: Stack Alexander Goesmann A&D II, Vorlesung 2010 −→ −→ −→ −→ −→ Stack Stack Stack T boolean Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Spezifikation Spezifikation der Operationen durch Gleichungen. Sei x eine Variable vom Typ T, stack eine Variable vom Typ Stack: Spezifikation Stackoperationen empty (initStack) empty (push (x, stack)) peek (push (x, stack)) pop (push (x, stack)) Alexander Goesmann A&D II, Vorlesung 2010 = = = = true false x stack Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Spezifikation Spezifikation der Operationen durch Gleichungen. Sei x eine Variable vom Typ T, stack eine Variable vom Typ Stack: Spezifikation Stackoperationen empty (initStack) empty (push (x, stack)) peek (push (x, stack)) pop (push (x, stack)) = = = = true false x stack initStack und push sind Konstruktoren (sie konstruieren Terme), daher gibt es keine Gleichungen für sie. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Objektorientierung Der Kerngedanke des objektorientierten Ansatzes besteht darin, Daten und Funktionen zu verschmelzen. Im ersten Schritt werden die Daten abgeleitet, im zweiten Schritt werden den Daten die Funktionen zugeordnet, die sie manipulieren. Die entstehenden Einheiten aus Daten und Funktionen werden Objekte genannt. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Objektorientierung Der Kerngedanke des objektorientierten Ansatzes besteht darin, Daten und Funktionen zu verschmelzen. Im ersten Schritt werden die Daten abgeleitet, im zweiten Schritt werden den Daten die Funktionen zugeordnet, die sie manipulieren. Die entstehenden Einheiten aus Daten und Funktionen werden Objekte genannt. Wir schränken den Begriff Objektorientierung gemäß folgender Gleichung von Coad & Yourdon weiter ein: Objektorientierung Objektorientierung = Alexander Goesmann A&D II, Vorlesung 2010 Klassen und Objekte + Kommunikation mit Nachrichten + Vererbung Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Klassen und Objekte Eine Klasse besteht aus einer Schnittstelle und einem Rumpf In der Schnittstelle sind die nach außen zur Verfügung gestellten Methoden und Daten aufgelistet Der Klassenrumpf enthält alle von außen unsichtbaren Implementierungsdetails Aus einer Klasse lassen sich beliebig viele Objekte erzeugen Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Kommunikation mit Nachrichten Objekte besitzen die Möglichkeit, mit Hilfe ihrer Methoden Aktionen auszuführen. Das Senden einer Nachricht stößt die Ausführung einer Methode an. Eine Nachricht besteht aus: einem Empfänger: das Objekt, das die Aktion ausführen soll einem Selektor: die Methode, deren Aktionen auszuführen sind ggf. aus Argumenten: Werte, auf die während der Ausführung der Aktion zugegriffen wird. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Vererbung Gleichartige Objekte werden zu Klassen zusammengefasst Häufig besitzen Objekte zwar bestimmte Gemeinsamkeiten, sind aber nicht völlig gleichartig Um solche Ähnlichkeiten auszudrücken, ist es möglich, zwischen Klassen Vererbungsbeziehungen festzulegen Dadurch wird das Verhalten einer existierenden Klasse erweitert Die Erweiterung erzeugt eine von ihr alle Attribute und Methoden erbende neue Klasse, die um weitere Attribute und Methoden ergänzt wird Die neue Klasse wird Unterklasse, die ursprüngliche Klasse Oberklasse genannt Gemeinsamkeiten: In der Oberklasse Unterschiede: In der Unterklasse Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Einfachvererbung Object @ System ? Math @ R @ Point @ @ R @ ... Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Mehrfachvererbung ... @ @ R @ Tiere @ @ R @ Pflanzen Fleischfresser @ @ R @ ... Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Klasse Object Die einzige Klasse in Java, die keine Oberklasse erweitert, ist die vordefinierte Klasse Object Klassen, die nicht explizit andere Klassen erweitern, erweitern implizit die Klasse Object Alle Objektreferenzen sind in polymorpher Weise von der Klasse Object, so dass Object die generische Klasse für Referenzen ist, die sich auf Objekte jeder beliebigen Klasse beziehen können Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Konstruktoren (I) neu erzeugten Objekten wird ein Anfangszustand zugewiesen Datenfelder können bei Deklaration initialisiert werden oft ist aber mehr als nur einfache Dateninitialisierung nötig Konstruktoren bewerkstelligen mehr als einfache Initialisierungen Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Konstruktoren (II) Konstruktoren methodenähnlich haben denselben Namen wie die von ihnen initialisierte Klasse keine oder mehrere Parameter keinen Rückgabetyp Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Konstruktoren (II) Konstruktoren methodenähnlich haben denselben Namen wie die von ihnen initialisierte Klasse keine oder mehrere Parameter keinen Rückgabetyp Bei der Objekterzeugung werden 1 den Instanzvariablen ihre voreingestellten Anfangswerte zugewiesen 2 Initialisierungsausdrücke der Instanzvariablen berechnet und zugewiesen 3 der Konstruktor aufgerufen Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Konstruktoren und Initialisierungsblöcke) public class Circle { int x=0, y=0, r=1; static int numCircles=0; public Circle() { numCircles++; } public double circumference() { return 2*Math.PI*r; } public double area() { return Math.PI*r*r; } public static void main(String[] args) { Circle c = new Circle(); System.out.println(c.r); System.out.println(c.circumference()); System.out.println(c.area()); System.out.println(numCircles); } Alexander Goesmann } A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Konstruktor mit Parametern Beispiel (Konstruktor mit drei Parametern) public Circle(int xCoord, int yCoord, int radius) { numCircles++; x = xCoord; y = yCoord; r = radius; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung mit this-Referenz Beispiel public Circle(int x, int y, int r) { numCircles++; this.x = x; this.y = y; this.r = r; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Überladen von Konstruktoren) public class Circle { int x = 0, y = 0, r = 1; static int numCircles; public Circle() { numCircles++; } public Circle(int x, int y, int r) { this(); this.x = x; this.y = y; this.r = r; } public Circle(int r) { this(0,0,r); } public static void main(String[] args) { Circle c1 = new Circle(); Circle c2 = new Circle(1,1,2); Circle c3 = new Circle(3); System.out.println(numCircles); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Komplexe Initialisierung von Klassenvariablen Klassenvariablen werden initialisiert, wenn die Klasse das erste Mal geladen wird. Das Analogon zu Konstruktoren, um komplexe Initialisierungen von Klassenvariablen durchzuführen, sind die sogenannten Initialisierungsblöcke. Diese Blöcke werden mit static{...} umschlossen. Beispiel public class Circle { public static double[] sines = new double[1000]; public static double[] cosines = new double[1000]; static { for(int i=0; i<1000; i++) { sines[i] = Math.sin(i); cosines[i] = Math.cos(i); } } Alexander } Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Java-Klassen als Realisierung und Implementierung von abstrakten Datentypen Durch den Modifizierer private können wir Implementierungsdetails verstecken, denn als private deklarierte Attribute und Methoden sind nur in der Klasse selbst zugreifbar2 . Folgende Klasse implementiert einen ADT Stack mittels eines Feldes: 2 Synonyme für Zugreifbarkeit sind: Gültigkeit bzw. Sichtbarkeit. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Stack) public class Stack { private Object[] stack; private int top = -1; private static final int CAPACITY = 10000; /** liefert einen leeren Keller. */ public Stack() { stack = new Object[CAPACITY]; } /** legt ein Objekt im Keller ab und liefert dieses Objekt zusaetzlich zurueck. */ public Object push(Object item) { stack[++top] = item; return item; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Stack) /** entfernt das oberste Objekt vom Keller und liefert es zurueck. Bei leerem Keller wird eine Fehlermeldung ausgegeben und null zurueckgeliefert. */ public Object pop() { if (empty()) { System.out.println("Method pop: empty stack"); return null; } else return stack[top--]; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Stack) /** liefert das oberste Objekt des Kellers, ohne ihn zu veraendern. Bei leerem Keller wird eine Fehlermeldung ausgegeben und null zurueckgeliefert. */ public Object peek() { if (empty()) { System.out.println("Method peek: empty stack"); return null; } else return stack[top]; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Stack) /** liefert true genau dann, wenn der Keller leer ist. */ public boolean empty() { return (top == -1); } /** liefert die Anzahl der Elemente des Kellers. */ public int size() { return top+1; } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Der Dokumentationskommentar /** ... */ wird zur automatischen Dokumentierung der Attribute und Methoden einer Klasse benutzt. Das Programm javadoc generiert ein HTML-File, in dem alle sichtbaren Attribute und Methoden mit deren Parameterlisten aufgezeigt und dokumentiert sind. > javadoc Stack.java Dieses HTML-File ist der Vertrag (die Schnittstelle) der Klasse und entspricht dem ADT Stack, wobei die Operationen bzw. Methoden allerdings nur natürlichsprachlich spezifiziert wurden. Die obige verbale Spezifikation entspricht weitgehend der der vordefinierten Java-Klasse Stack (genauer java.util.Stack). Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Methoden in Java 1 Methoden und Signaturen 2 Überladen von Methoden 3 Wertübergabe (call by value) Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Signaturen, Überladen von Methoden Methoden können wie Konstruktoren überladen werden jede Methode besitzt eine Signatur, die ihren Namen sowie die Anzahl und Typen der Parameter definiert Überladen von Methoden Zwei Methoden können denselben Namen haben, wenn ihre Signaturen unterschiedliche Anzahlen oder Typen von Parametern aufweisen. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung call by value Die Parameterübergabe zu Methoden erfolgt in Java durch Wertübergabe (call by value). D.h., dass Werte von Parametervariablen in einer Methode Kopien der vom Aufrufer angegebenen Werte sind. Das nächste Beispiel verdeutlicht dies. Beispiel public class CallByValue { public static int sqr(int i) { i = i*i; return(i); } public static void main(String[] args) { int i = 3; System.out.println(sqr(i)); System.out.println(i); } > java CallByValue 9 3 } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Allerdings ist zu beachten, dass nicht Objekte, sondern Objektreferenzen übergeben werden. Wir betrachten unser Standardbeispiel Circle in folgender abgespeckter Form (gemäß der Devise, Implementierungsdetails zu verbergen, werden die Datenfelder als private deklariert). Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel public class Circle { private int x,y,r; public Circle(int x, int y, int r) { this.x = x; this.y = y; this.r = r; } public double circumference() { return 2 * Math.PI * r; } public double area() { return Math.PI * r * r; } public static void setToZero (Circle arg) { arg.r = 0; arg = null; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Fortsetzung) public static void main(String[] args) { Circle kreis = new Circle(10,10,1); System.out.println("vorher : r = "+kreis.r); setToZero(kreis); System.out.println("nachher: r = "+kreis.r); } } > java Circle vorher : r = 1 nachher: r = 0 Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Fortsetzung) public static void main(String[] args) { Circle kreis = new Circle(10,10,1); System.out.println("vorher : r = "+kreis.r); setToZero(kreis); System.out.println("nachher: r = "+kreis.r); } } > java Circle vorher : r = 1 nachher: r = 0 Dieses Verhalten entspricht jedoch nicht der Parameterübergabe call by reference, denn bei der Wertübergabe wird eine Kopie der Referenz erzeugt und die ursprüngliche Referenz bleibt erhalten. Bei call by reference würde die übergebene Referenz eben nicht kopiert und daher in der Methode setToZero auf null gesetzt. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Unterklassen und Vererbung in Java Wir wollen die Klasse Circle so erweitern, dass wir deren Instanzen auch graphisch darstellen können. Erweiterung der Klasse Circle zu der neuen Klasse GraphicCircle durch das Schlüsselwort extends wird GraphicCircle eine Unterklasse von Circle GraphicCircle erweitert die (Ober-)Klasse Circle die Klasse GraphicCircle erbt alle Attribute und Methoden von Circle, die nicht als private deklariert sind Attribute und Methoden, die als protected deklariert sind, bleiben (nur) für die Unterklasse zugreifbar Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel import java.awt.Color; import java.awt.Graphics; public class GraphicCircle extends Circle { protected Color outline; // Farbe der Umrandung protected Color fill; // Farbe des Inneren public GraphicCircle(int x,int y,int r,Color outline) { super(x,y,r); this.outline = outline; this.fill = Color.lightGray; } public GraphicCircle(int x,int y,int r,Color outline,Color fill) { this(x,y,r,outline); this.fill = fill; } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel public void draw(Graphics g) { g.setColor(outline); g.drawOval(x-r, y-r, 2*r, 2*r); g.setColor(fill); g.fillOval(x-r, y-r, 2*r, 2*r); } public static void main(String[] args) { GraphicCircle gc = new GraphicCircle(0,0,100,Color.red,Color.blue); double area = gc.area(); System.out.println(area); Circle c = gc; double circumference = c.circumference(); System.out.println(circumference); GraphicCircle gc1 = (GraphicCircle) c; Color color = gc1.fill; System.out.println(color); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Color und Graphics Color und Graphics sind vordefinierte Klassen, die durch import zugreifbar gemacht werden (vgl. Abschnitt ??). Diese Klassen werden z.B. in [3] beschrieben. Zum Verständnis reicht es hier zu wissen, dass der erste Konstruktor den Konstruktor seiner Oberklasse aufruft (vgl. Abschnitt ??) und das Kreisinnere die Farbe hellgrau erhält, sowie, dass die Methode draw einen farbigen Kreis zeichnet. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Da GraphicCircle alle Methoden von Circle erbt, können wir z.B. den Flächeninhalt eines Objektes gc vom Typ GraphicCircle berechnen durch: Beispiel double area = gc.area(); Jedes Objekt gc vom Typ GraphicCircle ist ebenfalls ein Objekt vom Typ Circle bzw. vom Typ Object. Deshalb sind folgende Zuweisungen korrekt. Beispiel Circle c = gc; double area = c.area(); Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Man kann c durch casting3 in ein Objekt vom Typ GraphicCircle zurückverwandeln. Beispiel GraphicCircle gc1 = (GraphicCircle)c; Color color = gc1.fill; Die oben gezeigte Typumwandlung funktioniert nur, weil c tatsächlich ein Objekt vom Typ GraphicCircle ist. 3 explizite Typumwandlung Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Überschreiben von Methoden und Verdecken von Datenfeldern Wir betrachten folgendes Java-Programm (Arnold & Gosling [1], S. 66): Beispiel public class SuperShow { public String str = "SuperStr"; public void show() { System.out.println("Super.show: "+str); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel (Fortsetzung) public class ExtendShow extends SuperShow { public String str = "ExtendStr"; public void show() { System.out.println("Extend.show: "+str); } public static void main(String[] args) { ExtendShow ext = new ExtendShow(); SuperShow sup = ext; sup.show(); ext.show(); System.out.println("sup.str = "+sup.str); System.out.println("ext.str = "+ext.str); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Verdecken von Datenfeldern Jedes ExtendShow-Objekt hat zwei String-Variablen, die beide str heißen und von denen eine ererbt wurde. Die neue Variable str verdeckt die ererbte; wir sagen auch die ererbte ist verborgen. Sie existiert zwar, man kann aber nicht mehr durch Angabe ihres Namens auf sie zugreifen. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Überschreiben von Methoden die Methode show() der Klasse ExtendShow überschreibt die gleichnamige Methode der Oberklasse die Implementierung der Methode der Oberklasse wird durch eine neue Implementierung der Unterklasse ersetzt dabei müssen Signatur und Rückgabetyp dieselben sein überschreibende Methoden besitzen ihre eigenen Zugriffsangaben Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Überschreiben von Methoden Wenn eine Methode von einem Objekt aufgerufen wird, dann bestimmt immer der tatsächliche Typ des Objektes, welche Implementierung benutzt wird. Bei einem Zugriff auf ein Datenfeld wird jedoch der deklarierte Typ der Referenz verwendet. Daher erhalten wir folgende Ausgabe beim Aufruf der main-Methode: Beispiel > java ExtendShow Extend.show: ExtendStr Extend.show: ExtendStr sup.str = SuperStr ext.str = ExtendStr Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Die Objektreferenz super Das Schlüsselwort super kann in allen objektbezogenen Methoden und Konstruktoren verwendet werden. In Datenfeldzugriffen und Methodenaufrufen stellt es eine Referenz zum aktuellen Objekt als eine Instanz seiner Oberklasse dar. Wenn super verwendet wird, so bestimmt der Typ der Referenz über die Auswahl der zu verwendenden Methodenimplementierung. Wir illustrieren dies wieder an einem Beispielprogramm. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung super Beispiel Beispiel public class T1 { protected int x = 1; protected String s() { return "T1"; } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel public class T2 extends T1 { protected int x = 2; protected String s() { return "T2"; } protected void test() { System.out.println("x= "+x); System.out.println("super.x= "+super.x); System.out.println("((T1)this).x= "+((T1)this).x); System.out.println("s(): "+s()); System.out.println("super.s(): "+super.s()); System.out.println("((T1)this).s(): "+((T1)this).s()); } public static void main(String[] args) { new T2().test(); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung > java T2 x= 2 super.x= 1 ((T1)this).x= 1 s(): T2 super.s(): T1 ((T1)this).s(): T2 Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Konstruktoren in Unterklassen In Konstruktoren der Unterklasse kann direkt einer der Oberklassenkonstruktoren mittels des super() Konstruktes aufgerufen werden. Achtung: Der super-Aufruf muss die erste Anweisung des Konstruktors sein! Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Wird kein Oberklassenkonstruktor explizit aufgerufen, so wird der parameterlose Konstruktor der Oberklasse automatisch aufgerufen, bevor die Anweisungen des neuen Konstruktors ausgeführt werden. Verfügt die Oberklasse nicht über einen parameterlosen Konstruktor, so muss ein Konstruktor der Oberklasse explizit mit Parametern aufgerufen werden, da es sonst einen Fehler bei der Übersetzung gibt. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Wird kein Oberklassenkonstruktor explizit aufgerufen, so wird der parameterlose Konstruktor der Oberklasse automatisch aufgerufen, bevor die Anweisungen des neuen Konstruktors ausgeführt werden. Verfügt die Oberklasse nicht über einen parameterlosen Konstruktor, so muss ein Konstruktor der Oberklasse explizit mit Parametern aufgerufen werden, da es sonst einen Fehler bei der Übersetzung gibt. Ausnahme: Wird in der ersten Anweisung eines Konstruktors ein anderer Konstruktor derselben Klasse mittels this aufgerufen, so wird nicht automatisch der parameterlose Oberklassenkonstruktor aufgerufen. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Java liefert einen voreingestellten parameterlosen Konstruktor für eine erweiternde Klasse, die keinen Konstruktor enthält. Dieser ist äquivalent zu: Beispiel public class ExtendedClass extends SimpleClass { public ExtendedClass () { super(); } } Der voreingestellte Konstruktor hat dieselbe Sichtbarkeit wie seine Klasse. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Ausnahme: Enthält die Oberklasse keinen parameterlosen Konstruktor, so muss die Unterklasse mindestens einen Konstruktor bereitstellen. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Reihenfolgeabhängigkeit von Konstruktoren Wird ein Objekt erzeugt, so werden zuerst alle seine Datenfelder auf voreingestellte Werte initialisiert. Jeder Konstruktor durchläuft dann drei Phasen: Aufruf des Konstruktors der Oberklasse. Initialisierung der Datenfelder mittels der Initialisierungsausdrücke. Ausführung des Rumpfes des Konstruktors. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel public class X { protected String infix = "fel"; protected String suffix; protected String alles; public X() { suffix = infix; alles = verbinde("Ap"); } public String verbinde(String original) { return (original+suffix); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel public class Y extends X { protected String extra = "d"; public Y() { suffix = suffix+extra; alles = verbinde("Biele"); } public static void main(String[] args) { new Y(); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Die folgende Tabelle zeigt die Inhalte der Datenfelder beim Aufruf der main-Methode (d.h. des Y-Konstruktors). Schritt 0 1 2 3 4 5 6 Alexander Goesmann A&D II, Vorlesung 2010 Aktion Datenfelder auf Voreinstellungen Y-Konstruktor aufgerufen X-Konstruktor aufgerufen X-Datenfeld initialisiert X-Konstruktor ausgeführt Y-Datenfeld initialisiert Y-Konstruktor ausgeführt infix extra suffix alles fel fel fel fel d d fel fel feld Apfel Apfel Bielefeld Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Abstrakte Klassen und Methoden Es gilt: Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Abstrakte Klassen und Methoden Es gilt: eine abstrakte Methode hat keinen Rumpf; Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Abstrakte Klassen und Methoden Es gilt: eine abstrakte Methode hat keinen Rumpf; jede Klasse, die eine abstrakte Methode enthält, ist selbst abstrakt und muss als solche gekennzeichnet werden; Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Abstrakte Klassen und Methoden Es gilt: eine abstrakte Methode hat keinen Rumpf; jede Klasse, die eine abstrakte Methode enthält, ist selbst abstrakt und muss als solche gekennzeichnet werden; man kann von einer abstrakten Klasse keine Objekte erzeugen; Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Abstrakte Klassen und Methoden Es gilt: eine abstrakte Methode hat keinen Rumpf; jede Klasse, die eine abstrakte Methode enthält, ist selbst abstrakt und muss als solche gekennzeichnet werden; man kann von einer abstrakten Klasse keine Objekte erzeugen; von einer Unterklasse einer abstrakten Klasse kann man Objekte erzeugen – vorausgesetzt sie überschreibt alle abstrakten Methoden der Oberklasse und implementiert diese; Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Abstrakte Klassen und Methoden Es gilt: eine abstrakte Methode hat keinen Rumpf; jede Klasse, die eine abstrakte Methode enthält, ist selbst abstrakt und muss als solche gekennzeichnet werden; man kann von einer abstrakten Klasse keine Objekte erzeugen; von einer Unterklasse einer abstrakten Klasse kann man Objekte erzeugen – vorausgesetzt sie überschreibt alle abstrakten Methoden der Oberklasse und implementiert diese; eine Unterklasse, die nicht alle abstrakten Methoden der Oberklasse implementiert ist selbst wieder abstrakt. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel Benchmark Beispiel public abstract class Benchmark { public abstract void benchmark(); public long repeat(int count) { long start = System.currentTimeMillis(); for(int i=0; i<count; i++) benchmark(); return (System.currentTimeMillis()-start); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Beispiel public class MethodBenchmark extends Benchmark { public void benchmark() { } public static void main(String[] args) { int count = Integer.parseInt(args[0]); long time = new MethodBenchmark().repeat(count); System.out.println(count+" Methodenaufrufe in "+time+ " Millisekunden"); } } Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld Konzepte Softwaretechnik Konstruktoren ADT in Java Methoden in Java Unterklassen und Vererbung Weiterführende Literatur K. Arnold, J. Gosling: JavaTM - Die Programmiersprache. Addison-Wesley, 1996. T.H. Cormen, C.E. Leierson, R.L. Rivest: Introduction to Algorithms. MIT Press, 1990. D. Flanagan: Java in a Nutshell. O’Reilly & Associates Inc., 1996. F. Jobst: Programmieren in Java. Hanser Verlag, 1996. H. Klaeren: Vom Problem zum Programm. 2.Auflage, B.G. Teubner Verlag, 1991. K. Echtle, M. Goedicke: Lehrbuch der Programmierung mit Java. dpunkt-Verlag, 2000. Alexander Goesmann A&D II, Vorlesung 2010 Universität Bielefeld