Liste P: Programmieren mit Java WS 2001/2002 Prof. Dr. V. Turau FH Wiesbaden Kapitel 4: Klassen und Unterklassen Folie 54 : Unterklassen Die Bildung von Unterklassen und das Konzept der Vererbung sind wichtige Prinzipien objektorientierter Programmierung Überschneidet sich die Funktionalität zweier Klassen, so werden die Gemeinsamkeiten nicht mehrfach implementiert, sondern eine Klasse wird als Unterklasse der anderen umgesetzt und erbt so die gemeinsame Funktionalität oder die Gemeinsamkeiten werden in einer eigenen Klasse implementiert die ursprünglichen Klassen werden als Unterklassen umgesetzt Folie 55 : Klassenvereinbarung Beispiele: public class Tabelle extends Element { ... } public abstract class Dialog extends Window { ... } Folie 56 : Klassenhierarchie Klassen sind in einer Hierarchie angeordnet Jede Klasse außer Object hat genau eine Oberklasse Keine Mehrfachvererbung Wird bei der Klassenvereinbarung keine Oberklasse angegeben, so ist Object die Oberklasse Eine Klasse erbt die sichtbaren Variablen und Methoden Konstruktoren werden nicht vererbt Folie 57 : Klassenvereinbarung (Beispiel) In einer Anwendung sollen XHTML-Seiten generiert werden Eine XHTML-Seite besteht aus Elementen (Tags) Tags sind ineinander geschachtelt und können Attribute haben Beispiele: <img src=’cat.gif’ height=’700’/> <ol> <li> Erstens </li> ...</ol> Zur Repräsentation von XHTML-Elementen wird die Klasse Element erstellt Folie 58 : Klassenvereinbarung (Beispiel) Was muss dargestellt werden? Name des Elementes Unterelemente (Reihenfolge ist wichtig) Attributenamen und ihre Werte (Reihenfolge ist nicht wichtig) Welche Typen bzw. Klassen werden verwendet? String Vector Properties Folie 59 : Klassenvereinbarung (Beispiel) Welche Funktionalität soll angeboten werden? Elemente mit gegebenem Namen erzeugen Unterelemente einfügen Attribute hinzufügen Eine textuelle Darstellung erzeugen Folie 60 : Die Klasse Element import java.io.*; import java.util.*; public class Element { public static final int EINZUG = 2; Vector unterElemente = new Vector(); Properties attribute = new Properties(); String name; protected Element() { } public Element(String name) { this.name = name; } public Element insertElement(Element e) { unterElemente.add(e); return this; } Folie 61 : Die Klasse Element (Forts.) public Element addAttribut(String name, String wert) { attribute.setProperty(name, wert); return this; } public void println(PrintWriter w, int offset) { printOffset(w, offset); w.print(’<’ + name); printAttribute(w); if (unterElemente.size() == 0) w.println("/>"); else { w.println(">"); printUnterElemente(w, offset + EINZUG); printOffset(w, offset); w.println("</" + name + ’>’); } } Folie 62 : Die Klasse Element (Forts.) protected void printUnterElemente( PrintWriter w, int offset){ Iterator elemente = unterElemente.iterator(); while (elemente.hasNext()) ((Element)elemente.next()).println(w, offset); } protected void printAttribute(PrintWriter w) { Enumeration enum = attribute.propertyNames(); while (enum.hasMoreElements()) { String name = (String) enum.nextElement(); w.print(’ ’ + name + "=’" + attribute.getProperty(name) + "’"); } } protected static void printOffset(PrintWriter w, int off){ for (int i = 0; i < off; i++) w.print(’ ’); } Folie 63 : Anwendung Die Anweisungen Element wurzel = new Element("html"); Element head = new Element("head"); Element body = new Element("body"); body.addAttribut("bgcolor", "blue"); wurzel.insertElement(head); wurzel.insertElement(body); wurzel.println(new PrintWriter(System.out), 0); erzeugen folgende Ausgabe: <html> <head> </head> <body bgcolor=’blue’> </body> </html> Folie 64 : Anwendung Diese Anweisungen erzeugen die gleiche Ausgabe Element wurzel = new Element("html"); wurzel.insertElement(new Element("head")). insertElement(new Element("body"). addAttribut("bgcolor", "blue")); wurzel.println(new PrintWriter(System.out), 0); Hinweis: insertElement und addAttribut geben this zurück Folie 65 : Die Klasse Img Das Image-Tag: <img src=’java.gif’ alt=’Übersicht’/> public class Img extends Element { public Img(String src, String alt) { super("img"); addAttribut("src", src); addAttribut("alt", alt); } public Img(String src) { this(src, "Ein Bild"); } } new Img("java.gif", "Übersicht") Folie 66 : Überschreiben von Methoden Hat die Methode einer Klasse die gleiche Signatur wie eine Methode in der Oberklasse, so wird die Methode der Oberklasse in der Unterklasse überdeckt. Overriding Achtung Unterschied: Overloading -- Overriding Eine überschriebene Methode kann einen anderen Modifier haben, allerdings darf der Zugriff nicht eingeschränkt werden. Folie 67 : Die Klasse Text public class Text extends Element { String text; public Text(String text) { this.text = text; } public void println(PrintWriter w, int offset) { for (int i = 0; i < offset; i++) w.print(’ ’); w.println(text); } public Element insertElement(Element e) { return this; // Text kann keine Unterelemente haben } } Folie 68 : Die Klasse A Das A-Tag: <a href=’skrip.html’> Das Skript </a> public class A extends Element { public A(String href, String text) { this(href, new Text(text)); } public A(String href, Element e) { super("a"); addAttribut("href", href); insertElement(e); } } new A("skrip.html", "Das Skript") Folie 69 : Sichtbarkeit von Klassen Variablen und Methoden einer Klasse nennt man zusammen Members (Achtung: lokale Variablen von Methoden sind keine Members) Die Sichbarkeit einer Klasse wird durch den Modifier public gekennzeichnet Eine Klasse ohne den Modifier public ist nur im eigenen Paket sichtbar, public Klassen sind überall sichtbar Die Sichbarkeit der Members einer Klasse wird durch die Modifier public, protected und private gekennzeichnet Folie 70 : Sichtbarkeit von Members public Members sind überall sichtbar protected Members sind in Klassen des gleichen Paketes und in Unterklassen sichtbar (etwas vereinfacht ausgedrückt) Members ohne Modifier sind nur in Klassen des eigenen Paketes sichtbar private Members sind außerhalb der Klasse nicht sichtbar Folie 71 : Vererbung von Variablen Eine Klasse erbt von ihrer direkten Oberklasse alle Klassen- und Instanzvariablen, welche innerhalb der Klasse sichtbar sind und nicht durch lokale Vereinbarungen überdeckt werden. Konsequenzen: private Variablen werden nicht vererbt an Klassen in anderen Paketen werden nur public und protected Variablen vererbt Das Überdecken von Variablen sollte vermieden werden! Folie 72 : Vererbung von Methoden Eine Klasse erbt von ihrer direkten Oberklasse alle Klassen- und Instanzmethoden, welche innerhalb der Klasse sichtbar sind und nicht durch lokale Vereinbarungen überdeckt werden. Beispiel: Die Klasse Object vereinbart eine Methode toString(). Fast alle Klassen überschreiben diese Methode und geben klassenspezifische Daten aus In C++-Terminologie: alle Methoden sind virtuell, d.h. die Auswahl der ausgeführten Methode erfolgt erst zur Laufzeit (late binding) Folie 73 : Late Binding public class A { public String toString() { return "Ich bin ein A"; } } public class B extends A { public String toString() { return "Ich bin ein B"; } public static void main(String[] a) { A a = new B(), b = new A(); System.out.println(a.toString()); System.out.println(b.toString()); } } Folie 74 : Late Binding Ausgabe: Ich bin ein B Ich bin ein A Besonderheit der Methode println: Hat der übergebene Parameter nicht den Typ String, so wird automatisch die Methode toString() an den Parameter geschickt und deren Rückgabe wird ausgegeben. D.h. System.out.println(a.toString()) und System.out.println(a) bewirken die gleiche Ausgabe Folie 75 : Final Members Das Schlüsselwort final kann bei der Vereinbarung von Klassen, Methoden und Variablen angegeben werden: Klassen: Es können keine Unterklassen gebildet werden (Beispiele: String, URL, Integer) Methoden: Dürfen nicht überschrieben werden Variablen: Ein einmal zugewiesener Wert kann nicht mehr verändert werden. In vielen Fällen kann der Compiler den Code optimieren Folie 76 : Abstrakte Klassen und Methoden Abstrakte Klassen können Methoden vereinbaren, ohne dafür eine Implementierung anzugeben Solche Methoden werden genau wie abstrakte Klassen mit dem Modifier abstract gekennzeichnet Unterklassen von abstrakten Klassen sind selber abstrakt oder implementieren alle abstrakten Methoden der Oberklasse Folie 77 : Abstrakte Klassen und Methoden Von abstrakten Klassen können keine Instanzen gebildet werden Anwendung: Abstrakte Klassen werden eingesetzt, wenn ein Teil der Funktionalität von der speziellen Ausprägung eines Objektes abhängt, der andere Teil gilt für alle Ausprägungen und kann mit Hilfe der abstrakten Methoden implementiert werden Abstrakte Klassen können Konstruktoren vereinbaren, warum? Folie 78 : Abstrakte Klassen und Methoden (Beispiel) package java.awt.image; public abstract class ColorModel { public public public public abstract abstract abstract abstract int int int int getRed(int pixel); getGreen(int pixel); getBlue(int pixel); getAlpha(int pixel); public int getRGB(int pixel) { return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) | (getBlue(pixel) << 0) ; } } Folie 79 : Native Methoden Methoden einer Java-Klasse können auch in C implementiert werden Solche Methoden haben den Modifier native Zu Bindung der C-Programme an Java Klassen wird das Werkzeug javah verwendet Nachteil von nativen Methoden: Plattformunabhängigkeit geht verloren Anwendungsbeispiel: Kommunikation mit spezieller Hardware Folie 80 : Garbage Collection Java hat eine automatische Freispeicherverwaltung Der Garbage Collector läuft in einem eigenen Thread und arbeitet im Hintergrund Sobald ein Objekt nicht mehr über andere Objekte bzw. Variablen erreichbar ist, kann der belegte Speicher vom Garbage Collector freigegeben werden Die Option -verbose:gc des Java Interpreters zeigt die Aktivität des Garbage Collectors an