Informatik 2 - Einführung
Informatik 2 - Einführung
Informatik 2 - Einführung
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>Informatik</strong> 2<br />
Einführung in Java und UML<br />
Prof. Dr.-Ing. Holger Vogelsang<br />
holger.vogelsang@hs-karlsruhe.de
Inhaltsverzeichnis<br />
• Roter Faden (4)<br />
• Übersicht (6)<br />
• Übersicht: (8)<br />
• Übersicht (9)<br />
• Arbeitsschritte und Software (14)<br />
• Imperative Aspekte (35)<br />
• Klassen und Objekte (46)<br />
• Fehlererkennung (91)<br />
• Zusicherungen (98)<br />
• Klassen und Objekte (111)<br />
• Überladen von Methoden (121)<br />
• Vererbung (126)<br />
• Überschreiben von Methoden (156)<br />
• Vererbung (183)<br />
• Generische Klassen (189)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 2
Inhaltsverzeichnis<br />
• Generische Methoden (197)<br />
• Aufzähltypen (202)<br />
• Regeln und Hinweise (208)<br />
• Klassendiagramme (220)<br />
• Fehlerbehandlung mit Ausnahmen (275)<br />
• Pakete (291)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 3
Roter Faden<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 4
Roter Faden<br />
Übersicht Layouts Ereignisse Widgets<br />
Grafische<br />
Oberflächen<br />
Zeichenoperationen<br />
Grafikwidgets<br />
Effekte,<br />
Animationen<br />
Offene<br />
Punkte<br />
ADTs<br />
Datenstrukturen<br />
in Java<br />
Elementare<br />
Datenstrukturen<br />
Iteratoren<br />
Datenstrukturen<br />
Hashtabellen<br />
Bäume<br />
Graphen<br />
Typinfo.,<br />
I/O<br />
Annotationen<br />
Laufzeittypinfo.<br />
Ein-,<br />
Ausgabe<br />
Entwurf<br />
Prinzipien<br />
Verbindung<br />
von Modulen<br />
Spring<br />
OSGi<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 5
Übersicht<br />
Literatur<br />
Java<br />
• Christian Ullenboom:<br />
<br />
<br />
„Java ist auch eine Insel“, Galileo Computing (auch frei als „Open-Book“ unter<br />
http://openbook.galileocomputing.de/javainsel/)<br />
„Java 7 – Mehr als eine Insel“, Galileo Computing<br />
• D. Ratz, J. Scheffler, D. Seese, J. Wiesenberger: „Grundkurs Programmieren in Java“, Hanser-<br />
Verlag<br />
• R. C. Martin: „Clean Code“, mitp<br />
Objektorientierung allgemein<br />
• B. Lahres, G. Raýman: „Objektorientierte Programmierung“, Galileo Computing (auch frei als<br />
„Open-Book“ unter http://openbook.galileocomputing.de/oop/)<br />
Konfigurationsmanagement und Build-Systeme<br />
• G. Popp: „Konfigurationsmanagement mit Subversion, Maven und Redmine“, dpunkt<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 6
Übersicht<br />
Literatur<br />
UML (Objekt- und Klassendiagramme)<br />
• M. Jeckle, C. Rupp, J. Hahn, B. Zengler, S. Queins: „UML 2 - glasklar“, Hanser-Verlag<br />
• C. Kecher: „UML 2.0 – Das umfassende Handbuch“, Galileo Computing<br />
JavaFX 2<br />
• C. Dea: „JavaFX 2.0: Introduction by Example“, Apress<br />
• J. L. Weaver: „Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology“, Apress<br />
• http://docs.oracle.com/javafx/index.html<br />
Datenstrukturen<br />
• G. Saake, K. Sattler: „Datenstrukturen und Algorithmen: Eine Einführung mit Java“, dpunkt<br />
Spring<br />
• C. Walls: „Spring im Einsatz (3. Auflage)“, Hanser-Verlag (deutsch) oder „Spring in Action<br />
(Third Edition)“, Manning (englisch)<br />
OSGi<br />
• B. Weber, P. Baumgartner, O. Braun: „OSGi für Praktiker“, Hanser-Verlag<br />
• G. Wütherich, N. Hartmann, B. Kolb, M. Lübken: „Die OSGI Service Platform“, dpunkt<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 7
Übersicht:<br />
Änderungen zum Sommersemester 2013<br />
• veränderte Reihenfolge<br />
• kleinere Anpassungen<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 8
Übersicht<br />
Hinweise<br />
Markierungen<br />
• Expertenkapitel (nicht klausurrelevant):<br />
• Tafel-/ Rechnerübungen: Längeres Beispiel:<br />
• Pacman-Beispiel:<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 9
Übersicht<br />
Historie im <strong>Informatik</strong>studium<br />
• Bekannt sind aus „<strong>Informatik</strong> 1“:<br />
<br />
<br />
<br />
<br />
<br />
Datentypen<br />
Prozedurale Elemente<br />
einfache Klassen<br />
Arrays<br />
Algorithmen zum Suchen und Sortieren<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 10
Übersicht<br />
Entwicklungsumgebungen<br />
• Java-Entwicklung<br />
<br />
<br />
<br />
Eclipse: http://www.eclipse.org mit zusätzlichen Plugins:<br />
• Findbugs: In Eclipse Help Eclipse Marketplace, „Findbugs“ im Suchfeld<br />
eingeben und „Findbugs Eclipse Plugin” installieren<br />
• Checkstyle zur Überprüfung der Code-Konventionen: In Eclipse Help Eclipse<br />
Marketplace, „Checkstyle“ im Suchfeld eingeben und „Checkstyle Plug-in”<br />
installieren<br />
• SVN Team Provider: In Eclipse Help Eclipse Marketplace, „SVN“ im Suchfeld<br />
eingeben und „Subversive SVN Team Provider” installieren<br />
• SVN Connector: In Eclipse Help Install New Software Add… „SVN-<br />
Connector“ mit der URL „SVN-Connector” Update Site -<br />
http://community.polarion.com/projects/subversive/download/eclipse/3.0/kep<br />
ler-site/ eingeben OK Im Baum links „SVNKit 1.7.10 Implementation”<br />
sowie “SVN Connectors” auswählen und installieren.<br />
Netbeans: http://www.netbeans.org<br />
IntelliJIDEA (freie Community-Version): http://www.jetbrains.com/idea/<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 11
Übersicht<br />
Entwicklungsumgebungen, Durchgängiges Beispiel: Pacman-Klon<br />
• UML:<br />
<br />
<br />
Visual Paradigm, siehe im Ilias unter<br />
https://ilias.hs-karlsruhe.de/repository.php?ref_id=32415&cmd=&rep_frame=1<br />
UML Lab, siehe im Ilias unter<br />
https://ilias.hs-karlsruhe.de/repository.php?ref_id=32415&cmd=&rep_frame=1<br />
• Java und die Datenstrukturen werden anhand eines kleinen Spielfragmentes erläutert, einer<br />
Variation von Pacman:<br />
nur einen Level<br />
verändertes Spielfeld<br />
andere Punktezählung<br />
veränderter interner Aufbau, um alle wichtigen Techniken zeigen zu können<br />
fehlende Spielelemente des Originals<br />
teilweises anderes Verhalten der Figuren<br />
Vektor- statt Pixelgrafik<br />
plattformunabhängige Implementierung mit JavaFX<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 12
Übersicht<br />
Durchgängiges Beispiel: Pacman-Klon<br />
• Spielfeld:<br />
Kirsche (Geister werden für eine gewisse<br />
Zeit ungefährlich und können gefressen<br />
werden)<br />
Tor zur anderen Seite<br />
Geist<br />
Essen<br />
Pacman<br />
• Spielende: Pacman wurde von einem Geist gefressen, oder alle Essensrationen sind von<br />
Pacman gefressen worden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 13
Arbeitsschritte und Software<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 14
Arbeitsschritte und Software<br />
Motivation<br />
• Bekannt aus <strong>Informatik</strong> 1: Schreiben einfacher Java-Programme<br />
• Wie kann der Quelltext verwaltet werden?<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 15
Arbeitsschritte und Software<br />
Ausführbares Programm<br />
Erzeugen eines ausführbaren Programmes<br />
Quellcode<br />
Pacman.java<br />
Quellcode<br />
Cherry.java<br />
Compiler<br />
Compiler<br />
Bytecode<br />
Pacman.class<br />
Bytecode<br />
Cherry.class<br />
jar<br />
Archiv<br />
(Pacman.jar)<br />
Quellcode<br />
Ghost.java<br />
Compiler<br />
Bytecode<br />
Ghost.class<br />
Bilder/…<br />
Manifest.mf<br />
Manifest-Version: 1.0<br />
Main-Class: de.Main<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 16
Arbeitsschritte und Software<br />
Versionsverwaltung<br />
• Warum sollen die Quelltexte nicht nur im Dateisystem des Entwicklers liegen?<br />
<br />
<br />
Gruppenarbeit:<br />
- Viele Entwickler arbeiten an einem Programm Zugriff auf deren Quelltexte.<br />
- Was haben die anderen Entwickler gemacht oder geändert?<br />
- Was habe ich an dem aktuellen Projekt geschrieben?<br />
Verbesserung der eigenen Arbeitsmöglichkeiten:<br />
- Automatisierte Sicherung: Was passiert bei Zerstörung der lokalen Daten?<br />
- Wiederherstellung eines alten Standes, wenn der neue „kaputtprogrammiert“<br />
wurde „Undo“ zu einer bekannten Version<br />
Wieso sollen mehrere Versionen eines Programmes gepflegt werden?<br />
- Anpassungen für Kunden<br />
- Arbeit an alter Version (Korrekturen) und neuer Version (Erweiterungen)<br />
- Vergleich unterschiedlicher Versionen was hat sich geändert?<br />
Jede neue Version einer Datei erhält eine Versionsnummer.<br />
• Ziel: Speicherung in einem zentralen „Repository“.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 17
Arbeitsschritte und Software<br />
Versionsverwaltung<br />
• Einflüsse während der Programmentwicklung:<br />
viele Entwickler<br />
viele Klassen und<br />
Dokumente<br />
Projekt<br />
viele Versionen<br />
viele unterschiedliche<br />
Arbeitsplätze<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 18
Arbeitsschritte und Software<br />
Versionsverwaltung<br />
• Grafischer Versionsvergleich:<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 19
Arbeitsschritte und Software<br />
Versionsverwaltung<br />
• Lösung: Unterstützung der Entwicklung durch eine Versionsverwaltung. Auswahl:<br />
<br />
<br />
<br />
<br />
RCS/CVS: veraltet<br />
SVN: sehr häufig im Einsatz, ein zentraler Server<br />
Git: manchmal als Nachfolger von SVN gesehen, verteilte Datenhaltung auf mehreren<br />
Servern, oft in Open-Source-Projekten, in Firmen noch selten anzutreffen<br />
Team Foundation Server: reine Microsoft-Lösung<br />
• In <strong>Informatik</strong> 2 und im Softwarelabor: Arbeit mit Subversion (SVN)<br />
• Genauere Einführung z.B. unter http://svnbook.red-bean.com/<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 20
Arbeitsschritte und Software<br />
Versionsverwaltung<br />
• Interne Speicherung im Repository:<br />
<br />
<br />
<br />
Es wird normalerweise nicht jede Version komplett abgelegt.<br />
Statt dessen speichert ein Repository die Unterschiede („Deltas“).<br />
Subversion kennt beide Varianten + komplette Speicherung nach Bedarf.<br />
Version 1 Version 1<br />
Version 2<br />
Version 3<br />
Version 4<br />
Version 5<br />
(aktuell)<br />
als vollständige<br />
Datei<br />
Deltas<br />
(alt)<br />
als vollständige<br />
Datei<br />
Version 2<br />
Version 3<br />
Version 4<br />
Version 5<br />
Rückwärtsdelta:<br />
schnelleres Auslesen<br />
Vorwärtsdelta:<br />
schnelleres Schreiben<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 21
Arbeitsschritte und Software<br />
Versionsverwaltung<br />
• Wichtigste Aktionen für die Arbeit mit Subversion:<br />
<br />
<br />
<br />
<br />
Share: einmalig Projekt im Repository anlegen, eventuell lokales Projekt übergeben<br />
Check out (einmalig für ein Projekt): Projekt aus dem Repository in ein lokales<br />
Verzeichnis kopieren<br />
Commit: lokal erzeugte Änderungen im Repository ablegen<br />
Update: zwischenzeitliche Änderungen im Repository in das lokale Verzeichnis<br />
übernehmen<br />
• Für alle Schritte gibt es Kommandozeilenwerkzeuge sollen hier nicht betrachtet werden.<br />
• Die wichtigsten lassen sich auch mit IDE-Plugins durchführen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 22
Arbeitsschritte und Software<br />
Versionsverwaltung (Installation in Eclipse)<br />
Installation in Eclipse<br />
Unter Help<br />
• Install new Software<br />
• im Baum Collaboration den Subversive<br />
SVN Team Provider auswählen<br />
• Im Menü Window Preferences den<br />
Eintrag Team und dann SVN auswählen.<br />
• Jetzt wird ein SVN-Connector nachinstalliert.<br />
Die Version mit der höchsten Nummer und<br />
reiner Java-Implementierung erfüllt den<br />
Zweck.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 – Versionsverwaltung mit SVN 23
Arbeitsschritte und Software<br />
Versionsverwaltung (Installation in Eclipse)<br />
• Jetzt kann mit Window Open Perspective SVN Repository Exploring die<br />
Ansicht aller SVN-Server angezeigt werden (ist leer).<br />
• Im rechten Fenster SVN Repositories lässt sich durch Rechtsklick mit New <br />
Repository Location ein neuer Server einrichten.<br />
• Für den an der Hochschule müssen Sie folgendes eintragen:<br />
<br />
<br />
<br />
<br />
URL: http://www.iwi.hs-karlsruhe.de/I/svn//<br />
: Ihr IZ-Benutzername<br />
Als Nutzernamen und Password geben Sie Ihren IZ-Account ein.<br />
Save authentication ist auf eigenen Rechnern ganz praktisch, damit Sie sich nicht<br />
immer neu anmelden müssen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 – Versionsverwaltung mit SVN 24
Arbeitsschritte und Software<br />
Versionsverwaltung (Projekt anlegen)<br />
Projekt anlegen<br />
• Wenn das Projekt bisher nur lokal existiert, muss es im Repository angelegt werden.<br />
• Dann können alle anderen Entwickler mit der entsprechenden Berechtigung darauf<br />
zugreifen.<br />
share<br />
ProjektXYZ<br />
Projekt auf dem<br />
lokalen Arbeitsplatz-PC<br />
ProjektXYZ<br />
Repository auf dem<br />
Server mit dem neuen Projekt<br />
http://www.iwi.hs-karlsruhe.de/I/svn//ProjektXYZ/trunk<br />
Repository Root<br />
Projekt-Pfad<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 25
Arbeitsschritte und Software<br />
Versionsverwaltung (Projekt anlegen)<br />
• Ablauf in Eclipse:<br />
<br />
<br />
<br />
<br />
Rechtsklick auf das Projekt<br />
Dann Team und Share Project auswählen.<br />
SVN und im nächsten Dialog Ort des Repositorys auswählen, Simple Mode ist für uns<br />
ausreichend<br />
Kommentar eingeben und auf Finish klicken<br />
• Empfohlener Aufbau eines Projektarchivs (Repository) auf dem Server:<br />
<br />
<br />
<br />
/Projektname/trunk: Hauptentwicklungslinie des Projektes<br />
/Projektname/branches: Alternative Entwicklungen wie z.B. spezielle Anpassungen<br />
für einen Kunden, Wechsel auf neue Technologie, …<br />
/Projektname/tags: Kopie der Hauptentwicklungslinie oder einer Verzweigung zu<br />
einem bestimmten Zeitpunkt.<br />
- Wird z.B. angelegt, wenn eine neue Version an den Kunden ausgeliefert wird. Dann<br />
kann ein Tag mit dem Namen der Version erzeugt wird („Version 1.0“).<br />
- Ein Tag hat keine bestimmte Bedeutung. Er erlaubt aber, bestimmte Versionen mit<br />
einem leicht erkennbaren Namen zu versehen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 26
Arbeitsschritte und Software<br />
Versionsverwaltung (Check out)<br />
Checkout: Daten aus dem Repository auf den lokalen PC kopieren (einmalig)<br />
Check out<br />
Entwickler<br />
lokale Kopie<br />
des Quelltextes<br />
Repository auf dem<br />
Server mit allen Versionen<br />
des Quelltextes +<br />
zusätzlichen Binärdateien<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 27
Arbeitsschritte und Software<br />
Versionsverwaltung (Check out)<br />
• Ablauf in Eclipse:<br />
<br />
<br />
<br />
<br />
Wechsel in die Ansicht SVN Repository Exploring<br />
Rechtsklick auf die gewünschte Version des Projektes<br />
Check Out wählen<br />
Arbeit auf der lokalen Kopie des Projektes<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 28
Arbeitsschritte und Software<br />
Versionsverwaltung (Commit)<br />
Commit: Lokale Änderungen in das Repository übertragen<br />
Änderungen<br />
eintragen,<br />
Konflikte lösen<br />
Entwickler<br />
lokale Kopie<br />
des Quelltextes<br />
Repository auf dem<br />
Server mit allen Versionen<br />
des Quelltextes +<br />
zusätzlichen Binärdateien<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 29
Arbeitsschritte und Software<br />
Versionsverwaltung (Commit)<br />
• Ablauf in Eclipse:<br />
<br />
<br />
<br />
<br />
<br />
<br />
Nach den lokalen Änderungen übertragen die Entwickler die neuen Daten in das<br />
Repository.<br />
Rechtsklick auf das Projekt (z.B. in der Java-Ansicht) oder Rechtsklick auf einzelne<br />
Pakete/Klassen<br />
Dann Team und Commit auswählen.<br />
Die Änderungen sollten unbedingt mit einem Kommentar versehen werden. Der<br />
Kommentar beschreibt, was an der Datei geändert wurde („Fehler xyz behoben“, …).<br />
Nur geänderte Daten werden geschrieben. Sie erhalten dabei eine neue<br />
Versionsnummer (siehe SVN Repository Explorer).<br />
Was passiert, wenn ein anderer Entwickler die Datei bereits verändert hat? Es ist eine<br />
Konfliktbehandlung erforderlich.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 30
Arbeitsschritte und Software<br />
Versionsverwaltung (Commit)<br />
• Konfliktbehandlung:<br />
1. Kopieren-Ändern-Zusammenführen-Modell<br />
- Auschecken einer Version aus dem Projektarchiv: Eine Kopie der Daten wird auf den<br />
Client kopiert.<br />
- Arbeit auf den Client-Dateien<br />
- Einchecken der Änderungen auf den Server: Die Änderungen werden dort<br />
gespeichert, Konflikte müssen behoben werden. Konflikte?<br />
• Was passiert, wenn ein anderer Entwickler dieselbe Datei verändert hat?<br />
• Möglichkeiten:<br />
– Änderungen zusammenführen<br />
– eigene Datei überschreibt die auf dem Server<br />
– eigene Änderungen werden verworfen<br />
– …<br />
• Der SVN-Client hilft beim Zusammenführen beider Versionen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 31
Arbeitsschritte und Software<br />
Versionsverwaltung (Commit)<br />
2. Sperren-Ändern-Entsperren-Modell<br />
- Zur Konfliktvermeidung lassen sich Dateien auf dem Server gegen Änderung<br />
sperren nicht sehr gerne gesehen (insbesondere wenn Sie in den Urlaub fahren<br />
und die Sperre vergessen).<br />
- Bei Binärdateien, die nicht sinnvoll zusammengeführt werden können, ist das<br />
Modell aber durchaus sinnvoll.<br />
- Häufig kann ein Administrator Sperren wieder entfernen.<br />
- Verwendung:<br />
• Rechtsklick auf eine Datei oder ein Verzeichnis, Team und Lock… auswählen.<br />
• Danach die Dateien bearbeiten.<br />
• Abschließend nach einem Commit mit Team und Unlock… wieder freigeben.<br />
• In der Praxis hat sich gezeigt, dass das Kopieren-Ändern-Zusammenführen-Modell wenig<br />
Probleme bereitet: Nicht jeder Entwickler arbeitet gleichzeitig an allen Projektteilen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 32
Arbeitsschritte und Software<br />
Versionsverwaltung (Update)<br />
Update: Zwischenzeitliche Änderungen aus dem Repository übernehmen<br />
Update<br />
Entwickler<br />
lokale Kopie<br />
des Quelltextes<br />
Repository auf dem<br />
Server mit allen Versionen<br />
des Quelltextes +<br />
zusätzlichen Binärdateien<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 33
Arbeitsschritte und Software<br />
Versionsverwaltung (Update)<br />
• Während der Arbeit oder nach einer Pause haben andere Entwickler eventuell neue<br />
Versionen im Repository abgelegt.<br />
• Vor einer Änderungen in der eigenen lokalen Kopie sollte sie aktualisiert werden, damit nicht<br />
ein alter Stand verändert wird.<br />
• Ablauf in Eclipse:<br />
Rechtsklick auf ein Paket, eine Klasse, eine Ressource oder das Projekt, dann Team und<br />
Synchronize with Repository auswählen.<br />
Eine weitere Ansicht zeigt die Änderungen, die übernommen werden können.<br />
• Weitere Funktionen: siehe weiterführende Literatur (insbes. „Merge“ verschiedene<br />
Entwicklungszweige und Kollisionsbehandlung beim „Commit“)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 34
Imperative Aspekte<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 35
Imperative Aspekte<br />
Motivation<br />
• Wie sollte der Quelltext formatiert sein?<br />
• Zusammenhang zwischen primitiven Datentypen und Klassen<br />
• Wie kann die falsche Verwendung von Funktionen und Algorithmen zur Laufzeit<br />
erkannt werden?<br />
• Als bekannt vorausgesetzt: Schleifen, Abfragen, lokale Variable<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 36
Imperative Aspekte<br />
Formatierung des Quelltextes<br />
Hinweise zur Formatierung<br />
• Der Compiler ignoriert jegliche Formatierung des Quelltextes.<br />
• Ein Programmierer benötigt dringend eine gut lesbare Struktur!<br />
• Beispiel:<br />
public V(){for(int i=0;i
Imperative Aspekte<br />
Einige Regeln zur Formatierung des Quelltextes<br />
Einige ganz einfache Regeln<br />
• Anfangs- und Endklammern eines Blocks immer in dieselbe Spalte setzen oder die<br />
Endklammer an das Ende der Zeile davor.<br />
• Den Inhalt eines Blockes immer entweder um einen Tabulator oder eine gleiche Anzahl von<br />
Leerzeichen einrücken.<br />
• Beispiel:<br />
for (int i = 0; i < 10; i++) {<br />
Blockinhalt<br />
}<br />
• Selbsterklärende Variablen- und Methodennamen verwenden.<br />
• Großzügig Leerzeilen zwischen verschiedene Blöcke einfügen, um logisch getrennte Einheiten<br />
optisch anzuzeigen.<br />
• Großzügig Leerzeichen zur Formatierung einfügen.<br />
• Reihenfolgen der Operatoren durch Klammerungen optisch hervorheben.<br />
• Sinnvolle Kommentare verwenden (nicht einfach: Hier wird x erhöht.)<br />
• Siehe auch: http://www.ioccc.org/ (The International Obfuscated C Code Contest)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 38
Imperative Aspekte<br />
Konstanten: String und Zeichen<br />
String- und Zeichenkonstanten im Unicode-Format<br />
• Zeichenkonstanten: char, z.B.: 'A', numerischer Wert = 65<br />
• Stringkonstanten: Folge von char, z.B.: "ABD".<br />
Beispiele<br />
Zeichen Bedeutung Num. Wert<br />
A Großbuchstabe A 65<br />
Leerzeichen 32<br />
0 Ziffer 0 48<br />
\xdd dd = Num. Wert eines Zeichens im Hexadezimalsystem \xdd<br />
\ddd Eine Folge von 1, 2 oder 3 oktalen Ziffern \ddd<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 39
Imperative Aspekte<br />
Konstanten: String und Zeichen<br />
Vordefinierte Sonderzeichen<br />
Zeichen Bedeutung Num. Wert<br />
\\ Das Zeichen \ selbst (ein Backslash). 92<br />
\" Das Zeichen " 34<br />
\' Das Zeichen ' 39<br />
\b Rückwärts Löschen, Backspace, BS 8<br />
\f Seitenvorschub, form-feed, FF 12<br />
\n Zeilenvorschub, new line oder line feed, LF 10<br />
\r Wagenrücklauf, carriage return, CR 13<br />
\t Horizontaler Tabulator, HT 9<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 40
Imperative Aspekte<br />
Konstanten: String und Zeichen (Pacman-Beispiel)<br />
• Beschreibung des Spielfeldes im Quelltext durch eine Zeichenkette<br />
• Die Zeichenkette wird später eingelesen, um die einzelnen Objekte zu erzeugen.<br />
String[] fieldLayout = {<br />
".....*.........*.....",<br />
"o***.*.*******.*.***o",<br />
"..........C..........",<br />
"**.*.****.*.****.*.**",<br />
" *.*.*....*.*....*.* ",<br />
"**.*.****.*.****.*.**",<br />
"E .*......*......*. E",<br />
"**.*** ******* ***.**",<br />
" *. 0 .* ",<br />
" *.*** ###-### ***.* ",<br />
" *.* #2 1 3# *.* ",<br />
"**.* * ###-### * *.**",<br />
"E . * C * . E",<br />
"**.****** * ******.**",<br />
".*..... * .....*.",<br />
".*.***.*******.***.*.",<br />
"..........P..........",<br />
// usw.<br />
};<br />
C<br />
Zeichen<br />
Bedeutung des Feldes<br />
enthält eine Kirsche (Cherry)<br />
* kann nicht betreten werden<br />
0 - 3 Nummer des Geistes<br />
E<br />
mit Ausgang (Exit) auf die andere Seite<br />
# ist Gefängnisumrandung (entspricht hier<br />
'*')<br />
o<br />
mit Energiepaket (nicht verwendet)<br />
P mit Pacman<br />
Ohne Angabe: leeres Feld<br />
. mit Essensportion<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 41
Imperative Aspekte<br />
Konstanten: String und Zeichen (Pacman-Beispiel)<br />
String[] fieldLayout = {<br />
".....*.........*.....",<br />
"o***.*.*******.*.***o",<br />
"..........C..........",<br />
"**.*.****.*.****.*.**",<br />
" *.*.*....*.*....*.* ",<br />
"**.*.****.*.****.*.**",<br />
"E .*......*......*. E",<br />
"**.*** ******* ***.**",<br />
" *. 0 .* ",<br />
" *.*** ###-### ***.* ",<br />
" *.* #2 1 3# *.* ",<br />
"**.* * ###-### * *.**",<br />
"E . * C * . E",<br />
"**.****** * ******.**",<br />
".*..... * .....*.",<br />
".*.***.*******.***.*.",<br />
"..........P..........",<br />
".***.****.*.****.***.",<br />
// usw.<br />
};<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 42
Imperative Aspekte<br />
Parameterübergabe per Wert bei primitiven Datentypen<br />
Parameterübergabe per Wert (Call by Value)<br />
• Werte primitiver Datentypen werden immer per Wert übergeben. Es wird eine lokale Kopie<br />
erzeugt. Änderungen am Wert innerhalb einer Methode wirken nicht nach außen.<br />
Beispiel:<br />
public void doSomething(int xx){<br />
xx = 2;<br />
}<br />
public int doSomethingElse(){<br />
int x = 21;<br />
doSomething(x);<br />
System.out.println(x);<br />
return 0;<br />
}<br />
Ausgabe: 21<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 43
Imperative Aspekte<br />
Parameterübergabe per Referenz bei Objekten<br />
Parameterübergabe per Referenz (Call by Reference)<br />
• Objekte werden immer per Referenzen übergeben werden. Damit sind Änderungen nach<br />
außen sichtbar. Beispiel:<br />
public void doSomething(Bruch br){<br />
br.setZaehler(42);<br />
}<br />
public int doSomethingElse(){<br />
Bruch br = new Bruch(21, 3);<br />
doSomething(br);<br />
System.out.println(br.getZaehler());<br />
return 0;<br />
}<br />
Ausgabe: 42<br />
• Zusatznutzen einer Referenzübergabe: Das Anlegen einer Kopie kann zeitaufwändig sein.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 44
Imperative Aspekte<br />
Ergebnisrückgabe<br />
• Es gilt dasselbe wie bei Übergaben:<br />
<br />
<br />
Werte primitiver Datentypen werden als Kopie und<br />
Objekte per Referenz zurückgegeben.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 45
Klassen und Objekte<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Typinformationen<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassendiagramme<br />
Ein-,<br />
Ausgabe<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Annotationen<br />
Überladen<br />
Laufzeittypinfo.<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 46
Klassen und Objekte<br />
Objekte<br />
Einige Objekte im Pacman-Spiel<br />
• Pacman<br />
• die Geister 1 bis 4<br />
• einzelne Kirschen<br />
• das Spielfeld<br />
Einige Eigenschaften von Objekten (Zustandsinformationen)<br />
• Pacman: bewegt sich nach oben, öffnet den Mund<br />
• Geist 1: ist gefährlich, befindet sich auf Zelle (2,3), bewegt sich nach unten und hat eine<br />
gewisse „Intelligenz“<br />
• Geist 2: ist gefährlich, befindet sich auf Zelle (12,5), bewegt sich nach links und hat ebenso<br />
eine gewisse „Intelligenz“<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 47
Klassen und Objekte<br />
Objekte<br />
Objekte kommunizieren (Verhalten)<br />
• Das Spielfeld sagt zu Pacman: „Bewege Dich nach oben“<br />
Quellobjekt (Spielfeld) schickt dem Ziel (Pacman) eine Nachricht.<br />
Objekte unterscheiden sich (Identität)<br />
• Geist 1 ist nicht Geist 2.<br />
• Alle Objekte sind eindeutig unterscheidbar!<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 48
Klassen und Objekte<br />
Objekte<br />
Definition: Objekt<br />
Ein Objekt ist eine konkret vorhandene Einheit mit folgenden Merkmalen:<br />
<br />
<br />
<br />
<br />
Identität: Alle Objekte lassen sich eindeutig unterscheiden (z.B. durch die Referenz).<br />
Zustand (Daten):<br />
- Alle Attributwerte des Objektes. Der Typ der Attribute wird durch die Klasse<br />
festgelegt.<br />
- Der Zustand ist nur durch das Objekt selbst veränder- und sichtbar, nicht aber von<br />
außen.<br />
- Beziehungen zu anderen Objekten.<br />
Eigenschaften (Properties):<br />
- Sie können von außen abgefragt werden.<br />
- Sie werden unter Umständen aus Daten berechnet, sind aber selbst keine Daten<br />
(z.B. Alter = Datum - Geburtsdatum).<br />
Verhalten: Festgelegt durch Methoden der Klasse des Objektes.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 49
Klassen und Objekte<br />
Objekte<br />
Vereinfachte Darstellung von Objekten in UML:<br />
geist1: Geist<br />
x = 2<br />
y = 3<br />
IQ = 70<br />
direction = DOWN<br />
/nextX<br />
Name des Objektes<br />
und Name der Klasse<br />
Zustand (Daten)<br />
Eigenschaften (Properties)<br />
{if (direction == DOWN)<br />
nextX = max(x-1, 0)}<br />
Einschränkungen<br />
(Constraints)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 50
Klassen und Objekte<br />
Klassen<br />
Objekte haben Gemeinsamkeiten<br />
• Alle Geister haben Daten x, y und direction mit entsprechenden Werten und eine<br />
berechnete neue X-Position direction hat bei jedem Geist denselben Typ.<br />
Zusammenfassung von Objekten gleicher Eigenschaften zu Klassen<br />
• Geist 1 und 2 gehören zur Klasse Ghost:<br />
<br />
<br />
gleiche Attribut- und Eigenschaftstypen<br />
gleiches Verhalten<br />
Definition: Klasse (im Implementierungsmodell)<br />
Eine Klasse ist die Definition der Attribut-, Eigenschaftstypen und Operationen einer Menge<br />
von Objekten.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 51
Klassen und Objekte<br />
Klassen<br />
Definition: Attribut (auch Instanzvariable genannt)<br />
• Ein Attribut ist eine Eigenschaft eines Objektes, die von außen abgefragt werden kann.<br />
• Es kann ein Datenelement oder ein berechneter Wert (=abgeleitetes Attribut) sein.<br />
• Ein Attribut kommt in allen Objekten der Klasse vor.<br />
• Der Wert des Attributs kann in den Objekten unterschiedlich ausfallen.<br />
• Ein Attribut kann nicht ohne das zugehörige Objekt leben.<br />
• Ein Attribut hat keine Identität.<br />
In der Vorlesung wird der Begriff „Attribut“ immer für ein Datenelement verwendet.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 52
Klassen und Objekte<br />
Klassen<br />
Definition: Operation<br />
• Eine Operation legt fest, welche Funktionalität ein Objekt bereitstellt.<br />
• Unterstützt ein Objekt eine bestimmte Operation, so sichert es einem Aufrufer zu, dass es bei<br />
einem Aufruf die Operation ausführen wird.<br />
• Durch die Operation wird die Syntax des Aufrufs vorgegeben (Typen der Parameterwerte).<br />
• Die Operation gibt Zusicherungen darüber, welche Resultate die Operation haben wird.<br />
• Die Operation beinhaltet keine Implementierung. Sie beschreibt „lediglich“ Schnittstelle<br />
(Signatur) und Zusicherung nach außen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 53
Klassen und Objekte<br />
Klassen<br />
Definition: Methode<br />
• Eine Methode ist die konkrete Implementierung einer Operation.<br />
• Während Operationen die Funktionalität nur abstrakt definieren, sind Methoden für die<br />
Realisierung dieser Funktionalität zuständig.<br />
• In der Vorlesung wird die strenge Kategorisierung von Methode und Operation nicht immer<br />
aufrechterhalten.<br />
• Hier wird häufig „Methode“ als Synonym für beide Begriffe verwendet.<br />
• „Operation“ wird dort verwendet, wo es speziell auf den reinen Signaturcharakter ankommt.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 54
Klassen und Objekte<br />
Klassen und Objekte (Pacman-Beispiel)<br />
Beispiel zu Klasse und Objekt (unvollständiges Beispiel)<br />
Klassenname<br />
Attribute<br />
Operationen<br />
Ghost<br />
-x: int<br />
-y: int<br />
-direction: Direction<br />
+setX(x: int)<br />
+setY(y: int)<br />
+paint(p: JPanel,<br />
cellWidth: int,<br />
cellHeight: int)<br />
geist1: Ghost<br />
x = 2<br />
y = 3<br />
direction = UP<br />
Attributwerte<br />
geist2: Ghost<br />
x = 12<br />
y = 3<br />
direction = DOWN<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 55
Klassen und Objekte<br />
Objektorientierte Sichtweise<br />
Idee der Kapselung (Information hiding)<br />
• Die Implementierung der Datenstrukturen und Algorithmen innerhalb einer Klasse wird<br />
gegenüber den Aufrufern „versteckt“. Sie kann nach außen unsichtbar verändert werden.<br />
Methoden<br />
Attribute<br />
Aufruf<br />
Objekt<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 56
Klassen und Objekte<br />
Objektorientierte Sichtweise (Pacman-Beispiel)<br />
Beispiel: Kapselung des Geistes in einer Klasse<br />
paint<br />
x<br />
setX<br />
direction<br />
Ghost<br />
y<br />
setY<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 57
Klassen und Objekte<br />
Objektorientierte Sichtweise<br />
• Vorteile der Kapselung:<br />
<br />
<br />
Interne Zustände und deren Abhängigkeiten bleiben nach außen verborgen Leichtere<br />
Konsistenzhaltung der Daten.<br />
Bei Zustandsänderung müssen häufig noch andere Operationen ausgeführt werden.<br />
Beispiel:<br />
- Im Pacman-Spiel wird die Farbe einer Figur geändert. Die Farbe ist ein Attribut der<br />
Figur.<br />
- Danach muss die Figur neu gezeichnet werden.<br />
- Bei sauberer Kapselung wird durch die Farbänderung automatisch das Neuzeichnen<br />
ausgelöst.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 58
Klassen und Objekte<br />
Objektorientierte Sichtweise<br />
• Funktioniert die Kapselung immer? Beispiel:<br />
<br />
<br />
<br />
Im Pacman-Spiel werden einzelne Figuren auf dem Spielfeld platziert.<br />
Die Figuren haben Attribute wie „Farbe“, „Bewegungsrichtung“ und „Position“.<br />
Der aktuelle Spielstand soll auf Festplatte gespeichert werden Zugriff auf die Attribute<br />
zum Speichern notwendig.<br />
• Konsequenz:<br />
<br />
<br />
<br />
<br />
<br />
Jede Figur müsste selbst speichern Verteilung der Speicherfunktionalität auf viele<br />
Klassen sehr unschön.<br />
Eine Klasse speichert, muss aber auf die privaten Attribute der Figuren zugreifen <br />
Aushebelung der Kapselung?<br />
Nein: Kapselung ist immer auf einen Aufgabenbereich beschränkt.<br />
Speicherung ist eine andere Aufgabe, darf also auf die privaten Daten zugreifen.<br />
Das gilt aber nicht für Klassen, die für das Zeichnen verwendet werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 59
Klassen und Objekte<br />
Zugriffsrechte<br />
Zugriffsrechte<br />
• private: Auf private Attribute oder Methoden dürfen nur Methoden der eigenen Klasse<br />
zugreifen.<br />
• public: Auf öffentliche Attribute und Methoden dürfen alle Methoden anderer Klassen<br />
zugreifen.<br />
• protected: für Vererbung (kommt später ...)<br />
• : Paketrecht (kommt später …)<br />
• Die Rechte gelten auf Klassenebene: Ein Objekt einer Klasse darf auf private Attribute eines<br />
anderen Objektes derselben Klasse zugreifen!<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 60
Klassen und Objekte<br />
Klassen in UML<br />
Vereinfachte Darstellung von Klassen in UML:<br />
- x: int<br />
- y: int<br />
- count: int<br />
Ghost<br />
Klassenname<br />
Attribute<br />
statisches Attribut<br />
+ paint(p: JPanel, x: int, y: int)<br />
+ setX(x: int)<br />
+ setY(y: int)<br />
Operationen<br />
Attribut (Angaben in eckigen Klammern sind optional):<br />
[Sichtbarkeit][/]Name[:Typ][Multiplizität][=Vorgabewert] [{Eigenschaft}]<br />
• Sichtbarkeit/Zugriffsrecht:<br />
<br />
<br />
<br />
<br />
#: geschützt (protected)<br />
-: privat (private)<br />
+: öffentlich (public)<br />
~: Paket (package)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 61
Klassen und Objekte<br />
Klassen in UML<br />
• /: Das Attribut ist eine Eigenschaft. Es wird berechnet und muss somit nicht gespeichert<br />
werden.<br />
• Name: Name des Attributs. Aufgrund von Einschränkungen vieler Programmiersprachen sollte<br />
man auf Umlaute usw. verzichten.<br />
• :Typ: Typ des Attributs<br />
• Multiplizität: Anzahl Ausprägungen des Attributs<br />
kann als Array betrachtet werden<br />
Angaben sind minimale und maximale Anzahl oder die genaue Anzahl:<br />
- [2]: exakt zwei Werte<br />
- [1..2]: ein oder zwei Werte<br />
- [1..*]: mindestens ein Wert bis beliebig viele Werte<br />
- [0..*] bzw. [*]: beliebig viele Werte<br />
• =Vorgabewert: Initialwert für das Attribut<br />
muss zum Typ des Attributs passen<br />
bei Multiplizität größer als 1: Aufzählung in der Form {1, 2, 3, 4}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 62
Klassen und Objekte<br />
Klassen in UML<br />
• {Eigenschaft}: besondere Merkmale des Attributs (Auswahl)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
{readOnly}: Der Wert darf nach der Initialisierung nicht mehr verändert werden (eine<br />
Konstante).<br />
{subsets }: Der Wert ist eine Untermenge der Werte, die in dem<br />
Attribut erlaubt sind.<br />
{union}: Vereinigung aller Attributwerte, die mit subsets spezifiziert wurden.<br />
{redefines }: Redefiniert ein Attribut seiner Basisklasse<br />
{ordered}: Die Attributwerte müssen geordnet vorliegen. Duplikate sind nicht erlaubt.<br />
{bag}: Die Attributwerte müssen nicht geordnet vorliegen. Duplikate sind erlaubt.<br />
{seq} bzw. {sequence}: Die Attributwerte müssen geordnet vorliegen. Duplikate sind<br />
erlaubt.<br />
{unique}: Die Attributwerte müssen nicht geordnet vorliegen. Duplikate sind nicht<br />
erlaubt.<br />
{composite}: Das Attribut wird durch Komposition an die Klasse gebunden. Es ist so<br />
selbst für die Zerstörung seines Inhalts verantwortlich.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 63
Klassen und Objekte<br />
Klassen in UML<br />
Operation (Angaben in eckigen Klammern sind optional):<br />
[Sichtbarkeit]Name([Parameterliste])[:Rückgabetyp] [{Eigenschaft}]<br />
• Sichtbarkeit/Zugriffsrecht: wie bei Attributen<br />
• Name: wie bei Attributen<br />
• Parameterliste mit dem folgenden Aufbau:<br />
[Übergabemodus] Name :Typ [Multiplizität][=Vorgabewert][{Eigenschaft}]<br />
<br />
Übergabemodus (unvollständig):<br />
- in: Der Parameter wird von der Operation nur gelesen. Fehlt der Modus, so wird in<br />
angenommen. In Java nur für primitive Datentypen möglich.<br />
- out: Der Parameter wird von der Operation nur geschrieben.<br />
Umsetzungsmöglichkeit in Java nur für Objekte (Besonderheit String <br />
StringBuffer, …)<br />
- inout: Der Parameter wird von der Operation gelesen und geschrieben.<br />
Umsetzungsmöglichkeit in Java nur für Objekte.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 64
Klassen und Objekte<br />
Klassen in UML<br />
<br />
<br />
Name: Name des Parameters<br />
:Typ: Typ des Parameters<br />
Multiplizität: Anzahl Ausprägungen des Parameters, die übergeben werden. Die<br />
Angaben erfolgen wie bei Attributen. Umsetzungsmöglichkeit in Java: Arrays<br />
=Vorgabewert: Wert, den der Parameter erhält, wenn er nicht übergeben wird.<br />
Umsetzung in Java nicht direkt möglich.<br />
{Eigenschaft}: siehe Attribute<br />
• :Rückgabetyp: Typ des Rückgabewertes, fehlt dieser, so wird void angenommen. Die<br />
Angabe void ist nicht erlaubt.<br />
• {Eigenschaft}: Angabe spezieller Merkmale des Rückgabetyps, siehe Attribute.<br />
• Und was ist mit Ausnahmen (Exceptions)? UML kennt sie nicht. Ausweg in Form eines<br />
Eigenschaftswertes (Tagged Value):<br />
{raisedException=NameDerAusnahme}<br />
Andere, eigene Eigenschaftswerte sind auch erlaubt sinnvoll bei MDA.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 65
Klassen und Objekte<br />
Klassen in UML (Pacman-Beispiel)<br />
• Klasse für eine Zelle des Spielfeldes (unvollständig):<br />
- border: int<br />
- food: boolean<br />
- exit: boolean<br />
Cell<br />
+ paint(panel: JPanel, x: int, y: int)<br />
+ isFood(): boolean<br />
+ isExit(): boolean<br />
+ getBorder(): int<br />
• Weitere Klassen kommen erst später, weil sie Vererbung bzw. Beziehungen zwischen Klassen<br />
benötigen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 66
Klassen und Objekte<br />
Klassen allgemein<br />
Typen von Klassen<br />
• Statisches Typsystem (C++, C#, Java, …):<br />
<br />
<br />
Der Typ von Variablen und Parametern wird im Quelltext festgelegt.<br />
Vorteile:<br />
- bessere Optimierung durch den Compiler möglich<br />
- saubere Programmstruktur, da Typen direkt im Quelltext ersichtlich sind<br />
- gute Unterstützung durch IDEs, da diese die Variablentypen erkennen<br />
- frühzeitige Fehlererkennung durch den Compiler<br />
• Dynamisches Typsystem (z.B. JavaScript):<br />
<br />
<br />
<br />
Variablen können beliebige Daten aufnehmen.<br />
Der Variablentyp steht erst zur Laufzeit fest.<br />
Vorteile:<br />
- Werte können von beliebigem Typ sein automatische Konvertierung<br />
- Ducktyping: Wenn es watschelt wie eine Ente, wenn es schwimmt wie eine Ente,<br />
wenn es quakt wie eine Ente, dann behandeln wir es wie eine Ente.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 67
Klassen und Objekte<br />
Klassen allgemein<br />
Stark und schwach typisierte Programmiersprachen<br />
• Stark typisierte Sprache: Überwacht das Erstellen und den Zugriff auf alle Objekte so, dass<br />
sichergestellt ist, dass Referenzen/Zeiger immer auf Objekte verweisen, die auch die<br />
Spezifikation des Typs erfüllen, der für die Variable deklariert ist. Beispiel: Java<br />
• Schwach typisierte Sprachen: Zeiger können auf Objekte verweisen, ohne dass das Objekt<br />
notwendigerweise die Spezifikation des Typs der Variablen erfüllt. Beispiel: C++<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 68
Klassen und Objekte<br />
Klassensyntax in Java<br />
Syntax von Klassen in Java<br />
• Eine Klasse kapselt Attribute, Operationen und eventuell Operatoren als eine Einheit.<br />
• Beispiel zu Attributen und Methoden:<br />
public class Cell {<br />
private int border;<br />
private boolean food;<br />
private boolean exit;<br />
}<br />
public int getBorder() {<br />
return border;<br />
}<br />
• Hinweis: Statt „Methode“ wird häufig auch der Begriff „Funktion“ verwendet.<br />
• Statt „Attribut“ werden auch häufig „Instanzvariable“ oder „Variable“ verwendet.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 69
Klassen und Objekte<br />
Attributzugriffe<br />
• Alle Attributzugriffe sollten immer über Methoden mit gleichem Namen mit vorangestelltem<br />
get bzw. set erfolgen Kapselung!<br />
Beispiel:<br />
public class Cell {<br />
private int border;<br />
private boolean food;<br />
//...<br />
public int getBorder(){<br />
return border;<br />
}<br />
public boolean isFood(){<br />
return food;<br />
}<br />
public void setBorder(int nBorder){<br />
border = nBorder;<br />
}<br />
public void setFood(boolean nFood){<br />
food = nFood;<br />
}<br />
}<br />
falls der Lese- und<br />
Schreibzugriff erlaubt<br />
sein soll Namensvergabe<br />
nach Java-Konvention<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 70
Klassen und Objekte<br />
Beispiel (Vektor, Version 1)<br />
• Aus der Mathematik bekannt: Vektoren und Matrizen.<br />
• Klasse Vector, hier eingeschränkt auf Länge 3 mit double-Zahlen (noch unvollständig und<br />
gefährlich kommt später besser):<br />
package de.hska.iwii.i2;<br />
public class Vector {<br />
private double[] values =<br />
new double[ 3 ];<br />
}<br />
public void setValue(int index,<br />
double value) {<br />
values[ index ] = value;<br />
}<br />
public double getValue(int index) {<br />
return values[ index ];<br />
}<br />
Vector<br />
- values: double[3] {bag}<br />
+ setValue(index: int, double: value)<br />
+ getValue(index: int): double<br />
package de.hska.iwii.i2;<br />
public class VectorTest {<br />
public static void main(<br />
String[] args) {<br />
Vector v1 = new Vector();<br />
v1.setValue(0, 2.0);<br />
System.out.println(v1.getValue(0));<br />
}<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 71
Klassen und Objekte<br />
Konstruktoren<br />
Definition: Konstruktor<br />
Konstruktoren dienen der gezielten Initialisierung eines Objektes bei dessen Erzeugung.<br />
• Es kann mehr als einen Konstruktor in einer Klasse geben.<br />
Beispiel (Vector, Version 2):<br />
public class Vector {<br />
private double[] values;<br />
}<br />
public Vector(int size) {<br />
values = new double[ size ];<br />
}<br />
public void setValue(int index, double value) {<br />
values[ index ] = value;<br />
}<br />
public double getValue(int index) {<br />
return values[ index ];<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 72
Klassen und Objekte<br />
Konstruktoren<br />
• Ein Konstruktor darf auch einen anderen aufrufen:<br />
public class Vector {<br />
// ...<br />
public Vector(int size) {<br />
this(size, 0.0);<br />
}<br />
}<br />
public Vector(int size, double initValue) {<br />
values = new double[ size ];<br />
for (int i = 0; i < size; ++i) {<br />
values[ i ] = initValue;<br />
}<br />
}<br />
// ...<br />
• Ohne die Angabe eines Konstruktors wird immer automatisch der Defaultkonstruktor (ohne<br />
Parameter) erzeugt (sonst nicht).<br />
• Ein Konstruktor wird immer automatisch aufgerufen, wenn ein Objekt der Klasse erzeugt<br />
wird.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 73
Klassen und Objekte<br />
Beispielmethode zur Skalarproduktberechnung<br />
• Skalarprodukt (immer noch Version 2):<br />
public class Vector {<br />
// ...<br />
public double getScalarProduct(Vector second) {<br />
double result = 0.0;<br />
for (int i = 0; i < values.length; ++i) {<br />
result += values[ i ] * second.values[ i ];<br />
}<br />
}<br />
return result;<br />
}<br />
// ...<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 74
Klassen und Objekte<br />
Variable Anzahl Übergabeparameter<br />
• Probleme:<br />
Eine Methode oder ein Konstruktor wird mit einer beliebigen Anzahl Werte desselben<br />
Typs aufgerufen.<br />
Lösungen:<br />
- Alle Werte kommen in ein Array. Das Array wird übergeben.<br />
- Java unterstützt die Übergabe einer variablen Parameteranzahl.<br />
• Beispiel Konstruktor des Vektors mit variabler Anzahl double-Werte:<br />
public class Vector {<br />
private double[] values;<br />
}<br />
public Vector(double... initValues) {<br />
values = new double[initValues.length];<br />
for (int i = 0; i < initValues.length; ++i) {<br />
values[ i ] = initValues[ i ];<br />
}<br />
}<br />
// ...<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 75
Klassen und Objekte<br />
Variable Anzahl Übergabeparameter<br />
• Aufrufe:<br />
Vector v1 = new Vector(1.0, 2.0, 3.0, 4.0); // Länge 4<br />
Vector v2 = new Vector(1.0, 2.0); // Länge 2<br />
Vector v3 = new Vector(); // Länge 0<br />
• Intern werden die Parameter in einem Array abgelegt:<br />
• Die Anzahl der Parameter kann mit array.length ermitteln werden.<br />
• Die Parameter werden mit Array-Zugriffen ausgelesen.<br />
• Das funktioniert auch für Methoden.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 76
Klassen und Objekte<br />
Aufbau und Verwendung von Klassen<br />
• Klassen kapseln Daten und arbeiten selbst auf ihren eigenen Daten:<br />
“Don't ask for the information that you need to do something;<br />
rather, ask the object that has that information to do the job for you.”<br />
• Beispiel (so nicht):<br />
public class Article {<br />
private double price;<br />
}<br />
public double getPrice() {<br />
return price;<br />
}<br />
// usw.<br />
// Implementierung einer Preiserhöhung in einer anderen Klasse<br />
public void increasePrice(Article article, double percentage) {<br />
article.setPrice(article.getPrice() * (1 + percentage / 100.0));<br />
}<br />
Problem: Lesen, Manipulation und Schreiben von Article-Daten. Die Article-Operation<br />
gehört in die Klasse!<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 77
Klassen und Objekte<br />
Aufbau und Verwendung von Klassen<br />
• Beispiel (so ist es ok):<br />
public class Article {<br />
private double price;<br />
}<br />
public double getPrice() {<br />
return price;<br />
}<br />
// usw.<br />
// Implementierung einer Preiserhöhung<br />
public void increasePrice(double percentage) {<br />
price *= (1 + percentage / 100.0));<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 78
Klassen und Objekte<br />
Statische Attribute und Methoden<br />
• Bisher: Jedes Attribut einer Klasse existiert in jedem Objekt der Klasse.<br />
• Manchmal gewünscht: Auch „globale“ Attribute, die nur einmal für eine Klasse existieren <br />
Alle Objekte einer Klasse teilen sich dieses Attribut:<br />
static Typ Attribut-Name;<br />
• Zugriff auf statische Attribute:<br />
Statische Methoden:<br />
static Typ Methode(Parameter);<br />
Aufruf einer statischen Methode einer Klasse auch ohne ein konkretes Objekt.<br />
• Statische Attribute können als globale Attribute innerhalb einer Klasse betrachtet werden.<br />
• Beispiel kommt nachher im Rahmen der Einführung von Referenzen.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 79
Klassen und Objekte<br />
final-Parameter und final-Werte<br />
• final-Parameter und final-Werte können nicht verändert werden Konstante!<br />
Beispiel:<br />
public void add(final int arg) {<br />
}<br />
// ...<br />
• final Vector vector: Unveränderliche Referenz auf ein Vektor-Objekt, dessen Inhalt<br />
aber verändert werden kann.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 80
Klassen und Objekte<br />
Primitive Datentypen und Wrapper-Klassen<br />
Für die primitiven Datentypen existieren Wrapper-Klassen<br />
Typ Größe Wertebereich Wrapper<br />
boolean true, false Boolean<br />
char 16 Bit '\u0000'‚ bis '\uFFFF' Character<br />
byte 8 Bit -2 7 bis 2 7 -1 Byte<br />
short 16 Bit -2 15 bis 2 15 -1 Short<br />
int 32 Bit -2 31 bis 2 31 -1 Integer<br />
long 64 Bit -2 64 bis 2 64 – 1 Long<br />
float 32 Bit 2 -149 bis (2-2 -23 )·2 127 Float<br />
double 64 Bit 2 -1074 bis (2-2 -52 )·2 1023 Double<br />
void<br />
Void<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 81
Klassen und Objekte<br />
Primitive Datentypen und Wrapper-Klassen<br />
Eigenschaften der Wrapper<br />
• Sie kapseln einen Wert eines primitiven Datentyps (ein Integer-Objekt nimmt genau einen<br />
int-Wert auf).<br />
• Der gekapselte Wert ist unveränderlich.<br />
• Sie besitzen Methoden zur Konvertierung vom/in den Wrapper.<br />
Wozu dienen die Wrapper?<br />
• Manche Methoden und Klassen erwarten Objekte und keine primitiven Datentypen die<br />
Wrapper kapseln die Daten dazu.<br />
• Beispiel aus dem 1. Semester: Eine ArrayList mit int-Werten kann so verwendet werden:<br />
ArrayList daten = new ArrayList(); // primitive Datentypen sind<br />
// nicht möglich<br />
daten.add(500);<br />
// wird automatisch zu<br />
// daten.add(Integer.valueOf(500));<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 82
Klassen und Objekte<br />
Primitve Datentypen und Wrapper-Klassen<br />
Automatisches Einpacken mit Wrappern (autoboxing)<br />
• Automatisches „Einpacken“ (siehe vorheriges Beispiel)<br />
ArrayList daten = new ArrayList();<br />
daten.add(66); // autoboxing<br />
daten.add(42); // autoboxing<br />
daten.add(1); // autoboxing<br />
1<br />
daten<br />
add<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 83
Klassen und Objekte<br />
Primitive Datentypen und Wrapper-Klassen<br />
• Was passiert genau?<br />
<br />
<br />
Für die ganze Zahlen -128 bis 127 existieren vordefinierte Wrapper-Objekte, die<br />
verwendet werden.<br />
Für andere Zahlenbereiche sowie float und double werden jeweils neue Objekte<br />
erzeugt Probleme beim Vergleichen:<br />
Integer boxedKlein1 = 127;<br />
Integer boxedKlein2 = 127;<br />
System.out.println(boxedKlein1 == boxedKlein2);<br />
// true<br />
Integer boxedKlein1 = 128;<br />
Integer boxedKlein2 = 128;<br />
System.out.println(boxedKlein1 == boxedKlein2);<br />
// false<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 84
Klassen und Objekte<br />
Primitive Datentypen und Wrapper-Klassen<br />
Automatisches Auspacken mit Wrappern (unboxing)<br />
• Automatisches „Auspacken“<br />
ArrayList daten = new ArrayList();<br />
daten.add(66); // autoboxing<br />
daten.add(42); // autoboxing<br />
daten.add(1); // autoboxing<br />
int wert = daten.get(0); // unboxing<br />
66<br />
daten<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 85
Klassen und Objekte<br />
Primitive Datentypen und Wrapper-Klassen<br />
• Was passiert genau?<br />
<br />
<br />
Eine null-Referenz kann nicht umgewandelt werden und führt zu einer Exception:<br />
int zahl = (Integer) null;<br />
Es lauern Fallen bei der Umwandlung von Zahlen:<br />
Integer i1 = new Integer(42);<br />
Integer i2 = new Integer(42);<br />
System.out.println(i1 >= i2);<br />
System.out.println(i1
Klassen und Objekte<br />
Innere Klassen<br />
• Klassen lassen sich ineinander schachteln.<br />
• Java unterstützt drei unterschiedliche Arten innerer Klassen:<br />
<br />
<br />
<br />
nicht-statische innere Klassen<br />
statische innere Klassen<br />
anonyme innere Klassen<br />
• Einsatzgebiete:<br />
<br />
<br />
Die inneren Klassen werden hauptsächlich in der äußeren benötigt oder von dieser<br />
erzeugt.<br />
Beispiel (kommt später): Iteratoren<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 87
Klassen und Objekte<br />
Innere Klassen: Nicht-statische innere Klassen<br />
• Einsatz: Das Erzeugen eines Objektes der inneren Klasse erfolgt immer innerhalb der Grenzen<br />
der äußeren Klasse (z.B. in einer der Methoden oder im Konstruktor).<br />
• Beispiel:<br />
public class Outer {<br />
class Inner {<br />
private int attr1;<br />
public void method1(){}<br />
public void method2(){<br />
method1();<br />
Outer.this.method1();<br />
}<br />
}<br />
public void method1(){}<br />
}<br />
• Innere Klassen dürfen weder statische Methoden noch statische Attribute besitzen.<br />
• Outer darf auf alle Methoden und Attribute von Inner zugreifen.<br />
• Inner darf auf alle Methoden und Attribute von Outer zugreifen.<br />
• Innere und äußere Klasse sind somit fest miteinander verbunden.<br />
• Erzeugte Dateien: Outer.class, Outer$Inner.class<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 88
Klassen und Objekte<br />
Innere Klassen: Statische innere Klassen<br />
• Einsatz: Das Erzeugen eines Objektes der inneren Klasse kann außerhalb der Grenzen der<br />
äußeren Klasse erfolgen.<br />
• Beispiel:<br />
public class Outer {<br />
static class Inner {<br />
private int attr1;<br />
public void method1(){}<br />
public void method2(){<br />
method1();<br />
}<br />
}<br />
private int attr2;<br />
public void method1(){}<br />
}<br />
• Die innere Klasse ist nicht an die äußere gekoppelt und kann daher nicht auf Attribute und<br />
Methoden der äußeren Klasse zugreifen.<br />
• Erzeugte Dateien: Outer.class, Outer$Inner.class<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 89
Klassen und Objekte<br />
Innere Klassen: Anonyme innere Klassen<br />
• Einsatz: Mit dem Erzeugen einer Klasse wird auch gleichzeitig ein Objekt angelegt. Die Klasse<br />
wird nur einmalig benötigt.<br />
• Häufig im Zusammenhang mit dem Implementieren von Schnittstellen verwendet:<br />
• Beispiel:<br />
public class Outer {<br />
public void method() {<br />
Runnable runObject = new Runnable() {<br />
@Override<br />
public void run() {<br />
System.out.println("Huhu");<br />
}<br />
};<br />
runObject.run();<br />
}<br />
}<br />
• Runnable ist eine Schnittstelle kommt noch genauer<br />
• Die anonyme Klasse darf nur auf finale lokale Variablen der Methode zugreifen.<br />
• Die anonyme Klasse darf auf Attribute und Methoden der äußeren Klassen zugreifen.<br />
• Erzeugte Dateien: Outer.class, Outer$1.class<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 90
Fehlererkennung<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 91
Fehlererkennung<br />
Fehlerhafte Methodenaufrufe<br />
• Idee: Die eigenen Methoden und Klassen werden eventuell falsch oder mit falschen Daten<br />
aufrufen.<br />
• Auch wenn der eigene Algorithmus korrekt ist, darf er nicht durch falsche Werte<br />
durcheinander geraten.<br />
• Denn: Programme werden im Laufe der Zeit permanent verändert. Fehler können daher<br />
immer wieder einmal auftreten.<br />
• Konsequenz: Ein Profi sichert seine eigenen Klassen und Methoden gegen eine fehlerhafte<br />
Verwendung ab.<br />
• In Kombination mit einem sauberen Software-Entwurf und anschließenden Tests, stellt die<br />
defensive Programmierung einen wichtigen Schritt in Richtung stabiler Programme dar.<br />
• Der Anwender sollte Programmfehler nie zu Gesicht bekommen.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 92
Fehlererkennung<br />
Fehlerhafte Methodenaufrufe<br />
• 3 Strategien zur Parameterbehandlung:<br />
<br />
<br />
<br />
Müll rein – nichts raus<br />
Müll rein – Fehlernachricht raus<br />
Müll rein – Müll raus (nicht akzeptabel!)<br />
• Daher: Prüfen aller Eingabeparameter<br />
<br />
<br />
<br />
Numerische Werte innerhalb vorgegebener Toleranzen<br />
Maximale Länge von Strings<br />
Randbedingungen wie 0, "", null usw.<br />
• Festlegen und dokumentieren, wie fehlerhafte Parameter behandelt werden sollen:<br />
<br />
<br />
<br />
<br />
Rückgabe eines Fehlercodes (false, -1, ...). Besser: Ausnahmen<br />
Aufruf einer Fehlerbehandlungsroutine<br />
Eintrag in einer Protokolldatei erstellen<br />
Programm beenden<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 93
Fehlererkennung<br />
Fehlerhafte Methodenaufrufe<br />
• Kontrakt zwischen einer Klasse und den Nutzern einer Klasse:<br />
Beschreibt, welche Voraussetzungen (Vorbedingungen) ein Aufrufer der Operation<br />
schaffen muss, damit die Operation durchgeführt werden kann.<br />
Legt fest, welche Leistung (Nachbedingungen) die Operation erbringt, sofern die<br />
Vorbedingungen eingehalten sind.<br />
• Vorbedingungen (engl. Preconditions)<br />
Der Aufrufer der Operation ist verpflichtet, diese Bedingungen beim Aufruf der<br />
Operation herzustellen.<br />
Sind die Vorbedingungen nicht erfüllt, ist die Operation nicht verpflichtet, ihre<br />
spezifizierte Aufgabe zu erfüllen.<br />
Vorbedingungen sind damit der Kontraktbestandteil, den der Aufrufer einer Operation<br />
einzuhalten hat.<br />
Sind die Vorbedingungen eingehalten, ist der Aufgerufene wiederum verpflichtet, die<br />
Nachbedingungen herzustellen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 94
Fehlererkennung<br />
Fehlerhafte Methodenaufrufe<br />
• Nachbedingungen (engl. Postconditions)<br />
Eine Klasse, die eine Operation implementiert, sichert zu, dass die Nachbedingungen<br />
unmittelbar nach Aufruf der Operation gelten.<br />
Die Zusicherung gilt nur, wenn der Aufrufer die für die Operation definierten<br />
Vorbedingungen eingehalten hat.<br />
Zusätzlich können auch nach außen zugesicherte Bedingungen vereinbart sein, die<br />
immer gelten sollen, unabhängig vom Aufruf einer Operation.<br />
• Invarianten (engl. Invariants)<br />
Invarianten sind Eigenschaften und Beziehungen zwischen Attributen eines Objekts, die<br />
sich durch keine Operation ändern lassen.<br />
Invarianten, die für eine Klasse definiert werden, gelten für alle Objekte der Klasse.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 95
Fehlererkennung<br />
Fehlerhafte Methodenaufrufe<br />
• Deklaration von Bedingungen in UML<br />
<br />
<br />
Ziel: möglichst automatische Überprüfbarkeit im späteren Quelltext<br />
Einführung der Object Constraint Language (OCL)<br />
• Object Constraint Language (OCL)<br />
<br />
<br />
<br />
<br />
<br />
Die OCL wird verwendet, um zusätzliche Bedingungen darzustellen, die sich mit den<br />
sonstigen Beschreibungsmitteln der UML nicht oder nur umständlich ausdrücken lassen.<br />
OCL stellt dabei eine rein deklarative Beschreibungsmöglichkeit zur Verfügung, um<br />
sogenannte Constraints auszudrücken.<br />
Ein Constraint ist ein Ausdruck, der entweder wahr oder falsch ist.<br />
OCL eignet sich sehr gut, um Vorbedingungen, Nachbedingungen und Invarianten von<br />
Operationen auszudrücken.<br />
Hier: keine vollständige Einführung in OCL<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 96
Fehlererkennung<br />
Fehlerhafte Methodenaufrufe<br />
• Beispiel zu OCL:<br />
Account<br />
- number: int<br />
- balance: int<br />
+ payOff(amount: int)<br />
context<br />
Account::payOff<br />
pre: balance >= amount<br />
post: balance = balance - amount<br />
• Wozu Constraints? Im Quelltext sind sie doch sowieso nicht sichtbar. Falsch:<br />
<br />
<br />
Mit Assertions (Zusicherungen) lassen sich Vorbedingungen manuell überprüfen.<br />
Einhaltung der Vorbedingungen können mit http://sourceforge.net/projects/ocl4java/<br />
automatisch überwacht werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 97
Zusicherungen<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 98
Zusicherungen<br />
Fehlerhafte Methodenaufrufe<br />
• Idee: Jede Funktion oder Methode schützt sich selbst gegen beispielsweise falsche<br />
Aufrufparameter oder falsche Zustände.<br />
• Realisierung:<br />
Die Anweisung assert wird zur Prüfung der Vor- und Nachbedingungen einer Methode<br />
verwendet.<br />
Sie wertet eine übergebene Bedingung aus. Ist diese falsch, so wird das Programm mit<br />
einem AssertionError beendet.<br />
• Beispiel Methode sqrt:<br />
public double sqrt(double value) {<br />
assert value >= 0.0;<br />
// Nicht negativ<br />
// Wurzelberechnung<br />
}<br />
• Aufruf mit:<br />
x.sqrt(42.0); // OK<br />
x.sqrt(-66.66); // Abbruch<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 99
Zusicherungen<br />
Fehlerhafte Methodenaufrufe<br />
• Verwendungen:<br />
<br />
<br />
<br />
<br />
assert Bedingung;<br />
- Der Ausdruck muss einen Boole‘schen Wert ergeben.<br />
- Ist der Wert false, so wird dieses als Fehler betrachtet.<br />
- Ist der Wert true, so wird das Programm normal fortgesetzt.<br />
assert value >= 0.0;<br />
assert Bedingung : Meldungstext;<br />
- Es gelten die Aussagen wie im ersten Fall.<br />
- Zusätzlich wird hier ein Text übergeben, der in die Ausnahme aufgenommen wird.<br />
assert value >= 0.0 : "Die Wurzel aus 0 ist undefiniert."<br />
Assertions müssen aktiviert werden:<br />
- Alle aktivieren: java -ea Main.class<br />
- Nur im Paket de.hska und dessen Unterpaketen: java -ea:de.hska...<br />
Sind Assertions nicht aktiv, dann werden sie ignoriert.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 100
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
• Programmierung eines<br />
sehr einfachen Ticketautomaten:<br />
<br />
Der Preis erscheint auf<br />
dem Display (Einheitspreis in Cent).<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 101
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
<br />
Der Kunde zahlt solange mit Münzen oder Scheinen, bis der Betrag erreicht ist (muss<br />
passend bezahlen).<br />
<br />
<br />
Nach dem Geldeinwurf wird der Restbetrag angezeigt.<br />
Nach Erreichen des Betrags wird der Fahrschein ausgegeben.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 102
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
• Benötigte Attribute:<br />
<br />
<br />
int ticketPrice: Preis für ein Ticket<br />
int paidPrice: bereits bezahlter Preis<br />
• Benötigte Methoden, 1. Versuch:<br />
<br />
<br />
<br />
<br />
<br />
Konstruktor: Einheitspreis als int-Parameter flexibel<br />
void requestTicket(): Ticket anfordern<br />
int requestPrice(): (Rest-)Preis für das Ticket abfragen<br />
void insertMoney(int amount): Geld einwerfen<br />
void printTicket(): Ticket ausdrucken<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 103
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
• Klasse in UML:<br />
TicketMachine<br />
-ticketPrice: int<br />
-paidPrice: int<br />
+TicketMachine(price: int)<br />
+requestTicket()<br />
+requestPrice(): int<br />
+insertMoney(amount: int)<br />
+printTicket()<br />
context TicketMachine::printTicket<br />
pre: paidPrice >= ticketPrice<br />
post: paidPrice = 0<br />
context TicketMachine::requestTicket<br />
post: paidPrice = 0<br />
context TicketMachine::insertMoney<br />
pre: amount > 0<br />
post: paidPrice = paidPrice + amount<br />
context TicketMachine::TicketMachine<br />
pre: price > 0<br />
post: (ticketPrice = price and<br />
paidPrice = 0)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 104
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
• Quelltext:<br />
public class TicketMachine {<br />
// Die Attribute der Klasse<br />
private int ticketPrice;<br />
private int paidPrice;<br />
// Konstruktor zum Initialisieren<br />
public TicketMachine(int price) {<br />
ticketPrice = price;<br />
paidPrice = 0;<br />
}<br />
// Ticket anfordern --> löscht den bisher bezahlten Betrag<br />
public void requestTicket() {<br />
paidPrice = 0;<br />
}<br />
// (Noch) zu zahlenden Betrag anfordern.<br />
public int requestPrice() {<br />
return ticketPrice – paidPrice;<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 105
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
}<br />
// Geld einwerfen --> Restbetrag reduzieren.<br />
public void insertMoney(int amount) {<br />
paidPrice += amount;<br />
}<br />
// Ticket "ausdrucken"<br />
public void printTicket() {<br />
System.out.println("Ticket xyz");<br />
System.out.println("Preis: " + ticketPrice);<br />
paidPrice = 0;<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 106
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
• Eine perfekte Lösung Nein!!!<br />
• Probleme:<br />
<br />
<br />
Keine Prüfungen der Methodenparameter und internen Zustände:<br />
- negative Beträge eingeworfen<br />
- Ticket drucken, obwohl Endbetrag nicht erreicht wurde<br />
- Was passiert, wenn zu viel Geld eingeworfen wurde?<br />
- Der Ticketpreis im Konstruktor ist ungeprüft.<br />
Einhaltung der Constraints wurde nicht geprüft!!!<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 107
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
• Quelltext mit Prüfungen:<br />
public class TicketMachine {<br />
// Die Attribute der Klasse<br />
private int ticketPrice;<br />
private int paidPrice;<br />
// Konstruktor zum Initialisieren<br />
public TicketMachine(int price) {<br />
assert price > 0;<br />
ticketPrice = price;<br />
paidPrice = 0;<br />
}<br />
context TicketMachine::TicketPrice<br />
pre: price > 0<br />
post: (ticketPrice = price and<br />
paidPrice = 0)<br />
// Ticket anfordern --> löscht den bisher bezahlten Betrag<br />
public void requestTicket() {<br />
paidPrice = 0;<br />
}<br />
context TicketMachine::requestTicket<br />
post: paidPrice = 0<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 108
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
// (Noch) zu zahlenden Betrag anfordern.<br />
public int requestPrice() {<br />
return ticketPrice – paidPrice;<br />
}<br />
context TicketMachine::insertMoney<br />
pre: amount > 0<br />
post: paidPrice = min(paidPrice + amount,<br />
ticketPrice)<br />
// Geld einwerfen --> Restbetrag reduzieren.<br />
// Zuviel bezahlten Betrag wieder auswerfen.<br />
public int insertMoney(int amount) {<br />
assert amount > 0;<br />
int diff = ticketPrice – paidPrice - amount;<br />
paidPrice += amount;<br />
if (paidPrice > ticketPrice)<br />
paidPrice = ticketPrice;<br />
return diff >= 0 ? 0 : -diff;<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 109
Zusicherungen<br />
Fehlerhafte Methodenaufrufe: Ticketautomat<br />
}<br />
// Ticket "ausdrucken"<br />
public void printTicket() {<br />
assert paidPrice >= ticketPrice;<br />
System.out.println("Ticket xyz");<br />
System.out.println("Preis: " + ticketPrice);<br />
paidPrice = 0;<br />
}<br />
context TicketMachine::printTicket<br />
pre: paidPrice >= ticketPrice<br />
post: paidPrice = 0<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 110
Klassen und Objekte<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 111
Klassen und Objekte<br />
Beispiel: Ringpuffer<br />
• Eine erste einfache Implementierung eines Ringpuffers:<br />
<br />
<br />
Ein Ringpuffer kann als ein Array mit speziellen Lese- und Schreiboperationen<br />
interpretiert werden:<br />
Das Array dieses Ringpuffers kann nur int-Daten aufnehmen.<br />
Ein Leseindex RI zeigt die Position an, an der der nächste Wert gelesen wird. Nach dem<br />
Lesen wird der Index automatisch erhöht. Am Ende des Arrays wird der Index auf 0<br />
gesetzt. Somit handelt es sich um ein zerstörendes Lesen, bei dem der Wert nach dem<br />
Lesen nicht mehr im Ringpuffer zugreifbar ist.<br />
Ein Schreibindex WI zeigt die Position an, an die der nächste Wert geschrieben wird.<br />
Nach dem Schreiben wird der Index automatisch erhöht. Am Ende des Arrays wird der<br />
Index auf 0 gesetzt.<br />
Der Ringpuffer ist leer, wenn WI genauso groß wie RI ist.<br />
Der Ringpuffer ist voll, wenn gilt: WI hätte nach dem Erhöhen den Wert von RI.<br />
• Bessere Variante: siehe Übungsaufgabe<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 112
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung<br />
• Warum kann man Objekte und Variable nicht einfach alle auf dem Stack verwalten?<br />
• Wie werden Objekte auf dem Heap erzeugt und wieder freigegeben?<br />
• Referenzen sind spezielle Variable, die auf Objekte verweisen.<br />
• Zum Bau komplexer Datenstrukturen sind der Heap und Referenzen zwingend<br />
notwendig.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 113
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung<br />
Definition: Referenz<br />
Eine Referenz hat einen unveränderlichen Typ T. Sie enthält einen Verweis auf genau ein<br />
oder gar kein Objekt der Klasse T. Das Objekt liegt auf dem Heap.<br />
• Beispiel für eine Referenz, die auf kein Objekt verweist:<br />
Bruch brReferenz = null;<br />
• Beispiel für eine Referenz auf ein Bruch-Objekt:<br />
Bruch brReferenz = new Bruch(2,3);<br />
• Intern enthält die Referenz die Speicheradresse des Objektes.<br />
• Es existieren zwei Referenzen mit einer besonderen Semantik:<br />
<br />
null: Die Referenz verweist auf gar kein Objekt.<br />
this: Die Referenz verweist auf die eigene Objektinstanz (kann nur in Konstruktoren<br />
oder nicht-statischen Methoden verwendet werden).<br />
• Es gibt auch sogenannte schwache Referenzen, die hier aber nicht betrachtet werden sollen.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 114
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung<br />
Definition: Heap<br />
Speicherbereich, in dem der Entwickler selbst die Lebensdauer seiner Daten kontrolliert. Mit<br />
new wird ein Bereich reserviert. Die Freigabe erfolgt automatisch durch den Garbage-<br />
Collector.<br />
• Der Operator new führt die folgenden Schritte durch:<br />
<br />
<br />
<br />
Reservierung des benötigten Speichers auf dem Heap<br />
Aufruf eines Konstruktors<br />
Rückgabe einer Referenz auf das erzeugte Objekt<br />
• Anforderung eines Speicherbereichs mit Aufruf des Defaultkonstruktors:<br />
Syntax:<br />
Beispiel:<br />
Klasse ref = new Klasse();<br />
Pacman pacmanRef = new Pacman();<br />
• Anforderung eines Speicherbereichs mit Aufruf eines beliebigen Konstruktors:<br />
Syntax:<br />
Klasse ref = new Klasse(init);<br />
Beispiel:<br />
Pacman pacmanRef = new Pacman(x, y);<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 115
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung – new-Operator<br />
• Der Operator new führt die folgenden Schritte bei Arrays durch:<br />
<br />
<br />
<br />
Reservierung des benötigten Speichers auf dem Heap<br />
Initialisierung des Arrays:<br />
- bei Arrays mit primitiven Datentypen: 0, 0.0 oder false<br />
- bei Arrays mit Referenzen: null<br />
Rückgabe einer Referenz auf das Array<br />
• Anforderung eines Speicherbereichs der Größe des Arrays mit primitiven Daten:<br />
Syntax:<br />
Beispiel:<br />
Typ[] ref = new Typ[ size ]; int[] iRef = new int[ 10 ];<br />
• Das Array enthält 10 int-Daten mit dem Wert 0.<br />
• Anforderung eines Speicherbereichs der Größe des Arrays mit Referenzen:<br />
Syntax:<br />
Beispiel:<br />
Typ[] ref = new Typ[ size ]; Bruch[] brRef = new Bruch[ 10 ];<br />
Das Array enthält 10 null-Referenzen. Es werden keine Bruch-Objekte angelegt!<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 116
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung – new-Operator für Arrays<br />
• Ausführlicheres Beispiel: 4 Referenzen auf Ghost-Objekte in einem Array:<br />
Ghost[] allGhosts = new Ghost[ 4 ]; // Platz für vier Geister<br />
for (int i = 0; i < allGhosts.length; i++)<br />
allGhosts[ i ] = new Ghost(3, 1);<br />
for (int i = 0; i < allGhosts.length; i++)<br />
allGhosts[ i ].setX(12);<br />
0x1240<br />
0x1240 0x2000 0x2010 0x2020<br />
allGhosts<br />
0x2030<br />
Fiktive Adressen!<br />
Geist 1 Geist 2 Geist 3<br />
0x2000 0x2010 0x2020<br />
Geist 4<br />
0x2030<br />
• Mehrdimensionale Arrays lassen genauso erzeugen.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 117
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung – Speicherfreigabe<br />
Was passiert mit Objekten, auf die keine Referenzen mehr existieren?<br />
• Sie sind durch das eigene Programm nicht mehr erreichbar.<br />
• Der interne Garbage-Collector kann sie beseitigen und wieder dem Freispeicher zuordnen.<br />
• Vor der Speicherfreigabe wird die Methode protected void finalize() des zu<br />
löschenden Objektes aufgerufen.<br />
• Es kann passieren, dass die Objekte auf dem Heap bleiben, wenn genügend Speicher<br />
vorhanden ist Zeitpunkt der Freigabe ist nicht vorhersehbar.<br />
• Manueller Aufruf des Garbage-Collectors: Runtime.getRuntime().gc();<br />
Es werden trotzdem nicht alle unerreichbaren Objekte freigegeben.<br />
Mehrfacher Aufruf, bis sich der freie Speicher nicht mehr ändert:<br />
long freeMem = Runtime.getRuntime().freeMemory();<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 118
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung – Singleton<br />
Definition: Singleton<br />
Eine Klasse, von der nur ein Objekt erzeugt werden kann.<br />
• Beispielimplementierung (nicht perfekt).<br />
public class Logger {<br />
private static Logger instance;<br />
// Privater Konstruktor<br />
private Logger(){<br />
}<br />
public static Logger getInstance(){<br />
if (instance == null)<br />
instance = new Logger();<br />
return instance;<br />
}<br />
public void test() {<br />
Logger log1 = new Logger(); // Fehler<br />
Logger log2 = Logger.getInstance();<br />
Logger log3 = Logger.getInstance();<br />
}<br />
log2.log("Wichtige Nachricht");<br />
// Oder kürzer<br />
Logger.getInstance().log("Nachricht");<br />
}<br />
public void log(String message) {<br />
// Ausgabe<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 119
Klassen und Objekte<br />
Referenzen und dynamische Speicherverwaltung – Beispiel<br />
• Implementierung einer einfach verketteten Liste doppelte Verkettung ist eine<br />
Übungsaufgabe!<br />
• Welche Klassen werden benötigt?<br />
• Implementierung einiger Methoden der Klassen<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 120
Überladen von Methoden<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Typinformationen<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassendiagramme<br />
Ein-,<br />
Ausgabe<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Annotationen<br />
Überladen<br />
Laufzeittypinfo.<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 121
Überladen von Methoden<br />
Definition: Überladen von Methoden<br />
Eine Klasse besitzt zwei oder mehr Methoden mit demselben Namen und unterschiedlichen<br />
Parametertypen.<br />
Die passende Methode wird durch den Compiler ermittelt, indem er auch<br />
Typkonvertierungen durchführt.<br />
Der Rückgabetyp darf unterschiedlich sein.<br />
Beispiel:<br />
Klassenname<br />
-attribut: int<br />
+methode()<br />
+methode(wert: int)<br />
+methode(wert: string)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 122
Überladen von Methoden<br />
• Einsatz: Verwendung der gleichen Methode mit unterschiedlichen Parametertypen.<br />
• Vorteil: Keine explizite Konvertierung der Argumente im Aufruf.<br />
• Beispiel: Vereinfachter Auszug aus der bereits eingeführten Klasse GameController, die in<br />
Pacman die Figuren steuert.<br />
GameController<br />
+collisionOfPacmanWith(ghost: Ghost)<br />
+collisionOfPacmanWith(cherry: Cherry)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 123
Überladen von Methoden<br />
Auswahl der passenden Methode<br />
Auswahlkriterien durch den Compiler:<br />
• Die Anzahl der Parameter muss zum Aufruf passen.<br />
• Alle Übergabeparameter müssen in die Parametertypen der Methode konvertierbar sein.<br />
Beispiel:<br />
public class PrintStream {<br />
public void println(long x){}<br />
public void println(char x){}<br />
}<br />
Aufruf:<br />
PrintStream out = ...<br />
out.println(123);<br />
PrintStream<br />
+println(x: long)<br />
+println(x: char)<br />
int wird zu long<br />
• Für alle Übergabeparameter wird der kleinste passende Typ gesucht.<br />
Beispiel: char int, vor char long.<br />
• Ein größerer Typ wird nie in einen kleineren Typ umgewandelt.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 124
Überladen von Methoden<br />
• Es wird die Methode mit der kleinsten Summe der „Konvertierungsabstände“ aller Parameter<br />
ermittelt.<br />
• Existieren mehrere Methoden mit gleichem minimalen Abstand, so wird ein<br />
Übersetzungsfehler gemeldet.<br />
• Beispiel (OK, ziemlich sinnlos):<br />
public class MyClass {<br />
public void method(long x, int y);<br />
public void method(int x, long y);<br />
}<br />
Aufruf:<br />
MyClass cl = new MyClass();<br />
cl.method(123, 456 ); Fehler !<br />
cl.method(123L,456 );<br />
cl.method(123, 456L);<br />
MyClass<br />
+method(x: long, y: int)<br />
+method(x: int, y: long)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 125
Vererbung<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 126
Vererbung<br />
Motivation<br />
• Wie können existierende Klassen wiederverwendet werden?<br />
• Welche Methoden sollte eine Klasse immer unterstützen?<br />
• Welche Arten von Beziehungen können zwischen Objekten bestehen?<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 127
Vererbung<br />
Motivation<br />
• Eigenschaften, die für eine Figur gelten, gelten eventuell auch für spezielle Figuren:<br />
Figure<br />
Ghost<br />
Pacman<br />
• Vererbungsbeziehungen können mit der Vererbungshierarchie in der Biologie verglichen<br />
werden:<br />
Animal<br />
Mammal<br />
Reptile<br />
Kangaroo<br />
Koala<br />
Crocodile<br />
• Ein Koalabär ist ein Säugetier (Mammal) ist ein Tier.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 128
Vererbung<br />
Begriffe<br />
• Es gibt zwei Arten der Vererbung in Programmiersprachen:<br />
<br />
Vererbung der Spezifikation: wichtiges Konzept der objektorientierten Programmierung<br />
Vererbung der Implementierung: Mittel zur Vermeidung von Redundanzen mit einigen<br />
konzeptuellen und praktischen Problemen<br />
• Beide Techniken werden häufig unter dem Begriff der Vererbung zusammengefasst.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 129
Vererbung<br />
Begriffe<br />
Definition: Vererbung<br />
Vererbung ist eine Programmiersprachenkonzept zur Umsetzung einer Relation zwischen<br />
einer Ober- und einer Unterklasse:<br />
Eine Klasse AbgelKlasse ist dann eine Unterklasse der Klasse BasisKlasse, wenn<br />
AbgelKlasse die Spezifikation von BasisKlasse erfüllt, umgekehrt aber BasisKlasse<br />
nicht die Spezifikation von AbgelKlasse. Die Klasse BasisKlasse ist dann eine Oberklasse<br />
von AbgelKlasse.<br />
BasisKlasse<br />
+operation1()<br />
AbgelKlasse hält Vorund<br />
Nachbedingung von<br />
operation1 der<br />
BasisKlasse ein.<br />
AbgelKlasse<br />
+operation1()<br />
+operation2()<br />
AbgelKlasse erweitert<br />
die eigene Spezifikation<br />
um operation2.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 130
Vererbung<br />
Begriffe<br />
• Die Oberklasse vererbt ihre Spezifikation (Vor- und Nachbedingungen) an die Unterklasse.<br />
• Durch Unterklassen wird das Verhalten der Oberklasse nicht verändert.<br />
• Durch Vererbung (Ableitung) entsteht eine Klassenhierarchie.<br />
-x: int<br />
-y: int<br />
Figure<br />
+setX(x: int)<br />
+setY(y: int)<br />
Oberklasse<br />
Superklasse<br />
Basisklasse<br />
Generalisierung<br />
ist Spezialfall von<br />
ist Erweiterung von<br />
ist Verallgemeinerung<br />
von<br />
-IQ: int<br />
Ghost<br />
+getIQ(): int<br />
Pacman<br />
-mouthOpening: boolean<br />
+isMouthOpening(): boolean<br />
Unterklasse<br />
Subklasse<br />
abgeleitete Klasse<br />
Spezialisierung<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 131
Vererbung<br />
Begriffe<br />
Generalisierung und Spezialisierung – Begriffe<br />
• Prozess der Klassenbildung ist ein Abstraktionsvorgang:<br />
Spezialisierung: Aus bestehenden Klassen können spezialisierte Unterklassen<br />
(abgeleitete Klassen) gebildet werden.<br />
Generalisierung: Gemeinsamkeiten bestehender Klassen können in gemeinsame<br />
Oberklassen (Basisklasse) verlagert werden.<br />
Ergebnis: Klassenhierarchien aus Ober- und Unterklassen.<br />
• Oberklassen: Allgemeiner und abstrakter als Unterklassen.<br />
• Unterklassen: Spezieller und konkreter als Oberklassen.<br />
• Der Sprachmechanismus, der dieses Konzept unterstützt, wird Vererbung genannt.<br />
• Wichtig: Eine Unterklasse ist ein Untertyp von Oberklasse. Damit kann die Unterklasse<br />
überall dort verwendet werden, wo die Oberklasse erwartet wird.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 132
Vererbung<br />
Begriffe<br />
• Eine Unterklasse ist ein Stellvertreter für die Oberklasse.<br />
• Sie kann Methoden der Oberklasse überschreiben (umdefinieren).<br />
Klassen<br />
Objekte<br />
-x: int<br />
-y: int<br />
Figure<br />
+setX(x: int)<br />
+setY(y: int)<br />
Speicher<br />
x = 1<br />
y = 4<br />
IQ = 70<br />
ghost1<br />
pacman<br />
-IQ: int<br />
Ghost<br />
+getIQ(): int<br />
Pacman<br />
-mouthOpening: boolean<br />
+isMouthOpening(): boolean<br />
x = 2<br />
y = 13<br />
mouthOpening = false<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 133
Vererbung<br />
Vererbung der Spezifikation<br />
Allgemeiner Fall: Vererbung der Spezifikation<br />
• Eine Unterklasse erbt grundsätzlich die Spezifikation ihrer Oberklasse.<br />
• Die Unterklasse übernimmt damit alle Verpflichtungen und Zusicherungen der Oberklasse.<br />
• Häufiger wird auch der Begriff Vererbung von Schnittstellen benutzt.<br />
• Vererbung der Spezifikation: Eine Unterklasse übernimmt die Verpflichtungen (Vor- und<br />
Nachbedingungen), die sich aus der Spezifikation der Oberklasse ergeben.<br />
• Vererbung ist mehr als die einfache Syntax zur Implementierung einer Schnittstelle.<br />
• Prinzip der Ersetzbarkeit: Wenn die Klasse B eine abgeleitete Klasse der Klasse A ist, dann<br />
können in einem Programm alle Objekte der Klasse A durch Objekte der Klasse B ersetzt<br />
worden sein, und es gelten trotzdem weiterhin alle zugesicherten Eigenschaften der Klasse A.<br />
• Java unterstützt dieses Konzept durch eigene Sprachmittel, C++ nicht kommt gleich<br />
genauer.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 134
Vererbung<br />
Vererbung der Implementierung<br />
Spezieller Fall: Vererbung der Implementierung<br />
• Anwendungsbeispiel: Es gibt eine Basisklasse, die nicht vollständig durch spezialisierte<br />
abgeleitete Klassen abgedeckt wird.<br />
• Es gibt also Objekte der Basisklasse.<br />
• Beispiel (in der Basisklasse sind z.B. Beamte und Rentner):<br />
Steuerzahler<br />
Angestellter<br />
Selbstaendiger<br />
• Syntaxbeispiel:<br />
public class Angestellter extends Steuerzahler {<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 135
Vererbung<br />
Vererbung der Implementierung<br />
Beispiel: Erben gesetzlicher Regelungen (aus „Praxisbuch Objektorientierung“)<br />
• Gesetzliche Regelungen werden auf verschiedenen Ebenen vorgenommen. Für eine in<br />
Karlsruhe lebende Person gilt:<br />
Die europäische Union legt rechtliche Rahmenbedingungen fest.<br />
Die Bundesrepublik Deutschland hat gesetzliche Regelungen für das Steuerrecht.<br />
Das Land Baden-Württemberg hat wiederum eigene spezielle Regelungen.<br />
Schließlich legt die Stadt Karlsruhe noch eigene Regelungen fest, zum Beispiel den so<br />
genannten Hebesatz für die Gewerbesteuer.<br />
• „Vererbung der Regelungen“<br />
Die Karlsruher-Regelung erbt von der des Landes Baden-Württemberg.<br />
Diese wiederum erben die Regeln des Bundes.<br />
Der Bund muss die Regeln der EU akzeptieren.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 136
Vererbung<br />
Vererbung der Implementierung<br />
• Effekte der Vererbung der Umsetzung:<br />
Beispiel: Der allgemeine Einkommenssteuersatz wird für Karlsruhe direkt aus der<br />
Regelung des Bundes übernommen.<br />
Eine Änderung des Einkommensteuersatzes bundesweit führt auch zu einer Änderung in<br />
Karlsruhe.<br />
In einem bestimmten Rahmen können eigene Umsetzungen in den speziellen Fällen<br />
erfolgen. Beispiel: Jede Kommune hat eigene Gewerbesteuerumsetzung.<br />
• Die Regelungen sind hierarchisch organisiert, wobei die weiter oben liegenden Regeln jeweils<br />
weiter unten liegende überschreiben.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 137
Vererbung<br />
Vererbung der Implementierung<br />
• Suche einer passenden Regelung anhand des Beispiels:<br />
Suchrichtung<br />
Steuerrecht Karlsruhe<br />
Steuerrecht BW<br />
Steuerrecht Bund<br />
Steuerrecht EU<br />
<br />
<br />
Suche eines Gesetzes durch Suchen in den Büchern „von oben nach unten“ im Stapel.<br />
Vorteil:<br />
- Karlsruhe muss nicht den kompletten Gesetzestext der EU beinhalten.<br />
- Eine Änderung innerhalb der EU wird automatisch übernommen.<br />
- Nur kleinere Anpassungen werden lokal festgelegt Karlsruher Recht muss mit EU-<br />
Recht übereinstimmen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 138
Vererbung<br />
Vererbung der Implementierung<br />
• Klassenhierarchie der Regelungen:<br />
Steuerrecht-<br />
EU<br />
Steuerrecht-<br />
Bund<br />
Steuerrecht-<br />
BW<br />
Steuerrecht-<br />
Karlsruhe<br />
• Wie wird eine Klassenhierarchie implementiert?<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 139
Vererbung<br />
Vererbung der Implementierung – Syntax<br />
• Beispiel:<br />
<br />
<br />
Figure als allgemeine Basisklasse für eine Figur<br />
Ghost als spezielle Figur<br />
public class Figure {<br />
private int xPos;<br />
private int yPos;<br />
}<br />
public Figure(int xPos, int yPos) { /* ... */ }<br />
public void move(int xPos, int yPos) { /* ... */ }<br />
//...<br />
public class Ghost extends Figure {<br />
private boolean dangerous;<br />
}<br />
public Ghost(int xPos, int yPos, boolean dangerous) { /* ... */ }<br />
public boolean isDangerous() { /* ... */ }<br />
public void move(int xPos, int yPos) { /* ... */ }<br />
//...<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 140
Vererbung<br />
Vererbung der Implementierung – Konstruktorenreihenfolge<br />
• Frage: Wie funktioniert der Konstruktoraufruf in Figure jetzt, wenn ein Ghost-Objekt<br />
erzeugt wird?<br />
• Antwort: Der Konstruktor von Ghost kann Argumente an den Konstruktor der Basisklasse<br />
Figure weiterleiten.<br />
• Ein Konstruktor kann auch seine eigenen Attribute initialisieren.<br />
Vorgehensweise:<br />
Aufruf des Basisklassenkonstruktors.<br />
Initialisierung der eigenen Attribute.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 141
Vererbung<br />
Vererbung der Implementierung – Konstruktorenreihenfolge<br />
• Klassenelemente werden von „oben“ nach „unten“ initialisiert:<br />
<br />
<br />
<br />
Erst wird der Konstruktor der Basisklasse aufgerufen.<br />
Dann werden die Attribute einer Klasse in der Reihenfolge ihrer Deklaration initialisiert.<br />
Abschließend wird der Konstruktor der Klasse selbst aufgerufen.<br />
• Initialisierungsreihenfolge im Ghost-Beispiel:<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
+Figure()<br />
Initialisierungsreihenfolge<br />
1. Attribute der Basisklasse in der<br />
Reihenfolge ihrer Deklaration<br />
2. Konstruktor der Basisklasse<br />
Ghost<br />
-dangerous: boolean<br />
+Ghost()<br />
3. Attribute der abgeleiteten Klasse<br />
in der Reihenfolge ihrer Deklaration<br />
4. Konstruktor der abgeleiteten Klasse<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 142
Vererbung<br />
Vererbung der Implementierung – Konstruktorenreihenfolge<br />
• Beispiel: Ghost<br />
public Ghost(int xPos, int yPos, boolean dangerous) {<br />
super(xPos, yPos);<br />
this.dangerous = dangerous;<br />
}<br />
Konstruktor<br />
Basisklasse<br />
Attribute<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 143
Vererbung<br />
Vererbung der Implementierung – Freigabereihenfolge<br />
• Zur Erinnerung: Vor der Freigabe wird die Methode finalize aufgerufen.<br />
<br />
<br />
Zuerst wird finalize der abgeleiteten Klasse aufgerufen.<br />
Diese Methode ruft finalize der Basisklasse auf und führt dann eigene<br />
Aufräumarbeiten durch.<br />
• Aufrufreihenfolge der finalize-Methoden im Ghost-Beispiel (sofern dort finalize<br />
implementiert wurde):<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
#finalize()<br />
Freigabereihenfolge<br />
2. finalize der Basisklasse<br />
Ghost<br />
-dangerous: boolean<br />
#finalize()<br />
ruft auf<br />
1. finalize der abgeleiteten Klasse<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 144
Vererbung<br />
Vererbung der Implementierung - Verhindern der Vererbung<br />
• Soll verhindert werden, dass von einer bestimmten Klasse geerbt wird, dann kann sie als<br />
final deklariert werden. Beispiel:<br />
public final class Game {<br />
private Cell[][] cells;<br />
public Game() { /* ... */ }<br />
}<br />
public void run() { /* ... */ }<br />
/* ... */<br />
Die Klasse String ist beispielsweise als final deklariert.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 145
Vererbung<br />
Vererbung der Implementierung – Klassenhierarchien<br />
Bildung komplexer Klassenhierarchien<br />
Jede abgeleitete Klasse kann die Basisklasse einer anderen Klasse sein.<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
public class Figure {<br />
private int xPos;<br />
private int yPos;<br />
+Figure()<br />
Ghost<br />
-dangerous: boolean<br />
+Ghost()<br />
}<br />
public Figure() { /* ... */ }<br />
public void move(int xPos, int yPos) {<br />
/* ... */<br />
}<br />
public void print() { /* ... */ }<br />
/* ... */<br />
FlyingGhost<br />
+FlyingGhost()<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 146
Vererbung<br />
Vererbung der Implementierung – Klassenhierarchien<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
+Figure()<br />
Ghost<br />
-dangerous: boolean<br />
+Ghost()<br />
FlyingGhost<br />
public class Ghost extends Figure {<br />
private boolean dangerous;<br />
}<br />
public void move(int xPos, int yPos) {<br />
/* ... */ }<br />
public void print() { /* ... */ }<br />
/* ... */<br />
+FlyingGhost()<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 147
Vererbung<br />
Vererbung der Implementierung – Klassenhierarchien<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
+Figure()<br />
Ghost<br />
-dangerous: boolean<br />
+Ghost()<br />
FlyingGhost<br />
public class FlyingGhost extends Ghost {<br />
+FlyingGhost()<br />
}<br />
public void print() { /* ... */ }<br />
/* ... */<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 148
Vererbung<br />
Vererbung der Implementierung – Klassenhierarchien<br />
Hinweise<br />
• Die Klassenhierarchie kann einen Baum bilden.<br />
Beispiel:<br />
public class Person { /* ... */ }<br />
public class Student extends Person { /* ... */ }<br />
public class Angestellter extends Person { /* ... */ }<br />
• Mehrfachvererbung gibt es in Java nicht.<br />
Definition: Einfachvererbung<br />
Eine abgeleitete Klasse erbt nur von einer direkten Basisklasse.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 149
Vererbung<br />
Vererbung der Implementierung – Rechte bei Attribut- oder Methodenzugriffen<br />
• Neues Zugriffsrecht: protected für Vererbung räumt einer abgeleiteten Klasse mehr<br />
Rechte als einer anderen Klasse ein.<br />
• Eine abgeleitete Klasse kann<br />
<br />
<br />
<br />
alle public- oder protected-Methoden aller seiner Basisklassen aufrufen.<br />
alle public- oder protected-Attribute aller seiner Basisklassen lesen und beschreiben.<br />
nicht auf die privaten Methoden oder privaten Attribute der Basisklassen zugreifen.<br />
• Wird eine abgeleitete Klasse in einem Programm verwendet, so kann nur auf die public-<br />
Methoden oder Attribute dieser Klasse sowie deren Oberklassen zugegriffen werden.<br />
Beispiel:<br />
Ghost ghost = new Ghost(3, 2, true);<br />
ghost.move(3, 1);<br />
boolean dangerous = ghost.dangerous;<br />
// OK<br />
// Fehler, privat<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 150
Vererbung<br />
Vererbung der Implementierung – Rechte bei Attribut- oder Methodenzugriffen<br />
• Szenario:<br />
hska.iwii.my hska.iwii.p1 hska.iwii.p2<br />
public class A {<br />
public int i1;<br />
protected int i2;<br />
private int i3;<br />
int i4;<br />
}<br />
//code<br />
class B extends A {<br />
//code<br />
}<br />
class C {<br />
//code<br />
}<br />
class D extends A {<br />
//code<br />
}<br />
class E {<br />
//code<br />
}<br />
class F {<br />
}<br />
//code<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 151
Vererbung<br />
Vererbung der Implementierung – Rechte bei Attribut- oder Methodenzugriffen<br />
hska.iwii.my hska.iwii.p1 hska.iwii.p2<br />
public class A {<br />
public int i1;<br />
protected int i2;<br />
private int i3;<br />
int i4;<br />
}<br />
//code<br />
class B extends A {<br />
//code<br />
}<br />
class C {<br />
//code<br />
}<br />
class D extends A {<br />
//code<br />
}<br />
class E {<br />
//code<br />
}<br />
class F {<br />
}<br />
//code<br />
public int i1 ist in allen Klassen und Paketen sichtbar.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 152
Vererbung<br />
Vererbung der Implementierung – Rechte bei Attribut- oder Methodenzugriffen<br />
hska.iwii.my hska.iwii.p1 hska.iwii.p2<br />
public class A {<br />
public int i1;<br />
protected int i2;<br />
private int i3;<br />
int i4;<br />
}<br />
//code<br />
class B extends A {<br />
//code<br />
}<br />
class C {<br />
//code<br />
}<br />
class D extends A {<br />
//code<br />
}<br />
class E {<br />
//code<br />
}<br />
class F {<br />
}<br />
//code<br />
protected int i2 ist in Unterklassen und im eigenen Paket sichtbar.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 153
Vererbung<br />
Vererbung der Implementierung – Rechte bei Attribut- oder Methodenzugriffen<br />
hska.iwii.my hska.iwii.p1 hska.iwii.p2<br />
public class A {<br />
public int i1;<br />
protected int i2;<br />
private int i3;<br />
int i4;<br />
}<br />
//code<br />
class B extends A {<br />
//code<br />
}<br />
class C {<br />
//code<br />
}<br />
class D extends A {<br />
//code<br />
}<br />
class E {<br />
//code<br />
}<br />
class F {<br />
}<br />
//code<br />
private int i3 ist nur in der eigenen Klasse sichtbar.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 154
Vererbung<br />
Vererbung der Implementierung – Rechte bei Attribut- oder Methodenzugriffen<br />
hska.iwii.my hska.iwii.p1 hska.iwii.p2<br />
public class A {<br />
public int i1;<br />
protected int i2;<br />
private int i3;<br />
int i4;<br />
}<br />
//code<br />
class B extends A {<br />
//code<br />
}<br />
class C {<br />
//code<br />
}<br />
class D extends A {<br />
//code<br />
}<br />
class E {<br />
//code<br />
}<br />
class F {<br />
}<br />
//code<br />
• int i4 ist im eigenen Package sichtbar.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 155
Überschreiben von Methoden<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 156
Überschreiben von Methoden<br />
Grundlagen<br />
• Idee: Eine abgeleitete Klasse besitzt eine Methode mit demselben Namen und derselben<br />
Signatur wie die Basisklasse.<br />
Basisklasse<br />
+print()<br />
AbgeleiteteKlasse<br />
+print()<br />
• Ein häufiges Problem beim Prinzip der Ersetzbarkeit:<br />
<br />
<br />
Eine Basisklassenreferenz verweist auf ein Objekt einer abgeleiteten Klasse.<br />
Wie kann festgestellt werden, welcher Klasse das Objekt angehört wichtig für den<br />
Aufruf der korrekten Methode?<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 157
Überschreiben von Methoden<br />
Grundlagen<br />
Definition: Überschreiben (von Methoden)<br />
• Wenn eine abgeleitete Klasse eine Methode implementiert, für die es bereits in einer<br />
Basisklasse eine Methode gibt, so überschreibt die abgeleitete Klasse die Methode der<br />
Basisklasse.<br />
• Wird die Operation auf einem Exemplar der abgeleiteten Klasse aufgerufen, so wird die<br />
überschriebene Implementierung der Methode aufgerufen.<br />
• Das ist unabhängig davon, welchen Typ die Referenz hat, über die das Objekt angesprochen<br />
wird.<br />
• Entscheidend ist der Typ des Objekts selbst, nicht der Typ der Variablen.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 158
Überschreiben von Methoden<br />
Grundlagen<br />
• Aufruf der neuen Methode print.<br />
public class Figure {<br />
public void print() {<br />
System.out.println("Figure");<br />
}<br />
}<br />
public class Ghost extends Figure {<br />
private boolean dangerous;<br />
@Override<br />
public void print() {<br />
System.out.println("Ghost");<br />
}<br />
}<br />
// …<br />
private int test() {<br />
Ghost ghost = new Ghost(3, 2, true);<br />
Figure figure = ghost;<br />
ghost.print();<br />
figure.print();<br />
// ...<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
+print()<br />
Ghost<br />
-dangerous: boolean<br />
+print()<br />
Ausgabe:<br />
Ghost<br />
Ghost<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 159
Überschreiben von Methoden<br />
Verhalten<br />
Verhalten<br />
• Aufruf der Methode der abgeleiteten Klasse (auch, wenn die Methode über eine<br />
Basisklassenreferenz aufgerufen wird).<br />
• Vorteil: Code, der die Methoden aufruft, bleibt unverändert, selbst wenn Klassen<br />
hinzukommen oder sich Klassen ändern.<br />
• Verhalten<br />
Alle Methoden, die nicht als final deklariert werden, können überschrieben werden.<br />
Signatur und Name der Methode müssen in Basisklasse und abgeleiteter Klasse identisch<br />
sein.<br />
• Überschreibende Methoden sollten mit der Annotation @Override versehen werden. Dann<br />
kann der Compiler prüfen, ob diese Methode wirklich eine andere überschreibt:<br />
public class Ghost extends Figure {<br />
@Override<br />
public void print() {<br />
System.out.println("Ghost");<br />
}<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 160
Überschreiben von Methoden<br />
Verhalten<br />
• Beispiel für eine Methode, die nicht überschrieben werden darf:<br />
public class Figure {<br />
public final void print() {<br />
System.out.println("Figure");<br />
}<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 161
Überschreiben von Methoden<br />
Manueller Einfluss<br />
Manueller Einfluss auf das Überschreiben<br />
• Umgehung der automatischen Methodenauswahl, expliziter Aufruf einer Methode der<br />
Basisklasse: super.methode(Parameter);<br />
Beispiel:<br />
public class Figure {<br />
// ...<br />
public void move(int xPos, int yPos) {<br />
// ...<br />
}<br />
}<br />
-xPos: int<br />
-yPos: int<br />
Figure<br />
+move(xPos: int, yPos: int)<br />
public class Ghost extends Figure {<br />
// ...<br />
@Override<br />
public void move(int xPos, int yPos) {<br />
super.move(xPos, yPos);<br />
// z.B. Neuzeichnen<br />
}<br />
}<br />
Ghost<br />
-dangerous: boolean<br />
+move(xPos: int, yPos: int)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 162
Überschreiben von Methoden<br />
Konstruktoren<br />
Konstruktoren und Überschreiben<br />
• Der Konstruktor der Basisklasse wird vor dem Konstruktor der abgeleiteten Klasse<br />
ausgeführt.<br />
• Aufruf einer polymorphen Methode im Konstruktor der Basisklasse:<br />
Im Gegensatz zu C++: Aufruf der überschriebenen Methode<br />
Achtung: Die abgeleitete Klasse ist noch gar nicht initialisiert!!<br />
Konsequenz: Konstruktoren sollten nur private oder finale Methoden aufrufen.<br />
nein<br />
public class Base {<br />
private Bruch br;<br />
public Base() {<br />
}<br />
br = new Bruch();<br />
init();<br />
}<br />
public void init() {<br />
br.setZaehler(42);<br />
}<br />
ja<br />
public class Derived<br />
extends Base {<br />
private MathVector mv;<br />
public Derived() {<br />
mv = new MathVector(3,true);<br />
init();<br />
}<br />
@Override<br />
public void init() {<br />
mv.setValue(0, 66);<br />
}<br />
}<br />
Base<br />
+Base()<br />
+init()<br />
Derived<br />
+Derived()<br />
+init()<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 163
Überschreiben von Methoden<br />
Hinweise<br />
Hinweise zum Umgang mit dem Überschreiben<br />
Ermittlung der „richtigen“ Methode:<br />
• Zur Übersetzungszeit (early binding, statische Bindung):<br />
Der Aufruf kann vom Compiler direkt in Bytecode umgesetzt werden, da die Methode<br />
jederzeit bekannt ist.<br />
nur für Methoden möglich, die als final oder private deklariert sind<br />
• Zur Laufzeit (late binding, dynamische Bindung):<br />
Alle Methoden, die nicht final, nicht privat und nicht statisch sind Polymorphismus.<br />
Das Objekt findet selbst heraus, welche Methode aufgerufen werden soll<br />
geringer Mehraufwand beim Methodenaufruf<br />
Die überschreibende Methode der abgeleiteten Klasse darf die Zugriffsrechte der<br />
Methode der Basisklasse nicht einschränken.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 164
Überschreiben von Methoden<br />
Hinweise<br />
Hinweise zum Design<br />
• „Normale“ Methoden:<br />
<br />
<br />
Alle Methoden einer Klasse, die überschrieben werden dürfen, sollten nicht final sein.<br />
final sollte nur aus Design- nicht aus Geschwindigkeitsgründen hinzugefügt werden.<br />
• Finale Methoden:<br />
<br />
Methoden, die nicht überschrieben werden dürfen, sollten als final deklariert werden.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 165
Überschreiben von Methoden<br />
Regeln<br />
• Wiederholung: Prinzip der Ersetzbarkeit<br />
• Wenn die Klasse Abgel eine abgeleitete Klasse der Klasse Basis ist, dann können in einem<br />
Programm alle Objekte der Klasse Basis durch Objekte der Klasse Abgel ersetzt worden<br />
sein, und es gelten trotzdem weiterhin alle zugesicherten Eigenschaften der Klasse Basis.<br />
• Der für die Basisklasse geschlossene Kontrakt mit Bezug auf Vorbedingungen,<br />
Nachbedingungen und Invarianten gilt also auch dann weiter, wenn Objekte der Basisklasse<br />
durch Objekte der abgeleiteten Klasse ersetzt werden.<br />
• Beim Überschreiben von Methoden gilt also: Abgeleitete Klassen dürfen zwar mehr anbieten,<br />
aber nicht mehr verlangen als Exemplare ihrer Basisklassen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 166
Überschreiben von Methoden<br />
Regeln<br />
Liskovsches Substitutionsprinzip<br />
Formulierung 1993 von Barbara Liskov und Jeannette Wing:<br />
• Basisklasse Basis<br />
• b ist ein Objekt von Basis.<br />
• Abgeleitete Klasse Abgeleitet,<br />
die von Basis erbt<br />
• a ist ein Objekt von Abgeleitet.<br />
• Es gilt:<br />
Sei q(b) eine beweisbare Eigenschaft von Objekten b des Typs Basis. Dann soll q(a) für<br />
Objekte a des Typs Abgeleitet wahr sein.<br />
• Beispiele kommen gleich!<br />
Basis<br />
Abgeleitet<br />
Besser verständlich als „ist-ein“-Beziehung.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 167
Überschreiben von Methoden<br />
Regeln<br />
• Konsequenzen für die Vorbedingungen, Nachbedingungen und Invarianten einer<br />
abgeleiteten Klasse:<br />
Schwächere Vorbedingungen:<br />
- Eine abgeleitete Klasse kann die Vorbedingungen für eine Operation, die durch die<br />
Basisklasse definiert wird, einhalten oder abschwächen. Sie darf die Vorbedingungen<br />
aber nicht verschärfen.<br />
- Falls eine abgeleitete Klasse die Vorbedingungen verschärfen würde, würde damit<br />
ohne Absprache mit den Partnern von diesen mehr verlangt als vorher.<br />
- Erlaubte und verbotene Maßnahmen (unvollständig):<br />
Der Wertebereich der Übergabeparameter wird erweitert.<br />
Eine nicht öffentliche Methode wird öffentlich überschrieben.<br />
Der Wertebereich der Übergabeparameter wird verkleinert.<br />
Der Übergabeparameter wird von einem Objekt der Basisklasse auf ein Objekt<br />
der abgeleiteten Klasse eingeschränkt.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 168
Überschreiben von Methoden<br />
Regeln<br />
<br />
Stärkere Nachbedingungen:<br />
- Eine abgeleitete Klasse kann die Nachbedingungen für eine Operation, die durch<br />
eine Oberklasse definiert werden, einhalten oder einschränken. Sie darf die<br />
Nachbedingungen aber nicht lockern.<br />
- Falls eine abgeleitete Klasse die Nachbedingungen lockern würde, würde diesen<br />
damit wieder ohne Absprache mit den Partnern des Kontrakts mehr geboten als<br />
vorher.<br />
- Erlaubte und verbotene Maßnahmen (unvollständig):<br />
Der Wertebereich der Rückgabeergebnisse wird eingeschränkt.<br />
Der Rückgabetyp ist ein Objekt der abgeleiteten Klasse A (A erbt von B),<br />
während die Methode der Basisklasse ein Objekt einer Basisklasse B zurückgibt.<br />
Der Wertebereich der Rückgabeergebnisse wird erweitert.<br />
Der Rückgabetyp ist ein Objekt der Basisklasse B, während die Methode der<br />
Basisklasse ein Objekt einer abgeleiteten Klasse A (A erbt von B) zurückgibt.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 169
Überschreiben von Methoden<br />
Regeln<br />
<br />
Invarianten:<br />
- Eine abgeleitete Klasse muss dafür sorgen, dass die für die Basisklasse definierten<br />
Invarianten immer gelten. Sie darf die Invarianten verschärfen.<br />
- Die Partner des Kontrakts müssen sich auf die zugesicherten Invarianten verlassen<br />
können.<br />
- Eine Verhaltensänderung darf eintreten.<br />
Ergebnis: Design by Contract<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 170
Überschreiben von Methoden<br />
Regeln<br />
• Beispiel für die Verletzung der Ersetzbarkeit:<br />
context Rectangle::scaleX(factor: float)<br />
pre: factor > 0<br />
post: (lengthX = lengthX@pre * factor<br />
and lengthY = lengthY@pre)<br />
context Square<br />
inv: lengthX = lengthY<br />
+display()<br />
Figure<br />
Rectangle<br />
-lengthX: int<br />
-lengthY: int<br />
+display()<br />
+scaleX(factor: double)<br />
+scaleY(factor: double)<br />
Square<br />
Ersetzbarkeit verletzt:<br />
Neue Einschränkung<br />
der Längen in der<br />
Invariante des<br />
Quadrates!<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 171
Überschreiben von Methoden<br />
Regeln<br />
• Beispiel für die Einhaltung der Ersetzbarkeit:<br />
context Account::withdraw<br />
pre: amount > 0 and amount 0<br />
and amount
Überschreiben von Methoden<br />
Regeln<br />
• Implementierung des Kontobeispiels:<br />
public class Account {<br />
private int balance = 0;<br />
}<br />
public int getBalance() {<br />
return balance;<br />
}<br />
public void withdraw(int amount) {<br />
assert amount > 0<br />
&& amount 0<br />
&& amount
Überschreiben von Methoden<br />
Regeln<br />
• Verwendung des Kontobeispiels:<br />
CreditAccount account1 = new CreditAccount(10000);<br />
Account account2 = new Account();<br />
// Abheben<br />
bank.withdraw(account1);<br />
bank.withdraw(account2);<br />
// Methode zum Abheben eines Festbetrags<br />
// account verweist auf Account oder CreditAccount<br />
public void withdraw(Account accountPtr) {<br />
if (accountPtr.getBalance() >= 200)<br />
accountPtr.withdraw(200);<br />
}<br />
• Wichtig: In der Methode withdraw sind Vor- und Nachbedingung sowie Invariante nur<br />
anhand der Klasse Account erkennbar!<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 174
Überschreiben von Methoden<br />
Regeln<br />
• Beispiel für die Verletzung der Ersetzbarkeit (Einschränkung der Vorbedingung):<br />
context Account::transfer<br />
pre: amount > 0 and amount
Überschreiben von Methoden<br />
Regeln<br />
• Implementierung des Kontobeispiels (unvollständig):<br />
public class Account {<br />
private int balance = 0;<br />
private int creditLimit = 0;<br />
public class DepositAccount extends<br />
Account {<br />
}<br />
public int getBalance() {<br />
return balance;<br />
}<br />
public void transfer(int amount,<br />
Account dest) {<br />
assert amount > 0<br />
&& amount 0;<br />
balance += amount;<br />
}<br />
}<br />
@Override<br />
public void transfer(int amount,<br />
Account dest) {<br />
assert false;<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 176
Überschreiben von Methoden<br />
Regeln<br />
• Verwendung des Kontobeispiels:<br />
DepositAccount account1 = new DepositAccount();<br />
Account account2 = new Account();<br />
// Überweisen<br />
bank.transfer(account1, account2);<br />
bank.transfer(account2, account1);<br />
// Methode zum Überweisen eines Festbetrags<br />
public void transfer(Account dest, Account source) {<br />
if (source.getBalance() + source.getCreditLimit() >= 200)<br />
source.transfer(200, dest);<br />
}<br />
• Wichtig: In der Methode transfer berücksichtigt die Vorbedingung der Klasse Account.<br />
DepositAccount schränkt diese aber ein Methode transfer kann nicht richtig<br />
funktionieren.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 177
Überschreiben von Methoden<br />
Regeln<br />
• Problem: Die Kontraktverletzungen werden erst zur Laufzeit entdeckt vollständige Test<br />
erforderlich.<br />
• Lösung: Spracherweiterungen, die eine Spezifikation der Kontrakte erlauben<br />
• Problem: Prüfungen auf Kontrakteinhaltung müssen manuell in den Code verteilt werden <br />
sehr viel Arbeit.<br />
• Lösung: AOP (Aspect Oriented Programming) kommt später<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 178
Überschreiben von Methoden<br />
Regeln<br />
• Wie können Kontrakte angegeben werden?<br />
<br />
<br />
<br />
in UML mit OCL<br />
im Quelltext mit Assertions (auch mit Hilfe von AOP)<br />
Es gibt Erweiterungen objektorientierter Sprachen um Constraints, Auswahl:<br />
jContractor (http://jcontractor.sourceforge.net/),<br />
C4J (http://c4j.sourceforge.net/),<br />
COFOJA (http://code.google.com/p/cofoja)<br />
• Wie sieht es bei Schnittstellen oder abstrakten Klassen aus? Dort gibt es keine<br />
Implementierung!<br />
in UML mit OCL spezifizieren<br />
im Quelltext dokumentieren<br />
Constraint-Erweiterung verwenden<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 179
Überschreiben von Methoden<br />
Kovarianz und Kontravarianz<br />
Genauerer Blick auf die Vererbung bei Methodenparametern und Rückgabetypen<br />
• Kovariante Rückgabetypen in der clone-Methode: Der Rückgabetyp in der abgeleiteten<br />
Klasse erbt vom Rückgabetyp der Basisklasse<br />
Figure<br />
-x: int<br />
-y: int<br />
+clone(): Figure<br />
Ghost<br />
Die Klasse T2 ist der Klasse T1 kovariant,<br />
wenn alle Objekte von T2 gleichzeitig<br />
Objekte von T1 sind.<br />
Einfacher gesagt: T2 muss entweder T1<br />
oder eine abgeleitete Klasse sein.<br />
+clone(): Ghost<br />
<br />
<br />
<br />
Einschränkung der Nachbedingung in dieser Form ist erlaubt.<br />
Java unterstützt seit Version 5 kovariante Rückgabetypen.<br />
C++ hat kovariante Rückgabetypen im Standard definiert. Allerdings unterstützen nicht<br />
alle Compiler dieses Sprachmittel.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 180
Überschreiben von Methoden<br />
Kovarianz und Kontravarianz<br />
• Kovariante Übergabetypen in der set-Methode: Der Übergabegabetyp in der abgeleiteten<br />
Klasse erbt vom Übergabegabetyp der Basisklasse<br />
-x: int<br />
-y: int<br />
Figure<br />
+set(f: Figure)<br />
Ghost<br />
+set(g: Ghost)<br />
<br />
<br />
<br />
Die Einschränkung der Vorbedingung ist nicht erlaubt.<br />
Ausweg: In Java und C++ wird die Methode set in Figure gar nicht überschrieben, sie<br />
wird überladen!<br />
Schlussfolgerung: Die Übergabetypen sind nicht kovariant.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 181
Überschreiben von Methoden<br />
Kovarianz und Kontravarianz<br />
• Kontravariante Übergabetypen in der set-Methode: Der Übergabegabetyp in der<br />
abgeleiteten Klasse ist Basisklasse des Übergabetyps der Basisklasse<br />
-x: int<br />
-y: int<br />
Figure<br />
+set(g: Ghost)<br />
Ghost<br />
Die Klasse T2 ist der Klasse T1 kontravariant,<br />
wenn alle Objekte von T1 gleichzeitig<br />
Objekte von T2 sind.<br />
Einfacher gesagt: T1 muss entweder T2<br />
oder seine abgeleitete Klasse sein.<br />
+set(f: Figure)<br />
<br />
<br />
Aufweichung der Vorbedingung ist erlaubt.<br />
Kontravariante Übergabetypen sind erlaubt.<br />
• Kontravariante Rückgabetypen sind nicht erlaubt.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 182
Vererbung<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 183
Vererbung<br />
Vererbung der Implementierung (abstrakte Basisklasse)<br />
Spezialfall der Vererbung: Abstrakte Basisklasse<br />
• Idee: Es gibt keine Objekte der Oberklasse. Alle Objekte der Basisklasse müssen durch<br />
Unterklassenobjekte repräsentiert werden.<br />
• Beispiel: Ein Konto ist entweder ein Girokonto oder ein Sparkonto.<br />
• Es muss eines von beiden sein, kann aber nicht in beiden Klassen gleichzeitig sein.<br />
• Pacman-Beispiel: Es gibt keine Objekte der Basisklasse Figure.<br />
Figure<br />
kursiv<br />
Ghost<br />
Pacman<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 184
Vererbung<br />
Vererbung der Implementierung (abstrakte Basisklasse)<br />
• Klassen werden mit dem Schlüsselwort abstract als abstrakt markiert, um zu verhindern,<br />
dass ein Objekt solcher Klasse erzeugt wird.<br />
• Beispiel: Figure, von dem keine Objekte erzeugt werden dürfen.<br />
public abstract class Figure {<br />
private int xPos;<br />
private int yPos;<br />
}<br />
public void handleCollisionWith(Figure other){<br />
// ...<br />
}<br />
public class Pacman extends Figure {<br />
private boolean mouthOpening;<br />
}<br />
@Override<br />
public void handleCollisionWith(Figure other) {<br />
// ...<br />
}<br />
// ...<br />
Überschreiben bzw.<br />
implementieren der Methode<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 185
Vererbung<br />
Vererbung der Implementierung (abstrakte Basisklasse)<br />
• Auch Methoden können abstrakt sein:<br />
<br />
<br />
<br />
Die Basisklasse kann z.B. keine sinnvolle gemeinsame Implementierung anbieten.<br />
Die abgeleiteten Klassen müssen die Methoden dann implementieren.<br />
Ein Klasse mit mindestens einer abstrakten Methode ist abstrakt.<br />
• Beispiel: Figure ohne Implementierung des Zeichnens<br />
public abstract class Figure {<br />
private boolean dead;<br />
}<br />
public abstract void paint(JComponent panel);<br />
// ...<br />
keine Implementierung<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 186
Vererbung<br />
Vererbung der Spezifikation (Schnittstellen)<br />
• Für die Vererbung einer Spezifikation gibt es in Java Schnittstellen (interface).<br />
• Es werden nur Methodensignaturen und statische Attribute angeboten, ohne irgendwelche<br />
Implementierungsdetails bekannt zugeben.<br />
• Beispiel: Schnittstelle Runnable aus dem JDK<br />
public interface Runnable {<br />
void run();<br />
}<br />
• Alle Methoden sind public (nicht angegeben).<br />
• Alle Attribute sind public, static und final<br />
(nicht angegeben).<br />
• Implementierung einer Schnittstelle:<br />
public class Figure implements Runnable {<br />
@Override<br />
public void run() { /* ... */ }<br />
}<br />
<br />
Runnable<br />
+run()<br />
Figure<br />
-xPos: int<br />
-yPos: int<br />
+run()<br />
• Eine Klasse darf beliebig viele Schnittstellen direkt implementieren (die Schnittstellen werden<br />
mit Kommata getrennt aufgeführt).<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 187
Vererbung<br />
Beispiel: „Pacman“<br />
• Ziel: Klassenhierarchie für das Zeichenprogramm oder Pacman-Figuren<br />
• Die Algorithmen des Programms sollen auch mit noch „unbekannten“ Figuren funktionieren<br />
Erweiterbarkeit!<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 188
Generische Klassen<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 189
Generische Klassen<br />
Definition: Generische Klasse<br />
Eine generische Klasse ist eine mit formalen generischen Parametern versehene Schablone.<br />
Erst durch die Verwendung der Klasse werden die Parameter durch konkrete Klassen ersetzt.<br />
So kann zur Übersetzungszeit eine höhere Typsicherheit sichergestellt werden.<br />
Darstellung mit UML:<br />
TemplateKlasse<br />
T: class Parametertyp<br />
Parametername<br />
• Parameteraufbau: Parameter-Name[:Parameter-Typ][=Vorgabewert]<br />
<br />
<br />
<br />
Parameter-Name: Name des Platzhalters<br />
Parameter-Typ: Optionale Klasse des Parameters. Ist kein Typ angegeben, kann jede<br />
beliebige Klasse class verwendet werden.<br />
Vorgabewert: Standardwert, falls die Typangabe fehlt<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 190
Generische Klassen<br />
Vektor (Version 3)<br />
• Vektor als generische Klasse:<br />
public class Vector {<br />
private E[] values;<br />
@SuppressWarnings("unchecked")<br />
public Vector(int size, E initValue) {<br />
values = (E[]) new Object[ size ];<br />
for (int i = 0; i < size; ++i) {<br />
values[ i ] = initValue;<br />
}<br />
}<br />
public void setValue(int index, E value) {<br />
values[ index ] = value;<br />
}<br />
Vector<br />
- values: E[*] {bag}<br />
+ Vector(size: int, initValue: E)<br />
+ setValue(index: int, value: E)<br />
+ getValue(index: int): E<br />
E: class<br />
}<br />
public E getValue(int index) {<br />
return values[ index ];<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 191
Generische Klassen<br />
• Anmerkungen:<br />
<br />
<br />
<br />
<br />
<br />
public class Vector: ist der Platzhalter für eine Klasse.<br />
Der Platzhalter steht immer für den Namen einer Klasse oder Schnittstelle:<br />
- Primitive Datentypen werden nicht unterstützt.<br />
- Intern speichert die Klasse Referenzen vom Typ Object ab.<br />
- Der Platzhalter dient zum typsicheren Zugriff, der zur Übersetzungszeit geprüft<br />
werden kann.<br />
- Der Platzhaltertyp kann fast wie ein normaler Datentyp innerhalb der Klasse<br />
verwendet werden. Ausnahmen: Objekterzeugung, Arrays<br />
Der cast-Operator im Konstruktor ist nicht geprüft. Deshalb wird die Warnung des<br />
Compilers mit @SuppressWarnings("unchecked") unterdrückt.<br />
In Java können keine Arrays mit generischen Typen angelegt werden. Deshalb erzeugt<br />
der Vektor Object-Arrays kommt noch genauer.<br />
Es dürfen mehrere Platzhalter verwendet werden. Beispiel:<br />
public class HashMap { /* … */ }<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 192
Generische Klassen<br />
• Eine konkrete Instanz einer generischen Klasse wird durch die folgende Schreibweise<br />
erzeugt: Klasse<br />
• Beispiel:<br />
Vector vector1 = new Vector(3, 0.0);<br />
Kann anhand des Typs der Referenz erkannt werden.<br />
• Beispiel (der Compiler stellt sicher, dass die rot markierten Elemente vom Typ Double bzw.<br />
double sind):<br />
Vector v1 = new Vector(3, 0.0);<br />
v1.setValue(0, 2.0);<br />
double value = v1.getValue();<br />
System.out.println(value);<br />
• Beispiel ohne generische Klasse (der Compiler kann keine Typprüfung vornehmen):<br />
Vector v1 = new Vector(3, 0.0);<br />
v1.setValue(0, 2.0);<br />
Double value = (Double) v1.getValue();<br />
System.out.println(value);<br />
Falsche Werte (z.B. String) werden zur Laufzeit bemerkt (ClassCastException).<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 193
Generische Klassen<br />
Umsetzung in der virtuellen Maschine<br />
• Generische Klassen wurden erst mit Java 5 eingeführt.<br />
• Ziel war es, den Bytecode zu Java 1.4 kompatibel zu halten.<br />
• Wie lassen sich generische Klassen implementieren?<br />
<br />
heterogen: Für jeden Typparameter wird eine neue Klasse erzeugt (C++-Ansatz).<br />
homogen: Es wird nur eine Klasse erzeugt. Der Typparameter wird durch die oberste<br />
Basisklasse Object ersetzt. Die Typparameter dienen nur zur Prüfung während der<br />
Übersetzungszeit (Java-Ansatz).<br />
• Der Compiler löscht also die Typ-Informationen („type erasure“):<br />
Der Bytecode bleibt kompatibel zu Java 1.4.<br />
Die generischen Typen existieren nicht mehr zur Laufzeit führt zu Problemen:<br />
Vector v1 = new Vector();<br />
if (v1 instanceof Vector) // Compilerfehler, da Vector zur<br />
// Laufzeit nicht existiert!<br />
Korrekt wäre:<br />
Vector v1 = new Vector();<br />
if (v1 instanceof Vector) // Vector existiert<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 194
Generische Klassen<br />
Umsetzung in der virtuellen Maschine<br />
<br />
Damit sind die Klassen trotz unterschiedlicher Typparameter identisch:<br />
Vector v1 = new Vector();<br />
Vector v2 = new Vector();<br />
if (v1.getClass() == v2.getClass()) // true<br />
• Generische Klassen lassen sich auch ohne Typparameter verwenden („raw type“):<br />
Vector v1 = new Vector();<br />
Vector v2 = new Vector();<br />
Die Verwendung führt aber z.B. bei setValue zu einer Compiler-Warnung.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 195
Generische Klassen<br />
Umsetzung in der virtuellen Maschine<br />
• Beispiel für die Umsetzung anhand des Vektors (Ausschnitt):<br />
Definition im Quelltext<br />
public class Vector {<br />
private E[] values;<br />
Definition zur Laufzeit („fiktiv“)<br />
public class Vector {<br />
private Object[] values;<br />
// ...<br />
// ...<br />
public void setValue(int index, E value) {<br />
values[ index ] = value;<br />
}<br />
public void setValue(int index, Object value) {<br />
values[ index ] = value;<br />
}<br />
}<br />
public E getValue(int index) {<br />
return values[ index ];<br />
}<br />
}<br />
public Object getValue(int index) {<br />
return values[ index ];<br />
}<br />
Verwendung im Quelltext<br />
Vector names = new Vector();<br />
names.setValue(0, "Vogelsang");<br />
String name = names.getValue(0);<br />
Verwendung zur Laufzeit („fiktiv“)<br />
Vector names = new Vector();<br />
names.setValue(0, "Vogelsang");<br />
String name = (String) names.getValue(0);<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 196
Generische Klassen<br />
Arrays<br />
• Arrays mit generischen Typen haben einige Besonderheiten:<br />
<br />
<br />
Die Deklaration ist problemlos möglich:<br />
private ArrayList[] al;<br />
Aber eine Initialisierung klappt nicht intuitiv:<br />
private ArrayList[] al = new ArrayList[ 10 ];<br />
// Compilerfehler<br />
• Lösungen:<br />
Verwendung des Platzhalters ?:<br />
<br />
private ArrayList[] al<br />
= (ArrayList[]) new ArrayList[ 10 ];<br />
Erstellen einer Klasse für den Inhalt der Arrayzellen:<br />
public class MyList extends ArrayList {<br />
// notwendige Konstruktoren<br />
}<br />
private MyList[] al = new MyList[ 10 ];<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 197
Generische Methoden<br />
• „Normale“ (nicht-generische) und generische Klassen dürfen generische Methoden besitzen.<br />
• Das wird häufig bei Hilfsklassen mit statischen Methoden eingesetzt:<br />
• Beispiel: Methode asArrayList erzeugt aus einer variablen Anzahl Übergabewerte eine<br />
ArrayList (angelehnt an Klasse Arrays aus dem SDK)<br />
public class Arrays {<br />
@SafeVarargs<br />
public static ArrayList asArrayList(T... a) {<br />
ArrayList result = new ArrayList(a.length);<br />
for (int i = 0; i < a.length; ++i) {<br />
result.add(a[ i ]);<br />
}<br />
return result;<br />
}<br />
}<br />
• Syntax: Zugriffsrecht Rückgabetyp Methodenname(Parameter)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 198
Generische Methoden<br />
Einschränkungen der Parametertypen<br />
• Die Typparameter lassen sich einschränken:<br />
Basisklasse: Der Parametertyp muss von einer bestimmten oder mehreren Basisklassen<br />
erben.<br />
Schnittstellen: Der Parametertyp muss eine bestimmte oder mehrere Schnittstellen<br />
implementieren.<br />
• Beispiel, in dem der Vektor nur mit Klassen, die von Number erben, verwendet werden darf<br />
(weil der Vektor z.B. Zahlenoperationen durchführt), Vektor Version 4:<br />
public class Vector {<br />
private Number[] values;<br />
}<br />
public double getSum() { // Summe alle Werte ermitteln<br />
double sum = 0.0;<br />
for (int i = 0; i < values.length; ++i) {<br />
sum += values[ i ].doubleValue();<br />
}<br />
return sum;<br />
}<br />
// ...<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML<br />
199
Generische Methoden<br />
Einschränkungen der Parametertypen<br />
• Es können auch mehrere Einschränkungen vorhanden sein.<br />
• Bespiel: Der Typparameter des Vektors muss von Number erben und Cloneable<br />
implementieren:<br />
public class Vector<br />
• Syntax bei mehr als zwei Einschränkungen:<br />
public class Klasse<br />
• Achtung bei Vererbung:<br />
Vector ist keine Basisklasse von Vector!<br />
Vector v1 = new Vector(); // Compilerfehler!<br />
Ansonsten ließe sich z.B. ein String in dem Vektor speichern.<br />
Die Methode<br />
public void dump(Vector v1)<br />
darf nicht mit einem Vector aufgerufen werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 200
Generische Methoden<br />
Parametertypen und Vererbung<br />
• Ausweg: Wildcards erlauben es, einen Typ unbestimmt zu lassen. Beispiel:<br />
public void dump(Vector v1)<br />
<br />
<br />
? ist ein unbekannter Typ, nicht Object.<br />
Die Methode dump darf jetzt mit jedem beliebigen Typparameter verwendet werden.<br />
• Wildcards unterstützen auch Typeinschränkungen („upper bound wildcards“):<br />
public void dump(Vector
Aufzähltypen<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 202
Aufzähltypen<br />
Einführung<br />
• Ein Aufzähltyp ist eine spezielle Klasse, von der benannte Objekte erzeugt werden.<br />
Beispiel für die Bewegungsrichtungen von Figuren in Pacman:<br />
public enum Direction {<br />
NONE, UP, DOWN, LEFT, RIGHT;<br />
}<br />
• Daraus erzeugt der Compiler eine Klasse, die ungefähr so aussieht:<br />
public class Direction extends Enum {<br />
public static final Direction NONE = new Direction("NONE", 0);<br />
public static final Direction UP = new Direction("UP", 1);<br />
public static final Direction DOWN = new Direction("DOWN", 2);<br />
public static final Direction LEFT = new Direction("LEFT", 3);<br />
public static final Direction RIGHT = new Direction("RIGHT", 4);<br />
<br />
Direction<br />
NONE<br />
UP<br />
DOWN<br />
LEFT<br />
RIGHT<br />
private Direction(String name, int index) {<br />
super(name, index);<br />
}<br />
// Alle Werte ermitteln<br />
public static Direction[] values() { /* ... */ }<br />
}<br />
// weitere Methoden ...<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 203
Aufzähltypen<br />
Einführung<br />
• Vorteil von Aufzähltypen gegenüber finalen int-Werten:<br />
<br />
<br />
<br />
In einem switch-Block kann der Compiler testen, ob alle Werte eines Typs einen case-<br />
Block haben.<br />
Der Benutzer kann anhand des Typs dessen Bedeutung erkennen.<br />
Der Typ kann nur die erlaubten Werte annehmen.<br />
• Was bietet die Basisklasse Enum noch (Auswahl)?<br />
<br />
<br />
<br />
public String name(): Name des Aufzählwertes (z.B. "LEFT")<br />
Beispiel: String name = Direction.LEFT.name();<br />
public ordinal(): Index eines Wertes in der Aufzählung (z.B. 3 für der Wert<br />
Direction.LEFT, weil LEFT als dritter Wert angegeben ist)<br />
Beispiel: int index = Direction.LEFT.ordinal();<br />
public static valueOf(Class enumType,<br />
String name): Ermittelt aus dem Namen den Aufzählwert<br />
Beispiel: Direction dir = Enum.valueOf(Direction.class, "UP");<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 204
Aufzähltypen<br />
Einführung<br />
• Ein Aufzähltyp kann in Pacman für zwei Aufgaben eingesetzt werden:<br />
<br />
<br />
Richtung, in die sich eine Figur bewegt<br />
public enum Direction {<br />
NONE, UP, DOWN, LEFT, RIGHT;<br />
}<br />
Position einer Zelle, an der sich ein Rahmen befindet.<br />
- Problem: Eine Zelle kann an mehr als einer Position einen Rahmen haben.<br />
- Lösung: Bitkombination als zusätzlichen Wert dem Aufzähltyp übergeben ersetzt<br />
nicht den Index (Aufruf ordinal()).<br />
public enum Direction { // noch unvollständig<br />
NONE(0), UP(1), DOWN(2), LEFT(4), RIGHT(8), ALL(15);<br />
}<br />
• Die zweite Variante wird auch für die Richtung verwendet, wobei ALL unsinnig ist.<br />
• Beispiele:<br />
LEFT | UP | DOWN<br />
RIGHT<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 205
Aufzähltypen<br />
Methoden und Attribute<br />
• Wie funktioniert die Übergabe zusätzlicher Parameter an einen Aufzählwert genau? Dieses<br />
Beispiel ergibt Übersetzungsfehler, weil der entsprechende Konstruktor fehlt:<br />
public enum Direction {<br />
NONE(0), UP(1), DOWN(2), LEFT(4), RIGHT(8), ALL(15);<br />
}<br />
• Aufzähltypen dürfen zusätzliche Konstruktoren, Attribute und Methoden erhalten:<br />
public enum Direction {<br />
NONE(0), UP(1), DOWN(2), LEFT(4), RIGHT(8), ALL(15);<br />
private int value;<br />
protected Direction(int value) {<br />
this.value = value<br />
}<br />
Konstruktoraufruf<br />
public int getValue() {<br />
return value;<br />
}<br />
}<br />
// weitere Methoden<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 206
Aufzähltypen<br />
Methoden und Attribute<br />
• Aufzähltypen dürfen auch Schnittstellen implementieren.<br />
• Sie können aber nicht von Klassen erben, weil sie intern bereits Enum als Basisklasse<br />
besitzen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 207
Regeln und Hinweise<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 208
Regeln und Hinweise<br />
Wichtige Methoden und Operatoren einer Java-Klasse<br />
• Welche Methoden und Operatoren haben eine besondere Bedeutung (kleine Auswahl, hier<br />
anhand der Klasse Ghost)?<br />
Ghost()<br />
Methode/Operator<br />
protected void finalize()<br />
public boolean<br />
equals(Object s)<br />
public String toString()<br />
Bedeutung<br />
Standardkonstruktor. Wird immer dann automatisch<br />
erzeugt, wenn kein eigener Konstruktor geschrieben<br />
wurde.<br />
Wird aufgerufen, bevor das Objekt gelöscht wird.<br />
Kommt noch…<br />
Wird aufgerufen, wenn eine String-Darstellung des<br />
Objektes benötigt wird.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 209
Regeln und Hinweise<br />
Wichtige Methoden und Operatoren einer Java-Klasse<br />
• Identität und Gleichheit zweier Objekte (hier anhand der Klasse Ghost):<br />
Methode/Operator<br />
Ghost gh1 = new Ghost();<br />
Ghost gh2 = new Ghost ();<br />
if (gh1.equals(gh2))<br />
Ghost gh1 = new Ghost ();<br />
Ghost gh2 = new Ghost ();<br />
if (gh1 == gh2)<br />
Bedeutung<br />
Inhaltlicher Vergleich der Objekte. Dazu sollte<br />
die Methode equals der Klasse Ghost<br />
überschrieben werden.<br />
Identität der Objekte. Dazu werden die<br />
Referenzen auf die Objekte verglichen. Sind<br />
diese identisch, so handelt es sich um dasselbe<br />
Objekt.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 210
Regeln und Hinweise<br />
Wichtige Methoden und Operatoren – Vergleich von Objekten<br />
• Bedingungen für die Gleichheit zweier Objekte:<br />
Die Gleichheitsprüfung ist reflexiv: A ist gleich A.<br />
Die Gleichheitsprüfung ist symmetrisch: A ist gleich B ==> B ist gleich A.<br />
Die Gleichheitsprüfung ist transitiv: A ist gleich B und B ist gleich C ==> A ist gleich C.<br />
• Jede Implementierung muss diese Bedingungen einhalten!<br />
• Problem: Wie sieht der Vergleich bei Vererbung aus?<br />
-xPos: int<br />
-yPos: int<br />
Figure<br />
Die equals-Methode vergleicht<br />
die Positionen der Figuren<br />
+equals(o: Object): boolean<br />
Ghost<br />
-dangerous: boolean<br />
+equals(o: Object): boolean<br />
Die equals-Methode vergleicht<br />
die Positionen und die<br />
Gefährlichkeit der Geister<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 211
Regeln und Hinweise<br />
Wichtige Methoden und Operatoren – Vergleich von Objekten<br />
• Ohne Beweis: Der Vergleich von Objekten unterschiedlicher Klassen führt zur Verletzung<br />
mindestens einer Regeln.<br />
• Konsequenz: Nur Objekte identischer Klassen werden überhaupt auf Gleichheit überprüft.<br />
• Beispiel:<br />
public class Figure {<br />
private int xPos;<br />
private int yPos;<br />
// ...<br />
@Override<br />
public boolean equals(Object o) {<br />
if (o != null &&<br />
o.getClass() == getClass()) {<br />
Figure f = (Figure) o;<br />
return xPos == f.xPos<br />
&& yPos == f.yPos;<br />
}<br />
return false;<br />
}<br />
}<br />
public class Ghost extends Figure {<br />
private boolean dangerous;<br />
// ...<br />
@Override<br />
public boolean equals(Object o) {<br />
return super.equals(o) &&<br />
((Ghost) o).dangerous == dangerous;<br />
}<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 212
Regeln und Hinweise<br />
Wichtige Methoden und Operatoren – Vergleich von Objekten<br />
• Erklärung des Beispiels:<br />
<br />
<br />
<br />
Die Basisklasse Figure testet mit getClass() zunächst auf identische Klassen.<br />
Nur dann werden die Attribute vergleichen.<br />
Die abgeleitete Klasse Ghost lässt die Basisklasse die Gleichheit feststellen und prüft<br />
dann das zusätzliche Attribut.<br />
• Anmerkung:<br />
<br />
<br />
In der Praxis ist es manchmal auch sinnvoll, nur die Basisklasse ohne Test auf<br />
Klassengleichheit die Prüfung vornehmen zu lassen hängt von der Aufgabe ab.<br />
Dann können eine Figur und ein Geist gleich sein!<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 213
Regeln und Hinweise<br />
Probleme bei Vererbung – Instabile Basisklasse<br />
• Und noch etwas gibt es bei Vererbung zu beachten, Beispiel:<br />
<br />
<br />
<br />
Die Klasse LoggingVector erbt von der Basisklasse Vector (Vererbung der<br />
Implementierung).<br />
LoggingVector protokolliert zusätzlich alle Aktionen von Vector.<br />
Die Methode clear wird nicht überschrieben, weil sie intern setValue aufruft.<br />
Vector<br />
E: class<br />
-values: E[*]<br />
+Vector(size: int)<br />
+setValue(index: int, value: E)<br />
+getValue(index: int): E<br />
+clear()<br />
public void clear() {<br />
for (int i = 0; i < values.length; i++)<br />
setValue(null, i);<br />
}<br />
LoggingVector<br />
+LoggingVector(size: int)<br />
+setValue(index: int: value: E)<br />
+getValue(index: int): E<br />
E: class<br />
setValue und getValue protokollieren die<br />
Aktion und rufen die Methoden der<br />
Basisklasse auf.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 214
Regeln und Hinweise<br />
Probleme bei Vererbung – Instabile Basisklasse<br />
• Wo ist jetzt das Problem?<br />
• Eine Änderung an der Basisklasse führt dazu, dass die abgeleitete Klasse nicht mehr korrekt<br />
funktioniert.<br />
-values: E[*]<br />
Vector<br />
+Vector(size: int)<br />
+setValue(index: int, value: E)<br />
+getValue(index: int): E<br />
+clear()<br />
kein Aufruf<br />
E: class<br />
Kein Aufruf von setValue mehr<br />
public void clear() {<br />
for (int i = 0; i < values.length; i++)<br />
values[ i ] = null;<br />
}<br />
LoggingVector<br />
+LoggingVector(size: int)<br />
+setValue(index: int, value: E)<br />
+getValue(index: int): E<br />
E: class<br />
setValue und getValue protokollieren die<br />
Aktion und rufen die Methoden der<br />
Basisklasse auf.<br />
• Beim Aufruf von clear erfolgt kein Logging mehr!<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 215
Regeln und Hinweise<br />
Probleme bei Vererbung – Instabile Basisklasse<br />
• Problem der instabilen Basisklassen (Fragile Base Class Problem):<br />
Anpassungen an einer Basisklasse führen zu unerwartetem Verhalten von abgeleiteten<br />
Klassen.<br />
Konsequenz: Anpassungen an Basisklassen können häufig nicht vorgenommen werden,<br />
ohne den Kontext der abgeleiteten Klassen mit einzubeziehen.<br />
Problem: Die Wartung objektorientierter Systeme, die häufig die Vererbung der<br />
Implementierung nutzen, wird stark erschwert.<br />
Konsequenz: Vererbung der Implementierung darf nicht eingesetzt wird, wenn spätere<br />
Änderungen an den Basisklassen wahrscheinlich sind.<br />
Ziel: Reine Vererbung der Spezifikation. Die Vermeidung von Redundanzen, kann auch<br />
über Delegationsbeziehungen erreicht werden.<br />
• Anmerkung: Wenn die abgeleitete Klasse sich exakt an die Spezifikation der Basisklasse hält<br />
und die Spezifikation später auch nicht verändert wird, ist das Erben einer Implementierung<br />
problemlos möglich.<br />
• In der Praxis: Niemand spezifiziert das Verhalten exakt…<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 216
Regeln und Hinweise<br />
Probleme bei Vererbung – Instabile Basisklasse<br />
• Lösung mit Delegation:<br />
<br />
VectorInterface<br />
E: class<br />
+setValue(index: int, value: T)<br />
+getValue(): E<br />
+clear()<br />
-values: E[*]<br />
-size: int<br />
Vector<br />
+Vector(size: int)<br />
+setValue(index: int, value: E)<br />
+getValue(index: int): E<br />
+clear()<br />
E: class E: class<br />
LoggingVector<br />
+LoggingVector(size: int)<br />
+setValue(index: int, value: E)<br />
+getValue(index: int): E<br />
+clear()<br />
LoggingVector delegiert die<br />
Aufrufe an Vector weiter,<br />
nachdem die Log-Ausgaben<br />
erfolgt sind.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 217
Regeln und Hinweise<br />
Probleme bei Vererbung – Instabile Basisklasse<br />
• Unvollständige Implementierung des Beispiels:<br />
public class LoggingVector implements VectorInterface {<br />
private Vector vector;<br />
}<br />
public LoggingVector(int size) {<br />
vector = new Vector(size);<br />
}<br />
@Override<br />
public void setValue(int index, E value) {<br />
// Log-Ausgaben, z.B. hier vereinfacht auf dem Bildschirm<br />
System.out.println("Neuer Wert " + value + " an Position " + index + " im Vektor");<br />
vector.setValue(value, index);<br />
}<br />
// usw.<br />
• Änderungen an der Implementierung von Vector beeinflussen nicht die Funktionsfähigkeit<br />
von LoggingVector.<br />
• Neue Methoden im Vector müssen auch in der Schnittstelle deklariert werden können so<br />
nicht in LoggingVector vergessen werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 218
Regeln und Hinweise<br />
Probleme bei Vererbung – Instabile Basisklasse<br />
• Fazit:<br />
<br />
<br />
<br />
Vererbung der Spezifikation ist sicherer in Bezug auf Änderungen.<br />
Vererbung der Implementierung erfordert häufig weniger Code teilweise aber<br />
automatisch generierbar (z.B. in Eclipse).<br />
Wenn sich Vererbung der Spezifikation leicht umsetzen lässt, ist diese Form der<br />
Vererbung vorzuziehen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 219
Klassendiagramme<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 220
Klassendiagramme<br />
Übersicht<br />
Einführung in Java und UML<br />
Arbeitsschritte und Software<br />
Imperative Aspekte<br />
Objektorientierte Programmierung<br />
Referenzen und dynamische<br />
Speicherverwaltung<br />
Vererbung<br />
Generische Klassen und Methoden<br />
Aufzähltypen<br />
Regeln und Hinweise<br />
Klassendiagramme<br />
Fehlerbehandlung mit Ausnahmen<br />
Pakete<br />
Annotationen<br />
Laufzeit-Typinformationen<br />
Ein- und Ausgabe<br />
Grafische Oberflächen und<br />
Animationen mit JavaFX<br />
Datenstrukturen<br />
Objektorientierter Entwurf<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 221
Klassendiagramme<br />
Modellierungswerkzeuge<br />
Leicht verfügbare Modellierungswerkzeuge<br />
• Visual Paradigm for UML<br />
<br />
<br />
<br />
• UML Lab<br />
<br />
<br />
Frei verfügbare Community-Edition, Lizenz für die Professional-Edition im Ilias<br />
http://www.visual-paradigm.com/<br />
keine Code-Erzeugung in der Community-Edition<br />
Lizenz für die Academic-Edition im Ilias<br />
http://www.uml-lab.com/de/download/<br />
• ArgoUML<br />
Open Source, nur UML 1.4<br />
<br />
<br />
<br />
http://argouml.tigris.org/<br />
Start ohne lokale Installation:<br />
http://argouml-downloads.tigris.org/jws/argouml-latest-stable.jnlp<br />
Code-Erzeugung für Java, C++, PHP, …<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 222
Klassendiagramme<br />
Modellierungswerkzeuge<br />
• Magicdraw<br />
<br />
<br />
<br />
• eUML<br />
<br />
<br />
<br />
Frei verfügbare Community-Edition<br />
http://www.magicdraw.com/<br />
Code-Erzeugung für C++, C# und Java (nicht Community-Edition)<br />
Auch als Open Source verfügbar, Eclipse-Plugin<br />
http://www.soyatec.com/euml2/installation/<br />
Code-Erzeugung nur für Java<br />
• Borland Together<br />
<br />
http://www.borland.com/us/products/together/index.html<br />
Lizenz bei Frau Knodel in LI 136<br />
• Fujaba<br />
<br />
<br />
<br />
Open Source<br />
http://www.fujaba.de/<br />
Code-Erzeugung nur für Java<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 223
Klassendiagramme<br />
Beziehungen zwischen Klassen<br />
Rückblick: Die UML-Darstellung einer Klasse<br />
-number: int<br />
-balance: int<br />
-count: int<br />
Account<br />
+payOff(amount: int)<br />
+transfer(amount: int, number: int)<br />
+payIn(amount:int)<br />
Klassenname<br />
Attribute<br />
statisches Attribut<br />
Operationen<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 224
Klassendiagramme<br />
Beziehungen zwischen Klassen<br />
Definition: Stereotyp<br />
Durch einen Stereotypen wird der Zweck oder die Rolle einer Klasse beschrieben.<br />
Einige vordefinierte Stereotypen:<br />
• : Diese Klasse unterstützt zentrale und wichtige Klassen des Modells <br />
Hilfsklasse.<br />
• : Diese Klasse stellt einen Teil der zentralen Logik der Anwendung dar.<br />
• : eine Schnittstelle (siehe früheres Kapitel)<br />
• : Von dieser Klasse gibt es keine Instanzen. Sie stellt lediglich (statische)<br />
Hilfsmethoden und -attribute zur Verfügung.<br />
• : neuer Datentyp, der nur bestimmte Werte annehmen kann <br />
Aufzähltyp<br />
• Es dürfen auch eigenen Stereotypen erstellt werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 225
Klassendiagramme<br />
Beziehungen zwischen Klassen<br />
Rückblick: Die UML-Darstellung eines Aufzähltyps<br />
• Java-Spezialitäten wie die Initialisierung der Werte durch Konstruktoren sind nicht<br />
vorgesehen.<br />
<br />
Direction<br />
NONE<br />
UP<br />
DOWN<br />
LEFT<br />
RIGHT<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 226
Klassendiagramme<br />
Beziehungen zwischen Klassen: Geschachtelte Klassen<br />
• Klassen dürfen in anderen Klassen deklariert werden.<br />
• Die Schachtelung<br />
<br />
<br />
erlaubt es der inneren Klasse, auf die Daten der äußeren zuzugreifen und<br />
bietet die Möglichkeit, eine Klasse, die im Wesentlichen nur von einer anderen<br />
verwendet wird, auch in dieser zu deklarieren.<br />
Aussen<br />
<br />
Innen<br />
-attribut: int<br />
public class Aussen {<br />
class Innen {<br />
int attribut;<br />
// ...<br />
}<br />
// ...<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 227
Klassendiagramme<br />
Beziehungen zwischen Klassen<br />
• Zwischen Klassen können unterschiedliche Beziehungen bestehen.<br />
• Die Beziehungen lassen sich ja nach Aufgabe in unterschiedliche Kategorien einteilen.<br />
Kategorien in der UML:<br />
• Assoziation<br />
• Aggregation und Komposition („Teil und Ganzes“)<br />
• Vererbung (von einer Spezifikation, von einer Implementierung)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 228
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
Definition: Binäre Assoziation<br />
Eine binäre Assoziation beschreibt die semantische Beziehung zwischen zwei Klassen.<br />
Beispiel:<br />
GameController<br />
Pacman<br />
Assoziation<br />
• Pacman und GameController „kennen“ sich.<br />
• Beide Klassen können auf der jeweils anderen Operationen aufrufen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 229
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Leserichtung (GameController steuert Pacman):<br />
Name der Assoziation<br />
GameController<br />
steuert<br />
Pacman<br />
Leserichtung<br />
• Multiplizität (wie viele Objekte können gleichzeitig an der Beziehung beteiligt sein):<br />
max. Anzahl Controller im Spiel<br />
GameController<br />
1 steuert 1..*<br />
Figure<br />
Der Controller steuert mindestens einen, max. beliebig viele Figuren.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 230
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Rolle (sie beschreibt, welche Funktion/Rolle eine an einer Assoziation beteiligten Klasse<br />
einnimmt):<br />
Grosshaendler<br />
Haendler<br />
-verkaeufer<br />
-kaeufer<br />
-verkaeufer<br />
Sichtbarkeit<br />
der Rolle<br />
Name<br />
der Rolle<br />
-kaeufer<br />
Endkunde<br />
<br />
Zweck einer Rolle:<br />
- Besseres Verständnis der Assoziation<br />
- Name des Attributs in der Implementierung<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 231
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Implementierungsbeispiel, in dem der Name der Rolle den Namen des Attributes ergibt:<br />
public class Haendler {<br />
private ArrayList verkaeufer;<br />
private ArrayList kaeufer;<br />
}<br />
// Methoden usw.<br />
• Im Falle einer automatischen Code-Erzeugung ergeben sich so lesbare Attributnamen im<br />
Quelltext.<br />
• Achtung: Eine Rolle mit privater Sichtbarkeit kann durch Getter- und Setter-Methoden von<br />
„außen“ zugänglich gemacht werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 232
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Eigenschaft (ähnlich wie Eigenschaften von Attributen geben sie Eigenschaften von<br />
Assoziationen nähere Hinweise auf die Umsetzung der Assoziation):<br />
GameController<br />
{ordered}<br />
bearbeitet<br />
Figure<br />
<br />
Eigenschaft<br />
Der Controller benötigt die Figuren in einer bestimmten Reihenfolge (ist in der<br />
Beispielimplementierung aber nicht der Fall).<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 233
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
<br />
Eigenschaftstypen (unvollständig):<br />
- {subsets }: Die Menge der Objekte an diesem<br />
Assoziationsende ist eine Teilmenge der Objekte am Assoziationsende<br />
.<br />
- {union}: Die Menge der Objekte an diesem Assoziationsende ist die Vereinigung<br />
aller seiner subsets-Assoziationsenden.<br />
Beispiel (die Buchbestellung setzt sich aus den bereits gelieferten und den nicht<br />
verfügbaren Büchern zusammen):<br />
Bestellung<br />
geliefert<br />
{subsets bestellt}<br />
Buch<br />
nicht_vorhanden<br />
{subsets bestellt}<br />
/bestellt<br />
{union}<br />
Die Menge bestellt ist aus allen<br />
Teilmengen abgeleitet. Es kommen<br />
keine weiteren Bücher hinzu.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 234
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
- {ordered}: Die so markierten Objekte am Ende der Assoziation liegen sortiert vor.<br />
Duplikate sind nicht erlaubt.<br />
- {bag}: Dasselbe Objekt darf am Ende der Assoziation mehrfach erscheinen.<br />
- {seq} bzw. {sequence}: Das Ende der Assoziation verweist auf eine geordnete<br />
Menge von Objekten. Duplikate sind erlaubt.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 235
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Einschränkung (Teilnahme eines Objektes an einer Assoziation angeben).<br />
<br />
<br />
Einschränkungstypen:<br />
- {or}: Das Objekt muss eine der beiden Assoziationen verwenden.<br />
- {xor}: Das Objekt darf nur eine der beiden Assoziationen verwenden.<br />
- {and}: Das Objekt muss an beiden Assoziationen teilnehmen lässt sich besser<br />
durch Kardinalität 1 ausdrücken.<br />
Beispiel für ein Meilenkonto bei einer Fluggesellschaft:<br />
Meilenkonto<br />
inhaber<br />
Firma<br />
xor<br />
EMail<br />
Ein Meilenkonto<br />
gehört entweder<br />
einer Firma oder<br />
einer Person.<br />
inhaber<br />
Person<br />
or<br />
Anschrift<br />
Eine Person muss<br />
eine EMail-Adresse<br />
oder eine Anschrift<br />
angeben.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 236
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
<br />
Implementierung einer xor-Einschränkung:<br />
- Programmgesteuert überprüfen<br />
- Durch Vererbung und Einführung einer weiteren Klasse:<br />
Meilenkonto<br />
xor<br />
inhaber<br />
Firma<br />
Person<br />
inhaber<br />
Person<br />
Meilenkonto<br />
inhaber<br />
1<br />
JuristischePerson<br />
Firma<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 237
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Navigierbarkeit (erlaubt die Angabe, in welche Richtung eine Assoziation gelesen wird). Es<br />
werden folgende Arten unterstützt:<br />
<br />
Navigierbar: Die Klasse Field kennt die Klasse Pacman am Ende der Assoziation.<br />
Field<br />
Pacman<br />
<br />
Nicht navigierbar: Die Klasse Pacman kennt die Klasse Ghost am Ende der Assoziation<br />
nicht.<br />
Pacman<br />
Ghost<br />
<br />
Unspezifiziert: Es wird keine Aussage über die Navigierbarkeit getroffen. In der Praxis<br />
wird das häufig als navigierbar interpretiert.<br />
GameController<br />
Pacman<br />
<br />
Bidirektionale Navigierbarkeit: Beide Klassen kennen sich gegenseitig und können so<br />
auch jeweils die Methoden des Anderen aufrufen.<br />
GameController<br />
Pacman<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 238
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
<br />
<br />
Verbot der Navigierbarkeit: Beide Klasse dürfen sich nicht kennen. Es besteht zwar eine<br />
logische Beziehung, die aber nicht durch eine Assoziation ausgedrückt werden soll <br />
nicht sehr gebräuchlich.<br />
Ghost<br />
Pacman<br />
Unidirektionale Navigierbarkeit: Die Navigation ist in nur einer Richtung erlaubt.<br />
Field<br />
Pacman<br />
<br />
Teilweise Spezifikation der Navigation: Es ist offen gelassen, ob Pacman auch das Field<br />
kennt.<br />
Field<br />
Pacman<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 239
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Implementierung einer Assoziation:<br />
GameController<br />
-controller -figures<br />
1 controls 1..*<br />
Figure<br />
public class GameController {<br />
private ArrayList figures;<br />
// ...<br />
}<br />
public abstract class Figure {<br />
private GameController controller;<br />
// ...<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 240
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Reflexive Assoziation: Eine Assoziation einer Klasse zu sich selbst, ansonsten handelt es sich<br />
im eine normale Assoziation.<br />
Mitarbeiter<br />
-vorgesetzter<br />
0..1<br />
-untergebener<br />
*<br />
leitet<br />
<br />
<br />
<br />
Der Vorgesetzte hat mindestens einen Untergebenen.<br />
Jeder Untergebene hat maximal einen Vorgesetzten. Jeder Vorgesetzte kann also auch<br />
wieder Mitarbeiter sein.<br />
Implementierungsmöglichkeit:<br />
public class Mitarbeiter {<br />
private Mitarbeiter vorgesetzter;<br />
private ArrayList untergebener;<br />
}<br />
// ...<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 241
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
N-äre Assoziation<br />
Eine n-äre Assoziation ist die allgemeine Form einer Assoziation zwischen n Klassen.<br />
Vorspeise<br />
0..*<br />
Hauptgericht<br />
Dessert<br />
0..* 0..*<br />
Menue<br />
Assoziationsname<br />
• Erklärung des Beispiels:<br />
<br />
Die drei Klassen stehen in einer Beziehung namens Menue.<br />
Nicht jedes Hauptgericht muss in einem Menü vorkommen (Multiplizität 0).<br />
Jedes Hauptgericht kann in beliebig vielen Menüs vorkommen (Multiplizität *).<br />
<br />
Wenn ein Hauptgericht in mindestens einem Menü vorhanden sein muss, würde man<br />
am Hauptgericht die Multiplizität 1..* eintragen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 242
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Wie kann eine n-äre Assoziation implementiert werden?<br />
• Ganz einfach durch Umsetzung in mehrere binäre Assoziationen:<br />
Vorspeise<br />
0..*<br />
Hauptgericht<br />
0..* 0..*<br />
Menue<br />
Dessert<br />
Vorspeise<br />
1<br />
Hauptgericht<br />
1<br />
0..*<br />
Menue<br />
0..* 0..*<br />
1<br />
Dessert<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 243
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Qualifizierte Assoziation:<br />
Eine qualifizierte Assoziation besitzt einen Qualifizierer, der eine Menge von Attributen<br />
besitzt, die das Objekt am anderen Ende der Assoziation eindeutig referenziert.<br />
Eine qualifizierte Assoziation ist nur für binäre Assoziationen definiert.<br />
• Beispiel:<br />
<br />
<br />
Jeder Mitarbeiter in einer Firma wird über seine Personalausweisnummer eindeutig<br />
identifiziert. Nicht zu jeder Ausweisnummer gibt es einen Mitarbeiter (Multiplizität<br />
0..1).<br />
Ein Mitarbeiter darf für beliebig viele Firmen arbeiten, hat aber in jeder dieselbe<br />
Personalausweisnummer (Multiplizität 1..*).<br />
Firma<br />
persNummer<br />
Lohnzahlung<br />
1..* 0..1<br />
Mitarbeiter<br />
-persNummer: int<br />
Qualifizierer<br />
Qualifizierte<br />
Assoziation<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 244
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Vergleich zu einer normalen Assoziation:<br />
Firma<br />
Lohnzahlung<br />
1..* 1..*<br />
Mitarbeiter<br />
-persNummer: int<br />
n-zu-m-Beziehung<br />
Firma<br />
persNummer<br />
Lohnzahlung<br />
1..* 0..1<br />
Mitarbeiter<br />
-persNummer: int<br />
Die Beziehung zum Mitarbeiter wird genauer<br />
spezifiziert Fremdschlüsselkonzept in<br />
Datenbanken.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 245
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Implementierung einer qualifizierten Assoziation:<br />
public class Mitarbeiter {<br />
private int persNummer;<br />
}<br />
// ...<br />
// persNummer ist der Index im Vektor<br />
public class Firma {<br />
private ArrayList mitarbeiter;<br />
}<br />
// ...<br />
// persNummer ist der Schlüssel in<br />
// einer Hashtabelle oder einem Baum<br />
// (kommen noch...)<br />
public class Firma {<br />
private HashMap<br />
mitarbeiter;<br />
}<br />
// ...<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 246
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Assoziationsklasse: Eine Assoziationsklasse ist eine Assoziation, die neben Attributen auch<br />
Operationen wie bei einer Klasse aufnehmen kann:<br />
<br />
Die Namen der Assoziation und ihrer Klasse müssen identisch sein.<br />
Einsatz: Zusätzliche Attribute können logisch keinem der Enden der Assoziation<br />
zugeordnet werden Ablage in der Assoziationsklasse.<br />
• Beispiel: Die Auftragsnummer kann weder der Firma noch dem Kunden zugeordnet werden.<br />
Firma<br />
Auftrag<br />
1..* 1..*<br />
Kunde<br />
Auftrag<br />
-nummer: int<br />
Assoziationsklasse<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 247
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Implementierung: Weder C++ noch Java kennen Assoziationsklassen Einführung einer<br />
„Zwischenklasse“:<br />
Firma<br />
Auftrag<br />
1..* 1..*<br />
Kunde<br />
Auftrag<br />
-nummer: int<br />
Firma<br />
Auftrag<br />
fuehrtAus<br />
erteilt<br />
-nummer: int<br />
1 1..* 1..* 1<br />
Kunde<br />
• Der Kunde erteilt beliebig viele Aufträge.<br />
• Eine Firma kann beliebig viele Aufträge ausführen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 248
Klassendiagramme<br />
Beziehungen zwischen Klassen: Assoziation<br />
• Implementierung einer Assoziationsklasse:<br />
public class Auftrag {<br />
private int nummer;<br />
private Kunde kunde;<br />
private Firma firma;<br />
}<br />
// ...<br />
public class Firma {<br />
private ArrayList auftraege;<br />
}<br />
// ...<br />
public class Kunde {<br />
private ArrayList auftraege;<br />
}<br />
// ...<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 249
Klassendiagramme<br />
Beziehungen zwischen Klassen: Aggregation<br />
Definition: Aggregation<br />
Eine Aggregation ist eine spezielle Form einer binären Assoziation. Sie beschreibt eine Teil-<br />
Ganzes-Beziehung zwischen genau zwei Klassen.<br />
• Beispiel:<br />
Field<br />
Ganzes<br />
0..1<br />
0..*<br />
Figure<br />
Aggregation<br />
Teil<br />
Das Teil kennt das<br />
Ganze nicht (Pfeilspitze).<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 250
Klassendiagramme<br />
Beziehungen zwischen Klassen: Aggregation<br />
• Eigenschaften einer Aggregation:<br />
<br />
<br />
<br />
<br />
Die Lebensdauer des Ganzen ist von der Lebensdauer der Teile unabhängig.<br />
Die Lebensdauer der Teile ist von der Lebensdauer des Ganzen unabhängig.<br />
Teile können in mehreren Ganzen gleichzeitig verwendet werden.<br />
Die Teile kennen das Ganze häufig nicht.<br />
• Einsatzgebiete für Aggregation:<br />
<br />
<br />
<br />
Das Ganze handelt als Stellvertreter für seine Teile.<br />
Es nimmt Aufträge entgegen und delegiert diese an die Teile.<br />
Beispiel: Pacman<br />
- Ganzes: Spielfeld<br />
- Teile: Einzelne Figuren in der Zeichenfläche<br />
- Auftrag: Anforderung, sich neu zu zeichnen<br />
- Delegation: Jedes Teil erhält den Auftrag, sich selbst neu zu zeichnen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 251
Klassendiagramme<br />
Beziehungen zwischen Klassen: Aggregation<br />
• Implementierung einer Aggregation:<br />
public class Field {<br />
private ArrayList figures;<br />
public abstract class Figure {<br />
}<br />
// ...<br />
}<br />
// ...<br />
• Hinweise:<br />
<br />
<br />
Das Ganze erzeugt und löscht die Teile i.d.R. nicht selbst.<br />
Das Ganze besitzt häufig Methoden zum Hinzufügen und Entfernen von Teilen sowie<br />
zum Besuchen aller Teile.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 252
Klassendiagramme<br />
Beziehungen zwischen Klassen: Komposition<br />
Definition: Komposition<br />
Eine Komposition ist eine starke Form der Aggregation. Hier sind das Ganze und seine Teile<br />
untrennbar miteinander verbunden.<br />
• Beispiel:<br />
GameController<br />
Ganzes<br />
Komposition, Multiplizität ist 1<br />
0..*<br />
Figure<br />
Das Teil kennt das<br />
Ganze nicht (Pfeilspitze).<br />
Teil<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 253
Klassendiagramme<br />
Beziehungen zwischen Klassen: Komposition<br />
• Eigenschaften einer Komposition:<br />
Die Lebensdauer des Ganzen ist von der Lebensdauer der Teile unabhängig. Beim<br />
Löschen eines Teils bleibt das Ganze bestehen.<br />
Die Lebensdauer der Teile ist von der Lebensdauer des ganzen abhängig: Beim Löschen<br />
des Ganzen werden die Teile auch gelöscht.<br />
Teile können nicht in mehreren Ganzen gleichzeitig verwendet werden.<br />
Die Teile kennen das Ganze häufig nicht.<br />
• Einsatzgebiete für Komposition siehe Aggregation<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 254
Klassendiagramme<br />
Beziehungen zwischen Klassen: Komposition<br />
• Spezialfall der Komposition: Multiplizität 0..1<br />
GameController<br />
0..*<br />
Figure<br />
0..1<br />
• Figuren dürfen außerhalb und ohne Bezug zum Controller erzeugt werden.<br />
• Sie werden dann als Teile am Controller registriert und gehören ab diesem Zeitpunkt zum<br />
Controller.<br />
• Figuren dürften auch an einen anderen Controller übertragen werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 255
Klassendiagramme<br />
Beziehungen zwischen Klassen: Komposition<br />
• Implementierung einer Komposition (in Java wie bei einer Aggregation):<br />
public class GameController {<br />
private ArrayList figures;<br />
public abstract class Figure {<br />
}<br />
// ...<br />
}<br />
// ...<br />
• Hinweise:<br />
<br />
<br />
Häufig ist es sinnvoll, dass das Ganze die Teile selbst erzeugt und löscht: Die Teile können<br />
nicht so versehentlich auch ohne das Ganze verwendet werden.<br />
Das Ganze besitzt i.d.R. Methoden zum Erzeugen und Entfernen von Teilen sowie zum<br />
Besuchen aller Teile.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 256
Klassendiagramme<br />
Beziehungen zwischen Klassen: Hinweise zur Auswahl<br />
• Wann wird ein bestimmter Beziehungstyp verwendet?<br />
<br />
<br />
<br />
<br />
Existenzabhängige Teil-Ganzes-Beziehung: Komposition<br />
Logische Einheit, die nicht existenzabhängig ist: Aggregation<br />
Kaskadierende Methodenaufrufe: Aggregation (z.B. Pacman-Spiel, in dem die Spielfläche<br />
die Aufrufe zum Neuzeichnen an die Figuren weiter leitet)<br />
Rumbaugh: „Think of Aggregation as a modeling placebo“.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 257
Klassendiagramme<br />
Beziehungen zwischen Klassen: Abhängigkeit<br />
Definition: Abhängigkeit<br />
Eine Abhängigkeit zeigt, dass eine Klasse (Client) eine andere (Supplier) zur Erfüllung ihrer<br />
Aufgaben benötigt. Die Abhängigkeit dient nur der Dokumentation.<br />
• Beispiel (Bewerber ruft eine Methode der Klasse Firma auf):<br />
Firma<br />
+bewerben()<br />
<br />
Bewerber<br />
+bewerben()<br />
Supplier<br />
Client<br />
• Implementierung:<br />
public class Bewerber {<br />
}<br />
public void bewerben(Firma firma) {<br />
firma.bewerben(this);<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 258
Klassendiagramme<br />
Beziehungen zwischen Klassen: Abhängigkeit<br />
• Abhängigkeitstypen werden durch sogenannte Stereotypen beschrieben. Vordefiniert sind<br />
(unvollständig):<br />
: Der Client ruft mindestens eine Methode des Suppliers auf.<br />
: Der Client erzeugt Supplier-Objekte.<br />
: Der Client ist logisch aus dem Supplier abgeleitet. Er kann beispielsweise<br />
dieselbe Funktionalität wie der Supplier erfüllen, wurde aber aus<br />
Geschwindigkeitsgründen anders implementiert.<br />
: Der Supplier gewährt dem Client Zugriff auf private Daten.<br />
: Der Client kann den Supplier (ohne dass es eine Vererbung zwischen<br />
ihnen gibt) direkt ersetzen.<br />
: Der Client benötigt den Supplier für seine Funktion.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 259
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Implementierung<br />
Definition: Vererbung von einer Implementierung (Generalisierung)<br />
Die Vererbung beschreibt eine Beziehung zwischen einer Basisklasse und einer abgeleiteten<br />
Klasse. Details: Siehe vorherige Kapitel<br />
• Beispiel:<br />
Figure<br />
passive Figur<br />
passive Figur<br />
steuerbare Figur<br />
Diskriminator<br />
(optional)<br />
Ghost Cherry Pacman<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 260
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Implementierung<br />
• Der Diskriminator kann bei Gleichheit auch so notiert werden:<br />
gilt für beide<br />
Klassen<br />
Figure<br />
passive Figur<br />
steuerbare Figur<br />
Ghost Cherry Pacman<br />
• Durch den Diskriminator können<br />
<br />
<br />
Gruppen zusammengehöriger Klassen erkannt werden<br />
weitere Eigenschaften einer Vererbung gegeben werden.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 261
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Implementierung<br />
• Eigenschaften von Diskriminatoren:<br />
<br />
{complete, disjoint}: Die Klassen an dem Diskriminator sind vollständig. Sie<br />
decken alle möglichen Objekte ab (complete). Ein Objekt kann nicht gleichzeitig<br />
Pacman und Geist sein (disjoint).<br />
Eigenschaft<br />
Figure<br />
{complete, disjoint}<br />
Typ<br />
Ghost Cherry Pacman<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 262
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Implementierung<br />
<br />
{incomplete, disjoint}: Die Gruppe des Diskriminators ist unvollständig<br />
(incomplete), da beispielsweise die Kirschen fehlen. Ein Pacman kann nicht gleichzeitig<br />
Geist sein (disjoint).<br />
Figure<br />
{incomplete, disjoint}<br />
Typ<br />
Ghost<br />
Pacman<br />
<br />
Ohne Angabe wird {disjoint} angenommen.<br />
• Die Vererbung von einer abstrakten Basisklasse und einer nicht-abstrakten Basisklasse erfolgt<br />
genau gleich.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 263
Klassendiagramme<br />
Beziehungen zwischen Klassen: Mehrfachvererbung<br />
• Mehrfachvererbung einer Implementierung: Eine Klasse hat mehr als eine direkte Basisklasse<br />
(in Java nicht möglich).<br />
HSAngehoeriger<br />
{incomplete, overlapping}<br />
Student<br />
Taetigkeit<br />
Dozent<br />
Tutor<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 264
Klassendiagramme<br />
Beziehungen zwischen Klassen: Mehrfachvererbung<br />
• Diskriminatoren (Fortsetzung):<br />
<br />
<br />
{incomplete, overlapping}: Die Gruppe des Diskriminators ist unvollständig<br />
(incomplete). Ein Objekt kann Instanz von mehr als einer Basisklasse sein<br />
(overlapping).<br />
{complete, overlapping}: Die Gruppe des Diskriminators ist vollständig<br />
(complete). Ein Objekt kann Instanz von mehr als einer Basisklasse sein<br />
(overlapping).<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 265
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Spezifikation<br />
Definition: Vererbung von einer Spezifikation<br />
Diese Art der Vererbung beschreibt die Implementierung einer Schnittstelle. Details: Siehe<br />
vorherige Kapitel<br />
• Beispiel:<br />
<br />
Comparable<br />
T: class<br />
+compareTo(o: T): int<br />
Schnittstellenimplementierung<br />
String<br />
Integer<br />
+compareTo(o: String): int<br />
+compareTo(o: Integer): int<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 266
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Spezifikation<br />
• Alternative Darstellung mit Ball-Symbol (die Klasse String implementiert die Schnittstelle<br />
Comparable):<br />
String<br />
implementierte<br />
Schnittstelle<br />
+compareTo(o: String): int<br />
Comparable<br />
Schnittstellenname<br />
• Algorithmen und Datenstrukturen operieren häufig nur auf Schnittstellen:<br />
<br />
<br />
Klassendiagramme einer Beziehung genau wie bei einer Abhängigkeit zwischen Klassen<br />
notwendig<br />
Hier: Klasse benötigt eine Schnittstelle<br />
SortedContainer<br />
<br />
<br />
Comparable<br />
T: class<br />
benötigte<br />
Schnittstelle<br />
+compareTo(o: T): int<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 267
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung von einer Spezifikation<br />
• Alternative Darstellung mit dem Ball-Symbol:<br />
SortedContainer<br />
benötigte<br />
Schnittstelle<br />
Comparable<br />
Schnittstellenname<br />
• Gemeinsame Darstellung: Schnittstelle, implementierende Klasse und Klasse, die die<br />
Schnittstelle benötigt, in der Ball-Darstellung:<br />
SortedContainer<br />
String<br />
Comparable<br />
+compareTo(o: String): int<br />
• Implementierung:<br />
public class SortedContainer {<br />
private Comparable[] elements;<br />
// ...<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 268
Klassendiagramme<br />
Beziehungen zwischen Klassen: Generische Klassen<br />
• Zwischen generischen und konkreten Klassen als Instanzen der generischen Klassen<br />
existieren auch Beziehungen.<br />
• Erinnerung: Generische Klasse in UML<br />
Vector<br />
E: class<br />
-values: E[*] {bag}<br />
+Vector(size: int, initValue: E)<br />
+setValue(index: int, E: value)<br />
+getValue(index: int): E<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 269
Klassendiagramme<br />
Beziehungen zwischen Klassen: Vererbung einer Assoziation<br />
• Die Vererbung von Assoziationen wird meist in folgenden Szenarien verwendet:<br />
<br />
Es besteht bereits eine Assoziation zwischen zwei Basisklassen.<br />
Es soll ausgedrückt werden, dass die Assoziation einer abgeleiteten Klasse immer nur mit<br />
der Assoziation einer anderen abgeleiteten Klasse hergestellt werden soll.<br />
• Beispiel:<br />
Artikel<br />
*<br />
schreibt<br />
1<br />
Person<br />
Fachartikel<br />
-artikel<br />
-autor<br />
Redakteur<br />
Nur der Redakteur<br />
kann Fachartikel<br />
schreiben Eine<br />
Assoziation kann<br />
z.B. nicht von einer<br />
„normalen“ Person<br />
zum Fachartikel führen.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 270
Klassendiagramme<br />
Anmerkungen im Klassendiagramm<br />
Definition: Anmerkung<br />
Eine Anmerkung beinhaltet einen Kommentar für ein beliebiges UML-Sprachelement.<br />
• Beispiel:<br />
Die Figur ist das zentrale<br />
Element in einer<br />
Zeichenfläche.<br />
+paint()<br />
Figure<br />
Zuordnung<br />
Anmerkung<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 271
Klassendiagramme<br />
Übersicht zu Klassendiagramm (vereinfacht)<br />
Darstellung der wichtigsten Elemente durch MagicDraw:<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 272
Klassendiagramme<br />
Klassen im Pacman-Spiel (unvollständig)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 273
Klassendiagramme<br />
Beispiel aus der Klausur WS 2012/2013<br />
• Fiktives Flugbuchungssystem:<br />
<br />
<br />
<br />
<br />
<br />
Kunde: Name, Anschrift, E-Mail-Adresse, Angabe (privat/geschäftlich), Login-Name,<br />
Passwort<br />
Flug: Flugnummer, Datum, Uhrzeit, Start- und Endflughafen, Gebühr, abhängig vom<br />
Startflughafen, Preis, abhängig von der Klasse (1. Klasse, Business-Klasse, 2. Klasse). Es<br />
werden alle Sitze einer Klasse zum selben Preis angeboten.<br />
Buchung: Jeder Kunde kann beliebig viele Flugbuchungen gleichzeitig vornehmen. Eine<br />
Buchung kann mehrere Sitzplätze in derselben Klasse umfassen. Die Zahlungsart müssen<br />
Sie nicht berücksichtigen.<br />
Reservierung: Ist sich ein Kunde noch nicht ganz sicher, ob er einen Flug buchen möchte,<br />
dann kann er sich diesen für einen Zeitraum von 24 Stunden kostenlos reservieren.<br />
Zusatzoptionen bei der Buchung: Zu einem Flug können optionale Leistungen<br />
hinzugebucht werden, für die aber zusätzliche Kosten anfallen<br />
(Reiserücktrittsversicherung, Sitzplatz am Notausstieg, Übergepäck, eventuell weitere (je<br />
nach Fluggesellschaft und Flugzeugtyp).<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 274
Fehlerbehandlung mit Ausnahmen<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 275
Fehlerbehandlung mit Ausnahmen<br />
Motivation<br />
• Welche Arten von Fehlern gibt es?<br />
• Wie können Laufzeitfehler sicher gefunden werden?<br />
• Wie sollten Laufzeitfehler einer Methode dem Aufrufer mitgeteilt werden?<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 276
Fehlerbehandlung mit Ausnahmen<br />
Fehlerklassifikation<br />
• Erwartete Fehler durch Aufruf einer prinzipiell unsicheren Methode<br />
<br />
<br />
<br />
<br />
Auftreten: Es muss bei jedem Aufruf mit dem Fehler gerechnet werden.<br />
Beispiel: Versuch, eine Datei zum Lesen zu öffnen, die nicht existiert<br />
Vermeidung: nicht möglich<br />
Behandlung: ja<br />
• Unerwartete Fehler durch Programmierfehler oder mangelnde Systemressourcen<br />
<br />
<br />
<br />
<br />
Auftreten: Eigentlich sollte der Fehler nie auftreten.<br />
Beispiel: zu wenig Hauptspeicher vorhanden, Stacküberlauf<br />
Vermeidung: nur begrenzt möglich (intensive Programmtests)<br />
Behandlung: nur begrenzt möglich (z.B. Datensicherung vor der Programmbeendigung)<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 277
Fehlerbehandlung mit Ausnahmen<br />
Fehlerklassifikation<br />
• Sonderfall: Erwarteter oder unerwarteter Fehler während der Fehlerbehandlung<br />
<br />
<br />
<br />
<br />
Auftreten: siehe erwarteter und unerwarteter Fehler<br />
Beispiel: Die Fehlermeldung kann wegen fehlender Schreibrechte oder zu geringen<br />
freien Hauptspeichers nicht in eine Datei geschrieben werden.<br />
Vermeidung: nur bei sehr einfacher Fehlerbehandlung möglich<br />
Behandlung: hängt vom Fehler ab<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 278
Fehlerbehandlung mit Ausnahmen<br />
Reaktionen auf Fehler<br />
• Sofort behandelbarer Fehler<br />
Auswirkung: Das Programm kann auf den Fehler reagieren und seine Arbeit (eventuell<br />
eingeschränkt) fortsetzen.<br />
Reaktion: ignorieren (wenn sinnvoll möglich), alternativen Programmablauf starten<br />
Beispiel: Bei fehlender Eingabedatei werden immer Standardwerte angenommen.<br />
• Nicht sofort behandelbarer Fehler<br />
Auswirkung: Der Fehler kann an der Stelle, an der er auftritt, nicht behandelt werden.<br />
Reaktion: Fehlermeldung an den Aufrufer der Methode<br />
Beispiel: Datei existiert nicht sollen Standardwerte verwendet werden/soll der<br />
Benutzer gefragt werden? Kann eventuell an der Stelle des Fehlers nicht entschieden<br />
werden.<br />
• Nicht sinnvoll behandelbarer Fehler<br />
Auswirkung: sinnvolle Programmfortsetzung nicht möglich<br />
Reaktion: i.d.R. Programmbeendigung mit vorheriger Datensicherung (sofern möglich)<br />
Beispiel: Stacküberlauf, schwere Programmierfehler<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 279
Fehlerbehandlung mit Ausnahmen<br />
Exceptions – Idee<br />
• Fehlerbehandlung bisher:<br />
<br />
<br />
<br />
Ein Methode m1 stellt einen Fehler fest und liefert ein Ergebnis, das diesen Fehler<br />
beschreibt.<br />
Die aufrufende Methode m1 der Methode m2 stellt fest, dass m2 einen Fehler<br />
zurückliefert und beendet die eigene Arbeit mit der Rückgabe eines Fehlers.<br />
usw...<br />
• Schlechte Lösung, da sich eventuell große Teile einer Methode mit der Fehlerbehandlung<br />
befassen. Eine Trennung von Fehler- und Normalfall ist nicht vorhanden.<br />
• Fehler werden häufig über viele Aufrufebenen hinweg nach „oben“ weitergereicht, ohne<br />
dass die Fehler direkt bearbeitet werden.<br />
• Java bietet das Konzept der Ausnahme (Exception) zur besseren Fehlerbehandlung. Damit<br />
muss nicht der Rückgabewert einer Methode zur Fehlerübermittlung missbraucht werden.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 280
Fehlerbehandlung mit Ausnahmen<br />
Exceptions – Idee<br />
Einsatzgebiete<br />
• Meldung von Fehlern, die nicht lokal am Ort der Entstehung behoben werden konnten:<br />
Beispielsweise kann der Autor einer Bibliothek Laufzeitfehler („Datei existiert nicht“ etc.)<br />
zwar erkennen, er ist aber selten in der Lage, diese im Kontext des aufrufenden<br />
Programms richtig zu behandeln.<br />
Der Anwender der Bibliothek dagegen weiß, wie er mit den Fehlern umgehen soll.<br />
• Die Behandlung von anderswo gefundenen Fehlern.<br />
• Syntax:<br />
try {<br />
// versuche, eine Aufgabe zu lösen<br />
}<br />
catch (Fehlerklasse fehler) {<br />
// behandle Fehler des Typs "Fehlerklasse"<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 281
Fehlerbehandlung mit Ausnahmen<br />
Exceptions – Idee<br />
• Beispiel (Zugriff auf den Vektor, angelehnt an ArrayList):<br />
public class Vector {<br />
private E[] values;<br />
private int size;<br />
// ...<br />
public E getValue(int index) {<br />
if (index >= size || index < 0)<br />
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);<br />
return values[ index ];<br />
}<br />
}<br />
public static void main(String[] args) {<br />
Vector vector = new Vector(3, 0.0);<br />
try {<br />
System.out.println(vector.getValue(0));<br />
System.out.println(vector.getValue(4));<br />
}<br />
catch (IndexOutOfBoundsException ex) {<br />
System.err.println("Oops" + ex.getMessage());<br />
}<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 282
Fehlerbehandlung mit Ausnahmen<br />
Mehrere Exceptions<br />
Behandlung mehrerer Ausnahmen<br />
• Syntax:<br />
try {<br />
// versuche, eine Aufgabe zu lösen<br />
}<br />
catch (FehlerTyp1 ex1) {<br />
// behandle Fehler-Typ1<br />
}<br />
catch (FehlerTyp2 ex2) {<br />
// behandle Fehler-Typ2<br />
}<br />
• Unbehandelte Ausnahmen:<br />
Beendigung der Methode<br />
Auslösung der Ausnahme in der aufrufenden Methode<br />
Dieses Spiel funktioniert solange, bis eine Methode die Ausnahme abfängt oder das<br />
Programm beendet wurde.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 283
Fehlerbehandlung mit Ausnahmen<br />
Mehrere Exceptions<br />
• Es dürfen auch mehrere, unabhängige Fehler durch ein sogenanntes „multi-catch“<br />
abgefangen werden:<br />
• Syntax:<br />
try {<br />
// versuche, eine Aufgabe zu lösen<br />
}<br />
catch (FehlerTyp1 ex1 | FehlerTyp2 ex2) {<br />
// behandle Fehler-Typ1 und Fehler-Typ 2<br />
}<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 284
Fehlerbehandlung mit Ausnahmen<br />
Mehrere Exceptions<br />
• Ausnahmen werden in den catch-Blöcken in der Reihenfolge ihres Auftretens ausgewertet.<br />
• Abfangen aller möglichen Ausnahmen:<br />
try {<br />
// versuche, eine Aufgabe zu lösen<br />
}<br />
catch (FehlerTyp1 ex) {<br />
// behandle Fehler-Typ1<br />
}<br />
catch (Throwable thr) { // Alle unbehandelten Fehler<br />
// behandle alle anderen Fehler<br />
}<br />
• Ausnahmen können auch im catch-Block ausgelöst werden:<br />
try {<br />
// versuche, eine Aufgabe zu lösen<br />
}<br />
catch (FehlerTyp1 ex) {<br />
// behandle Fehler-Typ1<br />
throw ex; // Fehler weitermelden<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 285
Fehlerbehandlung mit Ausnahmen<br />
Exceptions mit Klassenhierarchien<br />
• Exception-Klassen können ganze Klassenhierarchien bilden.<br />
• Im catch-Block kann auch die Basisklasse einer Ausnahme angegeben werden, um eine<br />
Ausnahme einer abgeleiteten Klasse abzufangen.<br />
• Beispiel:<br />
public class FileNotFoundException extends IOException {<br />
// ...<br />
}<br />
• Eine FileNotFoundException kann jetzt auch durch die Angabe ihrer Basisklasse<br />
abgefangen werden:<br />
public void m() {<br />
try {<br />
// …<br />
throw new FileNotFoundException();<br />
}<br />
catch (IOException ex) {<br />
// …<br />
}<br />
}<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 286
Fehlerbehandlung mit Ausnahmen<br />
Exceptions mit Klassenhierarchien<br />
• Es können auch mehrere catch-Blöcke vorhanden sein, die sowohl die abgeleitete Klasse als<br />
auch die Basisklasse der Ausnahme abfangen. Achtung Reihenfolge:<br />
public void m() {<br />
try {<br />
// ...<br />
throw new FileNotFoundException();<br />
}<br />
catch (IOException ex1) {<br />
// ...<br />
}<br />
catch (Throwable thr) {<br />
// ...<br />
}<br />
}<br />
• Wird erst Throwable abgefangen, dann wird der catch-Block von IOException nie<br />
betreten.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 287
Fehlerbehandlung mit Ausnahmen<br />
Exceptions: Hinweise<br />
• Generelle Ausräumarbeiten nach einem erfolgreichem try oder einer Ausnahme mit<br />
finally. Beispiel:<br />
public void m() {<br />
try {<br />
// ...<br />
throw new FileNotFoundException();<br />
}<br />
catch (IOException ex1) {<br />
// ...<br />
}<br />
finally {<br />
// Wird immer betreten<br />
}<br />
}<br />
• Ein „echtes“ Beispiel folgt im nächsten Kapitel.<br />
• Seit Java 7 gibt es ein erweitertes try-Konstrukt siehe Kapitel zur Ein-<br />
/Ausgabebehandlung.<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 288
Fehlerbehandlung mit Ausnahmen<br />
Exceptions mit Klassenhierarchien<br />
• Arten der Ausnahmen:<br />
• gelb: unerwartete und in der Regel nicht sinnvoll behandelbare Fehler<br />
• grün: unerwartete und in der Regel nicht sinnvoll behandelbare Fehler<br />
(„Programmierfehler“)<br />
• rot: erwartete und sofort oder später behandelbare Fehler (erben direkt von Exception,<br />
nicht von RuntimeException)<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 289
Fehlerbehandlung mit Ausnahmen<br />
Eigenschaften und Deklaration erwarteter Fehler<br />
• Erwartete und sofort oder später behandelbare Fehler (rot markiert):<br />
<br />
<br />
<br />
Einem Anwender einer Methode muss die Art der Ausnahme, die diese auslösen kann,<br />
angegeben werden.<br />
Syntax:<br />
ret-type method-name(params) throws Exceptions<br />
Beispiel:<br />
public int readFromFile(String name) throws FileNotFoundException,<br />
EOFException {<br />
Beispiel durch Angabe der Basisklasse IOException (FileNotFoundException und<br />
EOFException erben davon):<br />
public int readFromFile(String name) throws IOException {<br />
Ohne Spezifikation kann die Methode nur unerwartete oder gar keine Ausnahmen<br />
auslösen.<br />
Beispiel:<br />
public int getValue(int index) {<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 290
Pakete<br />
Übersicht<br />
Java und<br />
UML<br />
Schritte,<br />
Software<br />
Imperative<br />
Aspekte<br />
Klassendiagramme<br />
Objektorientierung<br />
Ausnahmen<br />
Pakete<br />
Klassen,<br />
Objekte<br />
Fehler<br />
Überladen<br />
Zusicherungen<br />
Vererbung<br />
Gener.<br />
Klassen<br />
Überschreiben<br />
Aufzähltypen<br />
Regeln<br />
Holger Vogelsang<br />
<strong>Informatik</strong> 2 - Einführung in Java und UML 291
Pakete<br />
Motivation<br />
• Was passiert, wenn zwei Hersteller Klassen mit demselben Namen erstellt haben und<br />
beide Klassen in einem Projekt zusammen benutzt werden sollen?<br />
• Wie können logisch zusammengehörige Klassen gruppiert werden?<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 292
Pakete<br />
Idee<br />
• Ein Paket sollte eine Anzahl logisch zusammengehöriger Klassen, Schnittstellen, Ausnahmen,<br />
Fehler, Aufzähltypen und Annotationen beinhalten.<br />
Beispiel:<br />
alle Klassen, die mathematische Berechnungen durchführen<br />
alle Klassen, die Text formatieren<br />
• Der Paketname entspricht einem Verzeichnis im Dateisystem.<br />
Beispiel:<br />
Klasse Complex im Paket de.hska.iwii.math: Sowohl die Quelltextdatei Complex.java<br />
als auch die Bytecode-Datei Complex.class sollten in in einem Unterverzeichnis<br />
de/hska/iwii/math liegen.<br />
• Festlegung der Paket-Zugehörigkeit einer Klasse: Anweisung in der Klasse der Form package<br />
Paket-Name;. Diese Anweisung sollte die erste in der Datei sein.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 293
Pakete<br />
Idee<br />
• Verwendung einer Klasse eines anderen Pakets:<br />
Variante 1: import Paketname.*; Beispiel:<br />
<br />
import de.hska.iwii.math.*;<br />
//...<br />
Complex value = new Complex();<br />
// Bindet alle Klassen des Pakets<br />
// de.hska.iwii.math ein<br />
Variante 2: import Paketname.Klassenname; Beispiel:<br />
import de.hska.iwii.math.Complex;<br />
//...<br />
Complex value = new Complex();<br />
// Bindet Complex des Pakets<br />
// de.hska.iwii.math ein.<br />
Variante 3: Verwendung des vollständigen Klassennamens. Beispiel:<br />
//...<br />
de.hska.iwii.math.Complex value = new de.hska.iwii.math.Complex();<br />
• Nach Aussage von Oracle sollte Variante 1 vermieden werden.<br />
• Das Paket java.lang des JDK ist immer automatisch eingebunden.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 294
Pakete<br />
Aufbau<br />
• Allgemeiner Aufbau eines Namens (kann variieren):<br />
Organisation.Paketname.Klassenname.Methodenname<br />
Beispiele:<br />
Paket Klasse Methode<br />
de.hska.ss2012.project2.math.Complex.add()<br />
Land<br />
Hochschule<br />
KA<br />
Semester Projekt Teil des<br />
Projektes<br />
Paket Klasse Methode<br />
com.mycompany.math.Complex.add()<br />
Firma<br />
Teil des<br />
Projektes<br />
Paket Klasse Methode<br />
javax.swing.table.DefaultTableModel.getDataVector()<br />
Kommerziell<br />
Zusatzklasse<br />
des JDK<br />
GUI-<br />
Paket<br />
Tabelle<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 295
Pakete<br />
Inhalte eines Pakets<br />
• Innerhalb eines Pakets müssen die Namen eindeutig sein: Es darf eine Klasse Complex<br />
mehrfach geben, solange sie in unterschiedlichen Paketen liegt.<br />
• Beispiel: java.util.Timer und javax.swing.Timer<br />
• So ganz stimmt die Aussage nicht:<br />
Der komplette Paketname (der Pfad inkl. Klassenname) darf mehrfach vorkommen,<br />
wenn die Pakete durch unterschiedliche Klassenlader (Classloader) geladen werden.<br />
Also: Klassenlader + Paketname muss eindeutig sein!<br />
• Es ist mindestens ein Klassenlader in der virtuellen Maschine aktiv:<br />
Er kennt mehrere Dateipfade oder jar-Dateien, aus denen er die Klassen und<br />
Schnittstellen lädt.<br />
Weitere Klassenlader können erstellt und verwendet werden.<br />
Holger Vogelsang <strong>Informatik</strong> 2 - Einführung in Java und UML 296