Grundzüge der Informatik Teil 2: Objektorientierte Programmierung 2.3 Modularisierung Prof. Dr. Max Mühlhäuser FG Telekooperation TU-Darmstadt Java-Pakete: Überblick Pakete (Packages) ermöglichen: • Bündeln von Klassen, die zu einem gemeinsamen Aufgabenbereich gehören • Vermeiden von potentiellen Namenskonflikten – Klassennamen müssen innerhalb eines Pakets eindeutig sein – Ein Klassenname kann in anderen Paketen erneut verwendet werden • Definition und Kontrolle von Zugriffen und Sichtbarkeit 2003 © MM ... GdI1 - 2.3: Modularisierung 2 Java-Pakete: Überblick • Jede Klasse (und jede Schnittstelle) in Java ist Bestandteil genau eines Pakets – Ist eine Klasse (oder eine Schnittstelle) nicht explizit einem Paket zugeordnet, dann gehört es implizit zu einem default-Paket • Paket-Hierarchie – Pakete sind hierarchisch gegliedert à ein Paket kann Unterpakete besitzen, die selbst wieder in Unterpakete aufgeteilt sind, usw. • Punktnotation der Paketnamen paket.unterpaket1.unterpaket11.Klasse • Paketnamen sind sehr wichtig bei der Suche nach Klassen 2003 © MM ... GdI1 - 2.3: Modularisierung 3 Java-Pakete • Zu welchem Paket eine Klasse gehört, wird in der zugehörigen .java-Datei bestimmt • Der Quelltext eines gesamten Java-Programms kann über mehrere Klassen und damit Dateien verteilt sein • Typdefinitionen einer Datei können auch zu mehreren Programmen gehören (d.h. von ihnen verwendet werden) à Wiederverwendung 2003 © MM ... GdI1 - 2.3: Modularisierung 4 Java-Pakete • Struktur einer .java-Datei: Source-File = [Package-Declaration] {Import-Declaration} { Class-Definition | Interface-Definition }. Package-Declaration = "package" Package-Name ";". Package-Name = Identifier { "." Identifier }. • Vor der Package-Declaration dürfen nur Kommentare und Leerzeilen stehen • Nur eine Package-Declaration pro Datei • Wird die Package-Declaration weggelassen, ist die Datei Element des Default-Pakets 2003 © MM ... GdI1 - 2.3: Modularisierung 5 Java-Pakete Paketdeklaration • Der selbe Paketname kann in mehreren Dateien verwendet werden – Typdefinitionen, die zu einem Paket gehören, können somit über mehrere Übersetzungseinheiten verteilt sein à Kürzere Übersetzungszeiten à Arbeitsaufteilung in großen Projekten wird unterstützt • Paketname wird implizit jedem im Paket enthaltenen Typnamen vorangestellt à Abtrennung durch einen Punkt – Der vollständige Name einer Klasse ist packagename.classname 2003 © MM ... GdI1 - 2.3: Modularisierung 6 Java-Pakete Import-Deklaration Import-Declaration = "import" Package-Name "." (Class-Name | "*") ";". • Wird der Klassenname angegeben, kann auf diesen künftig ohne Angabe des Pakets zugegriffen werden • Wird * angegeben, können sämtliche im Paket enthaltene Klassen ohne weitere Angabe des Paketnamens verwendet werden 2003 © MM ... GdI1 - 2.3: Modularisierung 7 Java-Pakete Nutzen von Klassen eines anderen Pakets • Volle Qualifizierung der Klasse, z.B. java.util.Random einZufall = new java.util.Random(); • import-Anweisung, z.B. import java.util.Random; ... Random einZufall = new Random(); 2003 © MM ... GdI1 - 2.3: Modularisierung 8 Java-Pakete Nutzen von Klassen eines anderen Pakets • import paket.* : alle Klassen des Pakets, z.B. import java.util.*; ... Random einZufall = new Random(); • Schlechter Stil: für Leser ist unklar, was gebraucht wird • Nur wenn (fast) alle Typdefinitionen eines Pakets benötigt werden, ist die *-Form angebracht 2003 © MM ... GdI1 - 2.3: Modularisierung 9 Import von Paketen • Durch die Verwendung von Import-Anweisungen können Namenskonflikte auftreten – Existieren identische Typnamen in mehr als einer der importierten Pakete, muss bei der Verwendung dieser Namen immer das Paketpräfix benutzt werden, z.B. import java.awt.*; // Enthaelt eine Klasse List import java.util.*; // Enthaelt ebenfalls eine // Klasse List ... java.util.List list; // Paketname verwenden um festzustellen, // welche List verwendet wird 2003 © MM ... GdI1 - 2.3: Modularisierung 10 Import von Paketen • In jeder Datei werden einige Pakete automatisch importiert: – Das eigene Paket – Das vordefinierte Paket java.lang • enthält elementare Klassen wie z.B. Object, String 2003 © MM ... GdI1 - 2.3: Modularisierung 11 Import von Paketen • Zu Java gehören eine Vielzahl vordefinierter Pakete, die mit dem JDK ausgeliefert werden, z.B.: – – – – – – java.applet java.io java.net java.util java.util.zip usw. 2003 © MM ... Applet-Unterstützung Ein- und Ausgabe für Dateien Netzwerkprogrammierung Hilfsklassen, z.B. Zufallszahlengenerator Hilfsklassen zum Verwenden von .zip-Dateien GdI1 - 2.3: Modularisierung 12 Paketbenennung • Paketnamen spielen eine zentrale Rolle für die Vermeidung oder Auflösung von Namenskonflikten – sollten bedeutungstragend sein – sollten möglichst eindeutig sein, am besten weltweit • Konventionen zur Konstruktion weltweit eindeutiger Paketnamen – Der Paketname enthält als Präfix den Internet-DomainNamen der Hersteller in umgekehrter Reihenfolge – Bindestriche sind in Paketnamen nicht erlaubt – Beispiele • • • • 2003 © MM ... URL der Firma Sun: sun.com Klassen der Firma Sun: com.sun.paket1.paket11.Klasse URL der TU Darmstadt: informatik.tu-darmstadt.de Klassen der TU Darmstadt: de.tudarmstadt.informatik.paket1.paket11.Klasse GdI1 - 2.3: Modularisierung 13 Paketbenennung Paketnamen und Dateisystemstrukturen • Für die Zuordnung von Paketnamen zu Dateinamen müssen Punkte im Paketnamen durch das Trennzeichen des Betriebsystems ersetzt werden – UNIX: / à Slash – Microsoft-Betriebsysteme \ à Backslash • Beispiel: – Paketname: kilian.hobby.raytracer – Zugehöriger UNIX-Verzeichnisname: kilian/hobby/raytracer – Zugehöriger Windows-Verzeichnisname: kilian\hobby\raytracer 2003 © MM ... GdI1 - 2.3: Modularisierung 14 Suche nach Paket- und Typnamen • Ein Paketname wird als relativer Pfadname aufgefasst • Die Betriebssystemvariable CLASSPATH definiert die Verzeichnisse, ab denen ein Paketname gesucht wird • Einträge in einer CLASSPATH-Spezifikation können Verzeichnisse, ZIP- oder JAR-Dateien sein, die Klassen enthalten Trennt einzelne Verzeichnisse • Beispiel UNIX-Betriebssystem: CLASSPATH=.:/home/joe/classes:/usr/local/classes.zip • Beispiel Windows-Betriebssystem set CLASSPATH=.;C:\joe\classes;D:\local\classes.zip 2003 © MM ... GdI1 - 2.3: Modularisierung 15 Suche nach Paket- und Typnamen • Die Verzeichnisse aus CLASSPATH sind die Ausgangspunkte für den relativen Pfadnamen, der über den Paketnamen festgelegt ist • Die Verzeichnisse aus CLASSPATH werden in der angegebenen Reihenfolge durchsucht (von links nach rechts) • Prinzipiell können mehrere Verzeichnisse existieren, die über einen Paketnamen gefunden werden können – Keine gute Idee, da es dann von der in CLASSPATH definierten Reihenfolge abhängt, welche Pakete (und damit Typdefinitionen) tatsächlich verwendet werden 2003 © MM ... GdI1 - 2.3: Modularisierung 16 Suche nach Paket- und Typnamen • Eigene Pakete – Der Compiler löst den hierarchischen Namen in eine Kette von Unterverzeichnissen auf – Am Ende der Kette liegt die Quelldatei – Neben der Quelldatei wird auch die Klassendatei in diesem Unterverzeichnis abgelegt 2003 © MM ... GdI1 - 2.3: Modularisierung 17 Suche nach Paket- und Typnamen • Der Java-Compiler übersetzt eingebundene Quelldateien, die noch nicht übersetzt sind, automatisch mit, z.B.: package mypackage; import mypackage.subpackage.SomeClass; class MainClass { private SomeClass xy; public static void main(String[] args) { ... } } – Wird javac mypackage\MainClass.java aufgerufen, wird automatisch auch mypackage\subpackage\SomeClass.java compiliert 2003 © MM ... GdI1 - 2.3: Modularisierung 18 Kapselung Kapselung und Geheimnisprinzip (information hiding) • Objekte kommunizieren miteinander über wohldefinierte Schnittstellen • Jedes Objekt stellt den anderen Objekten nur die nötige Menge an Operationen zur Verfügung • Verdeckt hinter dieser Schnittstelle: – die interne Struktur und die aktuellen Werte der Attribute sowie die Implementierung der Operationen Was geht Dich meine Post an? 2003 © MM ... GdI1 - 2.3: Modularisierung 19 Kapselung • Mehr Abstraktion, einfacher von den Klienten zu benutzen – nicht geheim halten, sondern von unnötigen Details befreien! • Verhindert unerlaubte Zugriffe von kritischen Daten • Anpassbarkeit – Zugriff nur über öffentliche Methoden (Schnittstelle) – Realisierung der Schnittstelle ist austauschbar, ohne Änderungen in anderen getesteten und bewährten Klassen nachzuziehen 2003 © MM ... GdI1 - 2.3: Modularisierung 20 Kapselung Eine Analogie • Bankautomaten haben eine Bedienungsschnittstelle • Das Betätigen einer Funktionstaste z.B. „Auszahlung“ - entspricht dem Aufruf einer Methode des Bankautomat-Objekts • Frau Schmidt ist der Sender und der Automat der Empfänger • Die Eingabe des Betrags entspricht der Parametereingabe 2003 © MM ... GdI1 - 2.3: Modularisierung 21 Kapselung • Frau Schmidt sieht nur die Bedienungsschnittstelle • Sie hat keine Information darüber, wie der Automat intern aufgebaut ist • Für sie ist es unmöglich, den Geldbehälter des Automaten anzuschauen, ob genügend 50 EuroScheine darin enthalten sind, und ihren Betrag selbst herauszuholen. 2003 © MM ... GdI1 - 2.3: Modularisierung 22 Kapselung • leichter zu verwenden – Frau Schmidt möchte die Details der internen Realisierung gar nicht wissen! • verhindert unerlaubte Angriffe – Nicht jeder sollte auf den Geldbehälter des Automaten zugreifen können! • schützt Klienten vor Veränderungen in der Realisierung des Objektes – Die Bank kann einen neuen Automaten aufstellen – Solange die Bedienungsschnittstelle dieselbe bleibt, können Kunden die neue Implementierung ohne weiteres benutzen 2003 © MM ... GdI1 - 2.3: Modularisierung 23 Geheimnisprinzip class Auto { // Schnittstelle public Auto(String farbe, int geschwindigkeit, int tankinhalt) { this.tankinhalt = tankinhalt; this.farbe = farbe; this.geschwindigkeit = geschwindigkeit; . . . } // end constructor . . . // Implementierung (Modell) private int tankinhalt, geschwindigkeit; private String farbe; . . . } //2003end class Auto © MM ... GdI1 - 2.3: Modularisierung Schnittstelle 24 Geheimnisprinzip class Auto { // Schnittstelle public Auto(String farbe, int geschwindigkeit, int tankinhalt) { this.tankinhalt = tankinhalt rfarbe = rot(f); = f; g = gruen(f); ... this.geschwindigkeit = geschwindigkeit; . . . } // end constructor . . . // Implementierung (Modell) private int tankinhalt, geschwindigkeit; private int String private r, g, farbe; b; . . . } //2003end class Auto © MM ... GdI1 - 2.3: Modularisierung 25 Geheimnisprinzip class Auto { // Schnittstelle public Auto(String farbe, int geschwindigkeit, int tankinhalt) { Änderung der this.tankinhalt = tankinhalt Implementierungsrfarbe = rot(f); = f; g = gruen(f); ... entscheidung nach außen this.geschwindigkeit = geschwindigkeit; nicht sichtbar . . . Alle Klienten können } // end constructor . . . unverändert weiter // Implementierung (Modell) verwendet werden private int tankinhalt, geschwindigkeit; private int String farbe; private r, g, b; . . . } //2003end class Auto © MM ... GdI1 - 2.3: Modularisierung 26 Geheimnisprinzip Möglichkeiten zur Realisierung des Geheimnisprinzips • Vertrauen: andere wissen, dass Geheimnisprinzip eine gute Idee ist – sie sollten nur über Methoden auf Daten eines Objekts zugreifen – Aber: wenn das jemand nicht weiß? – Versehentliche Zugriffe? à Dokumentieren, welche Elemente wichtig sind – Bösartige Zugriffe auf das Modell? (Grund für viele Sicherheitslücken von Programmen) à Programmiersprache muss Geheimnisprinzip unterstützen 2003 © MM ... GdI1 - 2.3: Modularisierung 27 Geheimnisprinzip • Java bietet integrierte Sichtbarkeitsmodifikatoren – Definieren Zugriffsrechte auf Elemente – Die Programmiersprache erlaubt Zugriff auf Elemente nur für Klassen, die auch dürfen • In EBNF als Visibility geschrieben (siehe Teil 1.4, 2.1) – Sowohl Methoden, Konstruktoren und Attribute als auch Klassen können eine definierte Sichtbarkeit haben – Modifikatoren für Methoden, Konstruktoren und Attribute (Wiederholung): "public" | "protected" | "private" (oder kein Modifikator) – Modifikatoren für Klassen (Wiederholung): "public" (oder kein Modifikator) 2003 © MM ... GdI1 - 2.3: Modularisierung 28 Zugriffsrechte und Sichtbarkeit • implizit (Ohne Angabe eines Modifikators) – Das Element ist nur innerhalb des Pakets sichtbar, in dem die Klasse definiert ist – Das gilt für Subklassen und Nicht-Subklassen – Von außerhalb des Pakets ist kein Zugriff möglich 2003 © MM ... GdI1 - 2.3: Modularisierung 29 Zugriffsrechte und Sichtbarkeit • private: Nur Objekte der selben Klasse dürfen auf das Element zugreifen à weder andere Klassen, noch Erben class A { private void op1() { ... } public void op2(A anAObject) { ... anAObject.op1(); ... // OK } } 2003 © MM ... GdI1 - 2.3: Modularisierung 30 Zugriffsrechte und Sichtbarkeit • protected: Alle Klassen im gleichen Paket dürfen auf das Element zugreifen, sowie alle Klassen, die davon erben (egal in welchem Paket definiert) • public: Zugriff von überall erlaubt 2003 © MM ... GdI1 - 2.3: Modularisierung 31 Zugriffsrechte und Sichtbarkeit private implizit protected public Eigene Klasse 2003 © MM ... Erben im gleichen Paket Im Paket GdI1 - 2.3: Modularisierung Erbe in anderem Paket Im anderen Paket 32 Zugriffsrechte und Sichtbarkeit package packageA; A; public publicclass classAA AA{{ public publicint intone; one; int inttwo; two; private privatevoid voidthree() three(){{… …}} protected protectedvoid voidfour() four(){{… …}} }} package packageA; A; class classAB AB {{ ////one, one,two, two,four four }} 2003 © MM ... package packageA; A; class classAC ACextends extendsAA AA {{ ////one, one,two, two,four four }} package packageB; B; class classBA BAextends extends AA AA{{ ////one, one,four four }} package packageB; B; class classBB BB{{ ////one one }} GdI1 - 2.3: Modularisierung 33 Zugriffsrechte und Sichtbarkeit • UML-Darstellung von Sichtbarkeit – – – – – UML bietet die Sichtbarkeiten public, protected und private public-Elemente werden durch ein + gekennzeichnet protected-Elemente werden durch # gekennzeichnet private-Elemente werden durch – gekennzeichnet Keine Kennzeichnung der Sichtbarkeit = Sichtbarkeit undefiniert Klassenname -privateAttribute : Klasse1 #protectedAttribute : int +publicMethode(x: int) : boolean 2003 © MM ... GdI1 - 2.3: Modularisierung 34 Zugriffsrechte und Sichtbarkeit Zugriffskategorien beim Überschreiben • Beim Überschreiben einer Methode wird die geerbte Zugriffskategorie zunächst beibehalten • Zugriffsrechte dürfen erweitert werden (z.B. public anstelle von protected) • Zugriffsrechte nicht eingeschränkt werden • Grund für diese Regel: Ersetzbarkeit – Daher muss die Subklasse nach außen hin mindestens alles das zur Verfügung stellen, was auch ihr Vorfahr zur Verfügung stellt – Beim Überschreiben darf der Zugriff daher nicht weiter eingeschränkt werden 2003 © MM ... GdI1 - 2.3: Modularisierung 35 Zugriffsrechte und Sichtbarkeit Zugriffskategorien beim Überschreiben • private-Elemente, die in Unterklassen neu definiert werden, dürfen eine beliebige Kategorie besitzen – Grund: private-Elemente sind außerhalb der definierenden Klasse nicht sichtbar – Eine Subklasse sieht die Elemente nicht à es ist, als ob es diese Elemente gar nicht gäbe 2003 © MM ... GdI1 - 2.3: Modularisierung 36 Zugriffsrechte und Sichtbarkeit Zugriffskategorien beim Überschreiben • Methoden mit impliziter Zugriffskategorie können so bleiben oder als protected oder public überschrieben werden • protected darf als public überschrieben werden • public-Methoden müssen public bleiben 2003 © MM ... GdI1 - 2.3: Modularisierung 37 Die Bedeutung der Zugriffsrechte • Information Hiding (Parnas) – Jedes Objekt enthält die Details seiner Realisierung – Nach außen soll so wenig wie möglich von den Details der Realisierung sichtbar sein • Vererbung bricht Kapselung – Ein Erbe übernimmt die Implementierung seiner Vorfahren – Führt eine Abhängigkeit zwischen Ahnen und Erben ein • Regel: es ist sinnvoll, so viele Attribute und Methoden wie möglich mit dem Sichtbarkeitsmodifikator private zu deklarieren 2003 © MM ... GdI1 - 2.3: Modularisierung 38 Mehrfachvererbung • Bisher: Vererbung = Objektmodellierung mittels hierarchischer Taxionomie Lebewesen • Was passiert, wenn mehrere verschiedene Taxionomien verwendet werden sollen? … Pflanzen Spielgefährte Haustier Säugetiere Hunde Katzen Haushund • Lösung: Mit Mehrfachvererbung (Vielfachvererbung, Multiple Inheritance) kann eine Subklasse die Funktionalität mehrerer Basisklassen erben 2003 © MM ... GdI1 - 2.3: Modularisierung 39 Mehrfachvererbung • Bei Mehrfachvererbung erben die Subklassen die Eigenschaften und Methoden aller Basisklassen Angesteller Studierender personalNr : String matrikelNr : String geburtsdatum : Date fachbereich : int gehalt() : int lerne() alter() : int HiWi • Ein HiWi ist sowohl Angesteller als auch Studierender – – – – Erbt die Eigenschaften personalNr und geburtsdatum von Angestellter Erbt die Eigenschaften matrikelNr und fachbereich von Studierender Erbt die Methoden gehalt() und alter() von Angestellter Erbt die Methode lerne() von Studierender • Ersetzbarkeit: Objekte der Klasse HiWi kann überall verwendet werden, wo Objekte der Klasse Angesteller oder der Klasse Studierender verwendet werden kann 2003 © MM ... GdI1 - 2.3: Modularisierung 40 Mehrfachvererbung Probleme bei Mehrfachvererbung • Elemente mit gleichem Namen können in mehreren Basisklassen vorkommen – Beispiel: Angestellter und Studierender sollen je um ein Attribut Name erweitert werden Angesteller Studierender personalNr : String matrikelNr : String geburtsdatum : Date fachbereich : int name : String name : String gehalt() : int lerne() alter() : int HiWi • Welche Bedeutung hat HiWi.name ??? 2003 © MM ... GdI1 - 2.3: Modularisierung 41 Mehrfachvererbung Probleme bei Mehrfachvererbung • Sprachen mit Mehrfachvererbung bieten verschiedene Strategien 1. Mehrfache Kopie und explizite Basisklasse (z.B. C++) – – – Die Subklasse erbt alle Elemente Die Elemente mit Konflikten werden über den Namen der Basisklasse unterschieden Beispiel: HiWi h = new HiWi(); h.Angestellter::name = "Name"; h.Studierender::name = "anderer Name"; – à Attribute mit gleichem Namen können verschiedene Werte haben 2003 © MM ... GdI1 - 2.3: Modularisierung 42 Mehrfachvererbung Probleme bei Mehrfachvererbung 2. Mehrfache Kopie und explizites Umbenennen (z.B. Eiffel) – – – Die Subklasse erbt alle Elemente Bei Konflikten muss der Programmierer den problematischen Elementen neue Namen geben Beispiel (Java-ähnlich): class HiWi extends Angestellter, Studierender { rename Angestellter.name -> aName; rename Studierender.name -> sName; } – – à Attribute erhalten neue Namen, können weiterhin unterschiedliche Werte enthalten Vorteil gegenüber 1 – Vererbungshierarchie ist nicht nach außen sichtbar: kann geändert werden – Information Hiding! 2003 © MM ... GdI1 - 2.3: Modularisierung 43 Mehrfachvererbung Probleme bei Mehrfachvererbung • 3. Einfache Kopie (z.B. C++) – – – Basisklassen haben ihrerseits eine gemeinsame Basisklasse à Namen der Basisklasse werden mehrfach vererbt - Konflikt Die Elemente mit Konflikten werden vereinigt, es gibt nur ein Element Person Beispiel: name : String • HiWi erbt name sowohl von Angesteller als auch Angesteller von Studierender personalNr : String • Grund: beide erben geburtsdatum : Date von Person gehalt() : int à HiWi.name wird auf alter() : int Person.name abgebildet, ist eindeutig – Elegant, funktioniert aber nur bei derartigen Gabelungen 2003 © MM ... GdI1 - 2.3: Modularisierung Studierender matrikelNr : String fachbereich : int lerne() HiWi 44 Interfaces èMehrfachvererbung bringt Probleme, wenn ein Element mehrfach benannt vorkommen kann – Besonders konfliktträchtig: Attribute kommen mehrfach vor • Java unterstützt keine Mehrfachvererbung von Klassen mit Attributen • Allerdings: mit Interfaces (Schnittstellen) kann man ähnliche Effekte erzielen 2003 © MM ... GdI1 - 2.3: Modularisierung 45 Interfaces • Was sind Interfaces? – definieren Dienstleistungen für andere Klassen, ohne die Implementierung der Dienstleistungen festzulegen • stellen funktionale Abstraktionen bereit, d.h.: • legen das „Was“ fest, aber nicht das „Wie“ • nur das „Äußere“ einer Klasse, das ein Nutzer (Client) wissen muss, nicht das „Innere“, das für Clients gemäß OOP ohnehin „versteckt“ wird – verhalten sich wie Klassen, die nur abstrakte Methoden enthalten UML Notation – Interfaces können von anderen <<interface>> Interfaces erben • Zwischen Interfaces ist mehrfache Vererbung möglich 2003 © MM ... GdI1 - 2.3: Modularisierung AnInterface aMethod() 46 Interfaces EBNF Interface-Definition = ["public "] "interface " Interface-Name [Interface-Extension] "{" Interface-Body "}". Extension = "extends " Base-Interface {"," Base-Interface }. Interface-Body = { ["public "] Method-Header ";" }. 2003 © MM ... GdI1 - 2.3: Modularisierung 47 Interfaces • Interfaces enthalten nur eine Schnittstellenbeschreibung • Namenskonflikt zwischen Methoden von Interfaces à implementierte Methode gilt alle deklarierenden Interfaces Beispiel public interface AInterface { public void methodA(); public void methodX(); } public interface BInterface { public void methodB(); public void methodX(); } 2003 © MM ... GdI1 - 2.3: Modularisierung 48 Interfaces Beispiel (fortgesetzt) public interface ABInterface extends AInterface, BInterface { // enthält Methoden: // void methodA() von AInterface // void methodB() von BInterface // void methodX() von AInterface und BInterface } 2003 © MM ... GdI1 - 2.3: Modularisierung 49 Interfaces Implementierung von Interfaces • Interfaces werden von Java-Klassen implementiert • Wenn eine Klasse eine Schnittstelle implementiert, dann muss sie alle Methoden der Schnittstelle implementieren – Ansonsten ist Klasse abstrakt, Unterklassen müssen fehlende Methoden implementieren • Auch leere Implementierungen sind erlaubt, z.B. durch „{}“ 2003 © MM ... GdI1 - 2.3: Modularisierung 50 Interfaces Implementierung von Interfaces - Notation • Java: Interfaces werden nach dem „implements“ Schlüsselwort in der Klassendefinition angegeben • UML: Durch <<interface>> gestrichelte Linie des AnInterface Vererbungspfeils AnInterface wird implementiert von Klasse 1 Klasse1 2003 © MM ... GdI1 - 2.3: Modularisierung AnInterface wird implementiert von Klasse 2 Klasse2 51 Interfaces Verwendung von Interfaces • Verschiedene Java-Klassen können das selbe Interface auf unterschiedliche Weise implementieren • Die Klienten-Klassen sprechen nur die entsprechenden Klassen nur über das Interface an • Die implementierenden Klassen können nach Belieben verändert werden – Die Schnittstelle des Interface bleibt unverändert à keine Auswirkung auf Klienten-Klasse 2003 © MM ... GdI1 - 2.3: Modularisierung 52 Interfaces Verwendung von Interfaces • Ein Interface kann wie eine abstrakte Klasse verwendet werden à Variablen mit einem Interface als Typ sind möglich • Verfügbare Methoden: alle im Interface deklarierten Methoden • Prüfung, ob ein Objekt ein Interface implementiert: mit dem instanceof-Operator – anObject instanceof AnInterface ó anObject gehört zu einer Klasse, die AnInterface implementiert 2003 © MM ... GdI1 - 2.3: Modularisierung 53 Interfaces Beispiel • Das Interface Comparable stellt eine Methode zur Verfügung, um zwei Objekte zu vergleichen • compareTo nimmt einen Parameter vom Typ Object und gibt zurück – -1 oder kleiner wenn das implementierende Objekt kleiner als der Parameter ist – 0 wenn das implementierende Objekt gleich zum Parameter ist – +1 oder größer wenn das implementierende Objekt größer als der Parameter ist 2003 © MM ... GdI1 - 2.3: Modularisierung 54 Interfaces Beispiel Definition des Interfaces Comparable aus dem Java-Quelltext /* This interface imposes a total ordering on * the objects * of each class that implements * it. */ package java.lang; public interface Comparable { /* Compares this object with the specified * object for order. Returns a negative integer, * zero, or a positive integer as this object * is less than, equal to, or greater than the * specified object. */ int compareTo(Object o); } 2003 © MM ... GdI1 - 2.3: Modularisierung 55 Interfaces Beispiel • Verwendung von Comparable in einer allgemeinen Methode, die Elemente in eine Liste sortiert einfügt • Beispiel verwendet Klasse java.util.List – Enthält mehrere beliebige Objekte – Objekte werden über Index angegeben – Index beginnt bei 0 2003 © MM ... GdI1 - 2.3: Modularisierung 56 Interfaces Beispiel • java.util.List bietet Methoden – int size() // gibt die Anzahl der Elemente in der Liste zurück – Object get(int index); // liefert Objekt mit dem Index, der dem Parameter entspricht – Beispiel: get(1) liefert Objekt B Objekt A Objekt B Objekt C Index 0 Index 1 – void add(int index, Object element); // fügt element am angegebenen Index ein // alle nachfolgenden Elemente werden nach hinten geschoben 2003 © MM ... GdI1 - 2.3: Modularisierung 57 Interfaces Beispiel import java.util.List; /** * Neue Klasse SortedList, die sortiert einfuegt */ public class SortedList { private List elements = new List(); // leere Liste /** * Fuegt ein neues Element an die passende Position hinzu * @param newElement das hinzuzufuegende Element, * darf nicht null sein */ public void add(Comparable newElement) { if (newElement == null) return; // tue nichts, wenn newElement null ist int index = 0; boolean stored = false; // true, sobald newElement gespeichert ist 2003 © MM ... GdI1 - 2.3: Modularisierung 58 Interfaces Beispiel while (index < elements.size() && !stored) { Comparable testelement = (Comparable)elements.get(index); // Cast noetig, da get nur ein Object liefert // wir wissen: alle Elemente sind comparable // (es werden keine anderen hineingesteckt) // das Element am Index ist groesser als das // neue Element => Element auf diesen Index speichern if (testelement.compareTo(newElement) > 0) { elements.add(index, newElement); stored = true; } index++; } 2003 © MM ... GdI1 - 2.3: Modularisierung 59 Interfaces Beispiel if (!stored) // nicht gespeichert <=> newElement ist // groesser als alle Eintraege von elements // => speichern am Ende elements.add(elements.size(), newElement); } // end add /** * Gibt das Objekt am passenden Index zurueck */ public Object get(int index) { return elements.get(index); } } 2003 © MM ... GdI1 - 2.3: Modularisierung 60 Interfaces Beispiel public class Employee implements Comparable { String lastName; String firstName; /** Employees werden nach Namen geordnet */ public int compareTo(Object obj) { if (obj instanceof Employee) { Employee empl = (Employee)obj; int c = lastName.compareTo(empl.lastName); // Strings enthalten bereits compareTo // Wenn Nachnamen gleich, entscheidet der Vorname if (c == 0) return firstName.compareTo(empl.firstName); else return c; } else return -1 ; } ... } 2003 © MM ... GdI1 - 2.3: Modularisierung 61 Interfaces Beispiel public class Point extends GraphicObject implements Comparable { double x, y ; /** Points werden nach Abstand vom Ursprung geordnet */ public int compareTo(Object obj) { if (obj instanceof Point) { Point p = (Point)obj; double dist = x*x + y*y; double pDist = p.x*p.x + p.y*p.y; if (dist == pDist) return 0; else return dist < pDist ? -1 : 1; } else return -1 ; } ... } 2003 © MM ... GdI1 - 2.3: Modularisierung 62 Interfaces Beispiel • SortedList kann sowohl Objekte vom Typ Point als auch Objekte vom Typ Employee sortiert speichern • Änderungen am Quelltext der Klasse sind nicht notwendig • Point kann weiterhin ohne Probleme von GraphicObject erben 2003 © MM ... GdI1 - 2.3: Modularisierung 63