FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 11 INHERITANCE 1 Einleitung Sie haben die Begriffe Klasse und Objekt bereits kennen gelernt. Sie wissen, dass eine Klasse eine Beschreibung für gleichartige Objekte ist. Sie definiert, welche Attribute und Operationen alle Objekte besitzen, die zu dieser Klasse gehören. Zum Beispiel können wir eine Klasse Personenwagen definieren. Die Klasse definiert die gemeinsamen Attribute und Operationen aller Autos. Anhand der Klasse Personenwagen können wir dann beliebig viele Autos, oder eben Personenwagen-Objekte, erzeugen. Im Klassendiagramm könnte das so aussehen: myCar Personenwagen modell leistung anzahlPersonen starten() beschleunigen() bremsen() modell = DöSchwo leistung = 2 PS anzahlPersonen = 5 otherCar modell = Mercedes 500 leistung = 200 PS anzahlPersonen = 5 So weit, so gut. Was nun, wenn wir eine Klasse für Lastwagen schreiben sollen? Müssen wir dann nicht Attribute und Operationen, welche in der Klasse Personenwagen schon definiert sind, nochmals definieren? Zum Beispiel haben ja auch Lastwagen einen Motor mit einer Leistung. Dies ist ein Attribut, welches für alle Motorfahrzeuge gilt. Was uns fehlt, ist ein übergeordnetes, allgemeineres Konzept. 11 Inheritance.doc, V10 © H. Diethelm Seite 1/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE 2 Klassenhierarchien Die Lösung für unser Problem sieht folgendermassen aus: Wir definieren zuerst eine Klasse Motorfahrzeug. Diese enthält alle gemeinsamen Attribute und Operationen von Motorfahrzeugen. Im Klassendiagramm: Motorfahrzeug modell leistung starten() beschleunigen() bremsen() Mit Hilfe dieser Klasse können wir nun unsere bestehende Klasse Personenwagen sowie die neue Klasse Lastwagen auf einfachere Weise definieren: Wir sagen nur noch, welche zusätzlichen Attribute und Eigenschaften diese Klassen haben. Gleichzeitig legen wir fest, dass die Klassen auch über sämtliche Eigenschaften der Klasse Motorfahrzeug verfügen. 11 Inheritance.doc, V10 © H. Diethelm Seite 2/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Wieder in UML: Der Pfeil von der Klasse Personenwagen zur Klasse Motorfahrzeug symbolisiert, dass die Klasse Personenwagen neben ihren eigenen Attributen und Operationen auch über all jene der Klasse Motorfahrzeug verfügt. Man sagt, die Klasse Personenwagen erbt die Attribute und Operationen von der Klasse Motorfahrzeug. Man sagt auch, die Klasse Personenwagen ist von der Klasse Motorfahrzeug abgeleitet oder die Klasse Personenwagen erweitert die Klasse Motorfahrzeug. Motorfahrzeug ist die Superklasse und Personenwagen ist die Subklasse. Die drei Klassen bilden eine Klassenhierarchie. Geht man in der Hierarchie nach oben, so kommt man zu immer allgemeineren Klassen. Ein Personenwagen ist z.B. ein spezielles Motorfahrzeug; man spricht deshalb auch von einer is-a-Beziehung. Geht man nach unten, findet man immer spezialisiertere Klassen. 11 Inheritance.doc, V10 © H. Diethelm Seite 3/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE Aufgabe 1: a) Erweitern Sie obige Klassenhierarchie um folgende Elemente: - Eine Klasse für Motorräder - Eine Klasse für Cabriolets Zeichnen Sie ein paar Attribute und Operationen ein, welche typisch für die beiden neuen Klassen sind. b) Überlegen Sie sich, wie eine Klasse Fahrrad in die Klassenhierarchie integriert werden könnte. Zeichnen Sie ihren Vorschlag im Klassendiagramm ein. 11 Inheritance.doc, V10 © H. Diethelm Seite 4/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 3 Vererbung versus Aggregation Die Gefahr besteht, mit der Zeit zu sehr grossen und unübersichtlichen Klassenhierarchien zu kommen. Beispielsweise könnte man versucht sein, zwischen Motorfahrzeugen mit Elektroantrieb und solchen mit Verbrennungsmotor zu unterscheiden. Das würde aber zu einer Verdoppelung von Klassen führen, denn es gibt ja für beide Antriebsarten Personenwagen. Hier wäre vielmehr ein Aggregations-Beziehung (vgl. has-aBeziehung) zwischen der Klasse Motorfahrzeug und einer Klasse Motor angezeigt. Die Klasse Motor könnte dann ihrerseits wieder abgeleitet werden. In UML: Motor leistung Motorfahrzeug Elektromotor Verbrennungsmotor Wichtig zu wissen ist, dass es nicht DAS Klassendiagramm für ein bestimmtes Problem gibt! Die möglichen Lösungen sind meist sehr vielfältig und Modellieren ist ein iterativer, d.h. sich wiederholender Prozess. 11 Inheritance.doc, V10 © H. Diethelm Seite 5/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 4 Umsetzung in Java Wie man in Java eine Klasse definiert, das wissen Sie bereits. Neu für Sie ist, wie man in Java eine Klasse von einer anderen ableitet. Und eigentlich haben Sie auch das schon x-mal gemacht: class ... } MyApplet extends Applet { Mit dem Schlüsselwort extends kann man definieren, von welcher Klasse eine neue Klasse abgeleitet sein soll. In UML: 11 Inheritance.doc, V10 © H. Diethelm Seite 6/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE Das Motorfahrzeug-Beispiel würde demnach folgendermassen in Java umgesetzt: class Motorfahrzeug { public String modell; // Vorsicht mit public! public double leistung; public void starten() { ... } } class Personenwagen extends Motorfahrzeug { public int anzahlPersonen; // Vorsicht mit public! ... } 11 Inheritance.doc, V10 © H. Diethelm Seite 7/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE 5 Zugriff auf Instanzvariablen und Methoden der Superklasse(n) 5.1 Schlüsselwort public Aus abgeleiteten Klassen kann grundsätzlich auf alle publicElemente der Superklasse (und wiederum derer Superklasse etc.) zugegriffen werden, wie wenn diese in der eigenen Klasse definiert wären. Im obigen Beispiel kann also eine Methode in der Klasse Personenwagen auf die Instanzvariablen modell und leistung zugreifen, welche in Motorfahrzeug deklariert sind. Ebenso kann sie die Methode starten() direkt aufrufen: class Personenwagen extends Motorfahrzeug { ... public void demoMethode() { leistung = 2000.0; starten(); } ... 11 Inheritance.doc, V10 © H. Diethelm Seite 8/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE 5.2 Schlüsselwort private Hingegen kann aus einer abgeleiteten Klasse auf keine privateElemente der Superklasse (weder Instanzvariablen noch Methoden) zugegriffen werden. Guter Programmierstil ist, Instanzvariablen möglichst als private zu deklarieren! Zugriffe auf die Instanzvariablen erfolgen dann ausschliesslich über entsprechende set- und getZugriffsmethoden, welche auch allfällige Integritätsbedingungen sicherstellen. Zudem kann so gegebenenfalls die interne Repräsentation einfach und lokal in der Klasse geändert werden. class Motorfahrzeug { private String modell; private double leistung; public void setLeistung(double l) { if (l > 0.0) leistung = l; } public void starten() { ... } } class Personenwagen extends Motorfahrzeug { ... public void demoMethode() { setLeistung(2000.0); starten(); } ... 11 Inheritance.doc, V10 © H. Diethelm Seite 9/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 5.3 Schlüsselwort protected Die Zugriffsregel für private-Elemente kann zu einschränkend sein. Aus diesem Grund gibt es in Java das Schlüsselwort protected, welches erlaubt, Elemente einer Klasse für die abgeleiteten Klassen zugänglich zu machen, gegen "aussen" aber zu schützen. Fehlt ein Schlüsselwort private, protected oder public, so wird der Zugriff gemäss untenstehender Tabelle geregelt. Wie Sie sehen, wird dann der Zugriff relativ restriktiv gehandhabt. Zugriff von: eigener Klasse Klasse Unterklasse Nicht-Unterim gleichen aus andeklasse aus Package rem Packa- anderem ge Package private ja nein nein nein - ja ja nein nein protected ja ja ja* nein public ja ja ja* ja* (*) Die Klasse muss dann natürlich importiert sein. Bemerkung: Ein Package fasst Klassen zusammen, die eng miteinander kooperieren oder die zumindest konzeptionell zusammengehören. Die Klassen müssen dazu auch im gleichen Verzeichnis gespeichert sein (siehe später). 11 Inheritance.doc, V10 © H. Diethelm Seite 10/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Aufgabe 2: Wir möchten eine Klassenhierarchie für Grafiken entwickeln (z.B. für ein Grafikprogramm). Eine Grafik soll aus Kreisen oder Rechtecken bestehen. Beides sind Figuren. Gesucht sind Klassen, welche die wesentlichen Informationen sowie die notwendigen Methoden gemäss folgender Beschreibung enthalten: Das Rechteck ist durch seine Breite und Höhe definiert, der Kreis durch seinen Radius. Kreis und Rechteck ist gemeinsam, dass sie sich an einem bestimmten Ort auf dem Bildschirm befinden. Dieser ist definiert durch die linke, obere Ecke des Rechtecks oder eines gedachten, den Kreis umgebenden Rechtecks. Beide haben eine Methode display(), um sich auf dem Bildschirm zu zeichnen, sowie einen Konstruktor, welcher die nötigen Parameter für eine vollständige Festlegung eines Kreis- bzw. eines Rechteck-Objekts aufweist. Schliesslich soll eine Methode moveTo() zum Verschieben von Kreis- und Rechteck-Objekten an einen neuen Ort vorhanden sein. Die Methode hat als Parameter die Koordinaten des neuen Ortes. Zeichnen Sie ein Klassendiagramm und versuchen Sie, die beiden Klassen Rectangle und Circle sowie die übergeordnete Klasse Figure gemäss den obigen Angaben zu programmieren. Überlegen Sie sich, welche Instanzvariablen und Methoden in welche Klassen gehören. Die Regel heisst: Gemeinsame "Dinge" gehören in die Superklasse. Studieren Sie die Unterlagen noch nicht weiter, denn Sie wollen ja selber eine Lösung erarbeiten! 11 Inheritance.doc, V10 © H. Diethelm Seite 11/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE 11 Inheritance.doc, V10 © H. Diethelm Seite 12/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE Klassendiagramm in UML: Figure -xPos:int -yPos:int +Figure(x:int, y:int) +moveTo(x:int, y:int):void +setXPos(x:int):void +setYPos(y:int):void +getXPos():int +getYPos():int Circle Rectangle -radius:int -width:int -height:int +Circle(x:int, y:int, r:int) +setRadius(r:int):void +getRadius():int +display(g:Graphics):void +Rectangle(x:int, y:int, w:int, h:int) +setSize(w:int, h:int):void +getWidth():int +getHeight():int +display(g:Graphics):void Bemerkung: Obiges Klassendiagramm hält explizit Sichtbarkeit, Datentypen, formale Parameter sowie die Datentypen der Rückgabewerte fest. Die UML schreibt diese Vollständigkeit nicht vor. Entsprechend dem Kontext, in dem das Klassendiagramm verwendet wird, kann man teilweise oder ganz auf diese Präzisierungen verzichten. 11 Inheritance.doc, V10 © H. Diethelm Seite 13/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Java-Sourcecode: class Figure { private int xPos; private int yPos; public Figure(int x, int y) { xPos = x; yPos = y; } public void moveTo(int x, int y) { xPos = x; yPos = y; } public void setXPos(int x) { xPos = x; } public void setYPos(int y) { yPos = y; } public int getXPos() { return xPos; } public int getYPos() { return yPos; } } 11 Inheritance.doc, V10 © H. Diethelm Seite 14/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE import java.awt.Graphics; class Circle extends Figure { private int radius; public Circle (int x, int y, int r) { super(x, y); radius = r; } public void setRadius(int r) { radius = r; } public int getRadius() { return radius; } public void display(Graphics g) { g.drawOval(getXPos(), getYPos(), 2*radius, 2*radius); } } 11 Inheritance.doc, V10 © H. Diethelm Seite 15/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE import java.awt.Graphics; class Rectangle extends Figure { private int width; private int height; public Rectangle(int x, int y, int w, int h){ super(x, y); width = w; height = h; } public void setSize(int w, int h) { width = w; height = h; } public int getWidth() { return width; } public int getHeight() { return height; } public void display(Graphics g) { g.drawRect(getXPos(), getYPos(), width, height); } } 11 Inheritance.doc, V10 © H. Diethelm Seite 16/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Bemerkungen: Alle Instanzvariablen sind private deklariert. Zugriffe erfolgen ausschliesslich über set- und get-Zugriffsmethoden. Jedes Rechteck-Objekt ist auch ein Figur-Objekt. Ebenso ist jedes Kreis-Objekt ein Figur-Objekt. Erstere sind Spezialisierungen von letzteren. Deshalb muss der Konstruktor Rectangle() in einem ersten Schritt ein Figur-Objekt konstruieren und darf erst in einem zweiten Schritt rechteckspezifische Belange berücksichtigen! Mit super (vgl. super(), super.variable, super.methode()) kann explizit Bezug auf die Oberklasse genommen werden. So ruft super(x, y) den entsprechenden Konstruktor der Oberklasse Figure auf. Besitzt die Oberklasse gar keinen explizit deklarierten Konstruktor, so ist ein super()-Aufruf nicht zwingend notwendig. Es wird dann sozusagen ein leerer Default-Konstruktor aufgerufen. Besitzt die Oberklasse einen explizit deklarierten Konstruktor ohne Parameter, so ist ein super()-Aufruf ebenfalls nicht zwingend erforderlich; er wird in diesem Fall automatisch aufgerufen. Aufgabe 3: Angenommen die Instanzvariablen xPos und yPos der Klasse Figure seien nur protected deklariert. Schreiben Sie für diesen Fall nochmals den Quellencode für die Klassen Rectangle und Circle. 11 Inheritance.doc, V10 © H. Diethelm Seite 17/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 6 Anwendung der eigenen Grafik-Klassen Die Klassen, welche wir in der obigen Aufgabe entwickelt haben, können wir jetzt zum Beispiel in einem Applet einsetzen: import java.awt.*; import java.applet.Applet; public class Figurlet extends Applet { private Rectangle myRectangle; private Circle myCircle; public void init() { myRectangle = new Rectangle(100,100,20,40); myCircle = new Circle(200,100,30); } public void paint(Graphics g) { myRectangle.display(g); myCircle.display(g); } } 11 Inheritance.doc, V10 © H. Diethelm Seite 18/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Schliesslich könnten wir in unserem Applet auch die moveTo()Methoden aufrufen (z.B. als Antwort auf ein Event): ... myRectangle.moveTo(newX, newY); myCircle.moveTo(newX, newY); ... Bemerkung: Beachtenswert ist, dass wir die Methode moveTo() bei einem Rechteck- bzw. bei einem Kreis-Objekt aufrufen. Effektiv ist die Methode aber in der Klasse Figure definiert. Rechteck- und Kreis-Objekt sind aber gleichzeitig auch Figur-Objekte! Klassendiagramm in UML: 11 Inheritance.doc, V10 © H. Diethelm Seite 19/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 7 Zuweisung von Objekten zu Referenzvariablen Ein Objekt einer bestimmten Klasse (vgl. Rectangle) darf man jederzeit einer anderen Referenzvariablen derselben Klasse zuweisen (vgl. rect2). Auch dürfen gleichzeitig mehrere Referenzvariablen ein und dasselbe Objekt referenzieren (vgl. rect2 und rect3). Der Spezialwert null für "kein Objekt" kann immer zugewiesen werden. ... Rectangle rect1 = new Rectangle(10,10,20,30); Rectangle rect2 = rect1; Rectangle rect3 = rect2; rect1 = null; ... Gemäss Vererbungshierarchie gilt, dass ein Rechteck-Objekt gleichzeitig auch ein Figur-Objekt ist. Deshalb ist es auch möglich, ein Rectangle-Objekt einer Figure-Referenzvariablen zuzuweisen. ... Rectangle rect = new Rectangle(10,10,20,30); Figure fig = rect; ... Allerdings sind wir jetzt bezüglich der Möglichkeiten eingeschränkt, welche wir mit fig haben! Wichtig zu wissen ist, dass ein Objekt seine Klassenzugehörigkeit und seine Interna IMMER beibehält, auch wenn es von einer Referenzvariablen einer Oberklasse referenziert wird. (Es findet also keine Umwandlung der internen Darstellung statt, wie das bei der Zuweisung von Werten elementarer Datentypen passieren kann.) Allerdings ändert sich die Betrachtungsweise des Objektes; man betrachtet das Objekt sozusagen durch die "Brille der Oberklasse": 11 Inheritance.doc, V10 © H. Diethelm Seite 20/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Über fig kann nur auf die public Methoden und Instanzvariablen der Klasse Figure zugegriffen werden, denn fig kann ein Rectangle-, Circle- oder Figure-Objekt referenzieren! Weiter ist ein Zugriff auf Methoden und Instanzvariablen von Oberklassen möglich, falls diese zugänglich sind. ... rect = fig; // => Compilerfehler !! rect = (Rectangle) fig; // => korrekt ... Weil fig auch ein Circle-Objekt referenzieren kann, ist die erste Zuweisung nicht erlaubt! Der Compiler wird mit einer Fehlermeldung reagieren, weil man eine "allgemeinere Referenz" einer "spezielleren Referenz" zuweisen will. Die zweite Zuweisung mit dem Cast ist hingegen korrekt. Der Cast ist sozusagen eine Zusicherung/ein Versprechen, dass fig ein Rectangle-Objekt referenziert und die Zuweisung demzufolge möglich ist. Stellt sich zur Laufzeit heraus, dass dem nicht so ist, wird ein Laufzeitfehler bzw. eine Exception die Folge sein! 11 Inheritance.doc, V10 © H. Diethelm Seite 21/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 8 Überschreiben von Methoden und Polymorphismus In unserem Beispiel fällt auf, dass beide Klassen Rectangle und Circle je eine Methode display() haben. Von der Idee her machen beide Methoden dasselbe, sie zeichnen ihr Objekt. Eigentlich könnte man wünschen, dass jede Figur eine display()-Methode hat. Wie die Methode eine Figur zeichnet, hängt dann von der konkreten Situation bzw. vom konkreten Objekt ab. Ist die Figur ein Rechteck wird ein Rechteck gezeichnet etc. Genau das kann Java: Wir definieren zusätzlich auch in der Klasse Figure eine Methode display(). Diese Methode wird genau dann aufgerufen, falls fig ein Figur-Objekt referenziert. Referenziert fig aber ein Objekt einer Unterklasse, z.B. ein Kreis-Objekt, so wird automatisch die korrespondierende Methode display() der Unterklasse Circle aktiviert. class Figure { ... public void display(Graphics g) { g.drawString("I'm a Figure.", xPos, yPos); } ... } 11 Inheritance.doc, V10 © H. Diethelm Seite 22/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE class Circle extends Figure { ... public void display(Graphics g) { g.drawOval(getXPos(), getYPos(), 2*radius, 2*radius); } ... } class Rectangle extends Figure { ... public void display(Graphics g) { g.drawRect(getXPos(), getYPos(), width, height); } ... } Die Methode display() ist sowohl in der Klasse Figure wie auch in den Klassen Circle und Rectangle definiert. Die Methodenköpfe (Signaturen) müssen dabei absolut gleich sein! Man nennt dies Überschreiben einer Methode. 11 Inheritance.doc, V10 © H. Diethelm Seite 23/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE Damit können wir nun in einer Anwendung folgendes tun: ... Figure fig1 = new Figure(10, 120); Figure fig2 = new Rectangle(10, 10, 20, 30); Figure fig3 = new Circle(10, 60, 40); public void paint(Graphics g) { fig1.display(); fig2.display(); fig3.display(); } ... fig1 bis fig3 sind drei Referenzvariablen für Figur-Objekte. Ihnen werden je ein Figure-, Rectangle- und Circle-Objekt zugewiesen. In der paint()-Methode wird bei allen drei Referenzvariablen die display()-Methode aufgerufen. Weil die Methode display() in den abgeleiteten Klassen überschrieben ist, geschieht folgendes: Es wird bei allen drei Aufrufen immer diejenige Variante von display() ausgeführt, welche zur Klasse bzw. zum Objekt gehört, das referenziert wird. fig1.display() => Text ausgeben fig2.display() => Rechteck zeichnen fig3.display() => Kreis zeichnen Dies ist ein sehr mächtiges Konzept und wird in der objektorientierten Programmierung oft angewendet. Es erlaubt, unabhängigen Code zu schreiben. Wenn eine neue Figur-Klasse, z.B. für Dreiecke, eingeführt wird, so sind die Änderungen am bestehenden Code minimal. Das Konzept segelt auch unter dem Begriff Polymorphismus oder frei übersetzt "Vielgestaltigkeit". 11 Inheritance.doc, V10 © H. Diethelm Seite 24/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE Klassendiagramm in UML: is-a Applet Figurlet has-a 3 Figure is-a is-a +moveTo() +display() Rectangle Circle +display() +display() 9 Abstrakte Klassen Ist die Sachlage so, dass Objekte der Klasse Figure keinen Sinn machen, so kann die Klasse als abstract deklariert werden. Es ist dann nicht mehr möglich, Objekte dieser Klasse zu instanzieren. Damit wird auch die Methode display() in der Klasse Figure nie mehr zur Ausführung gelangen. Trotzdem macht es Sinn, eine abstrakte Methode display() bzw. den entsprechenden Methodenkopf in der Klasse Figure zu deklarieren. Damit wird zum Ausdruck gebracht, dass sämtliche Figur-Objekte eine Methode display() besitzen, die allerdings in den Unterklassen noch implementiert werden müssen. Die abstrakte Klasse Figure garantiert damit ein bestimmtes Verhalten für sämtliche Figur-Objekte. 11 Inheritance.doc, V10 © H. Diethelm Seite 25/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE Randbemerkung: Ein Interface bzw. eine Schnittstellenklasse ermöglicht Ähnliches, aber ohne Gebrauch der klassischen Vererbung (siehe später). Klassendiagramm in UML: Figure -xPos:int -yPos:int +Figure(x:int, y:int) +moveTo(x:int, y:int):void +setXPos(x:int):void +setYPos(y:int):void +getXPos():int +getYPos():int +display(g:Graphics):void Circle Rectangle -radius:int -width:int -height:int +Circle(x:int, y:int, r:int) +setRadius(r:int):void +getRadius():int +display(g:Graphics):void +Rectangle(x:int, y:int, w:int, h:int) +setSize(w:int, h:int):void +getWidth():int +getHeight():int +display(g:Graphics):void 11 Inheritance.doc, V10 © H. Diethelm Seite 26/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE abstract class Figure { ... public abstract void display(Graphics g); ... } class Circle extends Figure { ... public void display(Graphics g) { g.drawOval(getXPos(), getYPos(), radius, radius); } ... } class Rectangle extends Figure { ... public void display(Graphics g) { g.drawRect(getXPos(), getYPos(), width, height); } ... } ... Figure fig1 = new Rectangle(10, 10, 20, 30); Figure fig2 = new Circle(10, 60, 40); public void paint(Graphics g) { fig1.display(); fig2.display(); } ... 11 Inheritance.doc, V10 © H. Diethelm Seite 27/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE 10 Beispiel AWT Abstract: allgemeiner plattformunabhängiger Ansatz Window: Umgang mit Fenstersystemen Toolkit: sehr grosse Klassenbibliothek 10.1 Bildschirmausgabe in Windowsystemen "Nicht der Programmierer bestimmt, wann etwas auf dem Bildschirm dargestellt wird, sondern der User." Entsprechend bestimmt nicht das Programm, wann etwas auf dem Bildschirm dargestellt werden soll, sondern das Windowsystem. Konsequenzen: Das Programm muss zu jedem Zeitpunkt in der Lage sein, die komplette Bildschirmausgabe zu rekonstruieren. Das Programm muss das Windowsystem über neu anzuzeigende Bildschirminhalte informieren. Das Windowsystem ruft die paint()-Methode eines Applets oder Programms auf, sobald das Applet gezeichnet werden soll. Das Applet oder Programm ruft seine repaint()-Methode auf, sobald es wünscht, neu gezeichnet zu werden. 11 Inheritance.doc, V10 © H. Diethelm Seite 28/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE 10.2 Wichtige Klassen für das elementare Zeichnen Graphics: Stellt die eigentlichen Zeichenoperationen zur Verfügung. Graphics-Objekte dienen als eine Art "Zeichenblatt". Sie werden nicht selbst instanziert, sondern vom Ausgabegerät zur Verfügung gestellt (z.B. Bildschirm, Drucker). Zusätzlich speichert die Klasse den aktuellen Zustand des Gerätes (z.B. Zeichenfarbe, Font, Clipping-Region). Color: Farben Font: Schrifttypen Point: Punkt mit Koordinaten x, y Dimension: Grössenangabe mit width und height Rectangle: Rechteck Polygon: n-Eck Image: abstrakte Klasse für Bitmap-Grafiken AWT-Klassenhierarchie (Ausschnitt 1): Object equals():boolean Graphics drawLine(): void getFont(): Font Color Font Point Dimension Rectangle Polygon Image black: Color name:String size:int x:int y:int height:int width:int height:int width:int npoints:int xpoint:int[] SCALE_FAST:int darker():Color getName():String getX():double move():void equals():boolean setSize():void move():void resize():void addPoint():void inside():boolean getHeight():int 11 Inheritance.doc, V10 © H. Diethelm Seite 29/31 Abteilung Informatik, Fach Programmieren FHZ Hochschule für Technik+Architektur Luzern 11 INHERITANCE 10.3 Wichtige Klassen für GUIs Component: Das sind die Grundbausteine für ein GUI. Alles, was man sieht, ist ein Component! Die Klasse Component hat sehr viele Methoden. Im Zweifelsfalle hier eine Methode suchen! Canvas: Die einfachste Zeichenoberfläche (vgl. wie Applet ohne Funktionalität). Besitzt im Wesentlichen ein Graphics-Objekt. Container: Ein Behälter für Components. Die Anordnung der Bildelemente wird durch das Layout des Containers bestimmt. Typische Container sind Panel und Window. Ermöglicht eine hierarchische Gestaltung des GUI. Panel: Ein Objekt zum Zusammenfassen grösserer Sinneseinheiten in einem Fenster. Window: Ein einfaches Fenster-Objekt. Frame: Ein "richtiges" Fenster-Objekt. Hat einen Titelbalken, kann vom Benutzer verkleinert und vergrössert werden, kann ein Menü haben usw. (vgl. Java-Programme). Button: Druckknopf Checkbox: Ankreuzfeld Choice: Auswahlmenü (Pull-Down) List: Auswahlmenü Label: statischer Text Scrollbar: Schieberegler TextField: Texteingabe (einzeilig) TextArea: Texteingabefeld (mit mehreren Zeilen) 11 Inheritance.doc, V10 © H. Diethelm Seite 30/31 FHZ Hochschule für Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren 11 INHERITANCE AWT-Klassenhierarchie (Ausschnitt 2): Object equals():boolean Component paint():void repaint():void update():void Checkbox getLabel():String setState():void Choice Container addItme():void remove():void add():void remove():void paint():void setLayout():void Panel ScrollPane Button Canvas List Label TextComponent CENTER:int getLabel():String setLabel():void paint():void getRows():int select():void setText():void Scrollbar VERTICAL:int getText():String select():void getMinimum():int getValue():int Window SCROLLBARS_ NEVER:int addNotify():void setLayout():void show():void toBack():void Applet Dialog Frame init():void setModal():void setTitle():void setMenuBar():voi d FileDialog LOAD:int READ:int getFile():String getMode():int Ein Container ist bekanntlich ein Behälter (vgl. Aggregat) für Components (sogenanntes Composite-Entwurfsmuster): Component 0..n Container add():void remove():void paint():void setLayout():void paint():void repaint():void update():void Button getLabel():String setLabel():void Label Scrollbar CENTER:int VERTICAL:int setText():void getMinimum():int getValue():int Panel addNotify():void Applet init():void 11 Inheritance.doc, V10 © H. Diethelm Seite 31/31