Java-Programme. Lese- und Lernhilfe für [Staud 2026a] (Version 2026/7/24)
| |
|
|
Copyright 2025, 2026 Prof. Dr. Josef L. Staud |
|
|
|
Autor: Josef L. Staud |
|
Umfang des gedruckten Textes: ca. 344 Seiten |
|
Es ist eine auf langer Erfahrung beruhende Erkenntnis, dass eine Programmiersprache leichter erlernt werden kann, wenn der Lernstoff durch möglichst viele praxisnahe Beispielprogramme ergänzt wird. Dies war das erste Motiv für diesen Text. Das zweite Motiv besteht darin, Erläuterungen zu den Java-Beispielen in [Staud 2026a] bereitzustellen. Der Text stellt keine Einführung in Java dar; hierzu sei auf die im Literaturverzeichnis aufgeführten Bücher verwiesen und auf ChatGPT. Er soll vielmehr eine Beziehung zwischen den Konstrukten der UML in [Staud 2026a] und ihrer Umsetzung in einer objektorientierten Programmiersprache herstellen. Zur UML 2.5 findet sich eine umfassende Darstellung in [Staud 2019]. |
|
Diese HTML-Seiten wurden mit Hilfe eines von mir erstellten Programms erzeugt: WebGenerator2 (Version 2023). Es setzt Texte in HTML-Seiten um und wird ständig weiterentwickelt. Die "maschinelle" Erstellung erlaubt es, nach jeder Änderung des Textes diesen unmittelbar neu in HTML-Seiten umzusetzen. Da es nicht möglich ist, nach jeder Neuerstellung alle Seiten zu prüfen, ist es durchaus möglich, dass irgendwo auf einer "abgelegenen" Seite Fehler auftreten. Ich bitte dafür um Verzeihung und um Hinweise (hs@staud.info). |
|
Die Veröffentlichung im Web erfolgt ab 2022 in zwei Versionen: Mit und ohne Frame-Technologien. Zu meinem Bedauern wird die Frame-Technologie inzwischen von den Verantwortlichen als unerwünscht angesehen und es häufen sich die Hinweise, dass bestimmte Browser Frame-basierte Seiten nicht mehr korrekt interpretieren können. Deshalb habe ich eine zweite Version meines Programms WebGenerator erstellt, die ohne Frames realisiert ist. |
|
Urheberrecht |
|
Dieser Text ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere die der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen und Tabellen oder der Vervielfältigung auf anderen Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, auch bei nur auszugsweiser Verwertung, vorbehalten. Eine Vervielfältigung dieses Textes oder von Teilen dieses Textes ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechtsgesetzes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils geltenden Fassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegen den Strafbestimmungen des Urheberrechtsgesetzes. |
|
Warenzeichen und Markenschutz |
|
Alle in diesem Text genannten Gebrauchsnamen, Handelsnamen, Marken, Produktnamen, usw. unterliegen warenzeichen-, marken- oder patentrechtlichem Schutz bzw. sind Warenzeichen oder eingetragene Warenzeichen der jeweiligen Inhaber. Die Wiedergabe solcher Namen und Bezeichnungen in diesem Text berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Gesetzgebung zu Warenzeichen und Markenschutz als frei zu betrachten wären und daher von jedermann benutzt werden dürften. |
|
|
|

|
|
|
|
Prof. Dr. Josef Ludwig Staud |
|
|
|
Vorwort, Inhalt, Abkürzungen
| |
Vorwort |
|
Der Gegensatz von Struktur und Verhalten ist in der IT (bei den Digitalisierungsbemühungen) allgegenwärtig. Denken wir nur Programme und Datenbanken. Oder an Geschäftsprozesse vs. Datenbanken. Für Struktur in diesem Sinne wurden vor Jahrzehnten ausgefeilte Datenbanktechniken entwickelt, die derzeit mit NoSQL-Datenbanken eine an die Anforderungen des Internetzeitalters angepasste Form gefunden haben. Für Verhalten in diesem Sinne wurden die Programmiersprachen entwickelt, die schon immer erlaubten, Verarbeitungsvorgänge zu erfassen (dafür wurden sie geschaffen), und die es heute erlauben, die Dynamik ganzer Geschäftsprozesse in Programmen darzustellen. |
Struktur und Verhalten |
In der UML 2.5 sind die Strukturaspekte betont, vgl. [Staud 2019]. Hier soll nun gezeigt werden, wie diese in Java umgesetzt werden können. |
|
|
|
Inhaltsverzeichnis der Druckversion |
|
Vorwort, Inhalt, Abkürzungen.. 3 |
|
1 Einleitung.. 17 |
|
1.1 Konzept 17 |
|
1.2 Bibliotheken. 17 |
|
1.3 Packages. 18 |
|
1.4 Formatierung und Schreibweise. 18 |
|
2 Grundlagen. 19 |
|
2.1 Datentypen. 19 |
|
2.2 Attribute. 19 |
|
2.3 Logische Operatoren. 20 |
|
2.4 Referenzen. 21 |
|
2.5 Der Begriff "Typ" in Java. 22 |
|
3 Konsolenarbeit. 24 |
|
3.1 Ausgeben auf Konsole. 24 |
|
3.2 Lesen von der Konsole. 24 |
|
4 Klassen, Objekte, Methoden. 26 |
|
4.1 Klassen einrichten. 26 |
|
4.1.1 Grundlagen. 26 |
|
4.1.2 Sichtbarkeit 27 |
|
4.2 Objekte einrichten - Konstruktoren. 27 |
|
4.3 Record-Klassen. 29 |
|
4.4 Aufruf von Methoden und Attributen. 29 |
|
5 Prozedurales. 31 |
|
5.1 Schleifen und Verzweigungen. 31 |
|
5.2 Das Try/Catch-Konstrukt 32 |
|
6 Textdateien bearbeiten. 34 |
|
6.1 Einleitung. 34 |
|
6.2 Paket java.io. 34 |
|
6.3 Zugriffe mit Streams. 34 |
|
6.4 Klasse File. 35 |
|
7 Exceptions. 38 |
|
8 Projekt HS1 - Objekterzeugung.. 39 |
|
8.1 Klasse HP (Hauptprogramm; main) 39 |
|
8.2 Klasse Stud. 41 |
|
8.3 Ergebnis Programmlauf 43 |
|
8.4 Betrachtete Themen. 44 |
|
9 Projekt HS2 - Objekte und Referenzen.. 45 |
|
9.1 Klasse HP. 45 |
|
9.2 Klasse Stud. 49 |
|
9.3 Ergebnis Programmlauf 49 |
|
9.4 Anmerkungen zum Programm.. 50 |
|
9.5 Betrachtete Themen. 51 |
|
10 Projekt HS3 - Array mit Objekten. 52 |
|
10.1 Klasse HP. 52 |
|
10.2 Klasse Stud. 56 |
|
10.3 Ergebnis Programmlauf 57 |
|
10.4 Beschreibung des Programms. 58 |
|
10.5 Betrachtete Themen. 59 |
|
11 Projekt HS4 - Aufrufe über Klassengrenzen. 60 |
|
11.1 Klasse HP. 60 |
|
11.2 Klasse Noten. 61 |
|
11.3 Klasse Stud. 62 |
|
11.4 Ergebnis Programmlauf 63 |
|
11.5 Beschreibung des Programms. 64 |
|
11.6 Betrachtete Themen. 65 |
|
12 Projekt HS5 - Eingaben.. 66 |
|
12.1 Klasse HP. 66 |
|
12.2 Klasse Stud. 68 |
|
12.3 Ergebnis Programmlauf 69 |
|
12.4 Anmerkungen zum Programm.. 69 |
|
12.5 Betrachtete Themen. 69 |
|
13 Exkurs - Nachrichtenverkehr. 71 |
|
14 Projekt HS6 - Record-Klassen. 72 |
|
14.1 Projektbeschreibung. 72 |
|
14.2 Klasse HP. 73 |
|
14.3 Klasse Stud. 75 |
|
14.4 Ergebnis Programmlauf 76 |
|
14.5 Betrachtete Themen. 76 |
|
14.6 Exkurs - Record vs. Klasse. 77 |
|
14.7 Exkurs - Methode hashCode() 78 |
|
15 Projekt HS7 - Vererbung, Attribute. 79 |
|
15.1 Klasse Fahrzeuge. 79 |
|
15.2 Klasse PKW... 80 |
|
15.3 Klasse LKW... 81 |
|
15.4 Klasse VAN.. 82 |
|
15.5 Klasse HP. 83 |
|
15.6 Ergebnis Programmlauf 86 |
|
15.7 Betrachtete Themen. 88 |
|
15.8 Projektbeschreibung. 88 |
|
15.8.1 Ziel des Projekts. 88 |
|
15.8.2 Aufbau des Projekts. 89 |
|
15.8.3 Beschreibung der einzelnen Klassen. 89 |
|
15.8.4 Ablauf des Programms. 90 |
|
16 Projekt HS7a - Override und Overload.. 92 |
|
16.1 Klasse HP. 92 |
|
16.2 Klasse Fahrzeuge. 92 |
|
16.3 Klasse PKW... 92 |
|
16.4 Ergebnis Programmlauf 93 |
|
16.5 Betrachtete Themen. 93 |
|
16.6 Exkurs: Override vs. Overload. 94 |
|
17 Projekt HS8 - Kapselung.. 95 |
|
17.1 Klasse HP. 95 |
|
17.2 Klasse Stud. 96 |
|
17.3 Ergebnis Programmlauf 98 |
|
17.4 Projektbeschreibung. 98 |
|
17.5 Betrachtete Themen. 99 |
|
17.6 Anmerkung. 100 |
|
18 Projekt HS9 - Assoziationen. 101 |
|
18.1 Klasse HP. 101 |
|
18.2 Klasse Stud. 101 |
|
18.3 Klasse Note. 102 |
|
18.4 Ergebnis Programmlauf 103 |
|
18.5 Erläuterungen zum Programm.. 103 |
|
18.6 Betrachtete Themen. 103 |
|
19 Projekt hsdaten - Dateien.. 105 |
|
19.1 Klasse Erstellen. 105 |
|
19.1.1 Das Programm.. 105 |
|
19.1.2 Anmerkung. 107 |
|
19.1.3 Betrachtete Themen. 107 |
|
19.2 Klasse Schreiben. 107 |
|
19.2.1 Das Programm.. 107 |
|
19.2.2 Anmerkung. 109 |
|
19.2.3 Betrachtete Themen. 109 |
|
19.3 Klasse Schreiben2. 109 |
|
19.3.1 Das Programm.. 109 |
|
19.3.2 Anmerkung. 111 |
|
19.3.3 Betrachtete Themen. 111 |
|
19.4 Klasse Lesen. 112 |
|
19.4.1 Das Programm.. 112 |
|
19.4.2 Anmerkung. 112 |
|
19.4.3 Betrachtete Themen. 113 |
|
19.5 Klasse Anhaengen. 113 |
|
19.5.1 Das Programm.. 113 |
|
19.5.2 Anmerkung. 115 |
|
19.5.3 Theorieaspekte. 116 |
|
19.5.4 Betrachtete Themen. 116 |
|
19.6 Klasse Loeschen. 117 |
|
19.6.1 Das Programm.. 117 |
|
19.6.2 Ergebnis Programmlauf 118 |
|
19.6.3 Erläuterungen. 118 |
|
19.6.4 Betrachtete Themen. 119 |
|
19.7 Klasse ErzeugLoesch. 120 |
|
19.7.1 Ergebnis Programmlauf 122 |
|
19.7.2 Erläuterungen. 122 |
|
19.7.3 Betrachtete Themen. 123 |
|
19.8 Klasse EinlesenCSV.. 124 |
|
19.8.1 Das Programm.. 124 |
|
19.8.2 Erläuterungen. 126 |
|
19.8.3 Betrachtete Themen. 127 |
|
20 Übungsaufgaben Teil 1. 128 |
|
20.1 Aufgabe 1 - Klasse und Objekt 128 |
|
20.1.1 Aufgabenstellung. 128 |
|
20.1.2 Lernziele. 128 |
|
20.1.3 Lösung. 129 |
|
20.1.4 Ergebnis Programmlauf 129 |
|
20.1.5 Betrachtete Themen. 129 |
|
20.1.6 Erläuterung. 129 |
|
20.2 Aufgabe 2 - Referenzen. 131 |
|
20.2.1 Aufgabenstellung. 131 |
|
20.2.2 Lernziele. 131 |
|
20.2.3 Lösung. 132 |
|
20.2.4 Ergebnis Programmlauf 132 |
|
20.2.5 Betrachtete Themen. 133 |
|
20.2.6 Erläuterung. 133 |
|
20.3 Aufgabe 3a - Arrays Einführung. 134 |
|
20.3.1 Aufgabenstellung. 134 |
|
20.3.2 Lernziele. 134 |
|
20.3.3 Lösung. 134 |
|
20.3.4 Betrachtete Themen. 135 |
|
20.3.5 Erläuterung. 135 |
|
20.3.6 Hinweis - Arrays von Objekten. 136 |
|
20.4 Aufgabe 3b - Arrays mit Objekten. 138 |
|
20.4.1 Aufgabenstellung. 138 |
|
20.4.2 Lernziele. 138 |
|
20.4.3 Lösung. 139 |
|
20.4.4 Ergebnis Programmlauf 139 |
|
20.4.5 Betrachtete Themen. 139 |
|
20.4.6 Erläuterung. 140 |
|
21 Übungsaufgaben Teil 2. 141 |
|
21.1 Aufgabe 4a - Klassen ohne Beziehung. 141 |
|
21.1.1 Aufgabenstellung. 141 |
|
21.1.2 Lernziele. 141 |
|
21.1.3 Ergebnis Programmlauf 141 |
|
21.1.4 Lösung. 142 |
|
21.1.5 Betrachtete Themen. 143 |
|
21.1.6 Erläuterung. 143 |
|
21.2 Aufgabe 4b -Einseitig. 144 |
|
21.2.1 Aufgabenstellung. 144 |
|
21.2.2 Lernziele. 144 |
|
21.2.3 Ergebnis Programmlauf 144 |
|
21.2.4 Lösung. 145 |
|
21.2.5 Ergebnis Programmlauf 146 |
|
21.2.6 Betrachtete Themen. 146 |
|
21.2.7 Erläuterung. 146 |
|
21.2.8 Exkurs - Von Arrays zu Listen. 147 |
|
21.3 Aufgabe 4c - Bidirektional 149 |
|
21.3.1 Aufgabenstellung. 149 |
|
21.3.2 Lernziele. 149 |
|
21.3.3 Lösung. 150 |
|
21.3.4 Ergebnis Programmlauf 152 |
|
21.3.5 Betrachtete Themen. 152 |
|
21.3.6 Theorieaspekt 152 |
|
21.4 Aufgabe 4d - n:m-Beziehung. 154 |
|
21.4.1 Aufgabe. 154 |
|
21.4.2 Lernziele. 154 |
|
21.4.3 Lösung. 154 |
|
21.4.4 Ergebnis Programmlauf 156 |
|
21.4.5 Betrachtete Themen. 156 |
|
21.4.6 Anmerkung. 156 |
|
21.5 Aufgabe 4e - Assoziationsklasse. 157 |
|
21.5.1 Aufgabe. 157 |
|
21.5.2 Lernziele. 157 |
|
21.5.3 Lösung. 158 |
|
21.5.4 Betrachtete Themen. 159 |
|
21.5.5 Anmerkung. 159 |
|
22 Übungsaufgaben Teil 3. 161 |
|
22.1 Aufgabe 5 - Eingaben. 161 |
|
22.1.1 Aufgabenstellung. 161 |
|
22.1.2 Gewünschte Ausgabe. 161 |
|
22.1.3 Lernziele. 161 |
|
22.1.4 Lösung. 162 |
|
22.1.5 Betrachtete Themen. 163 |
|
22.2 Aufgabe 6 - Record. 164 |
|
22.2.1 Aufgabenstellung. 164 |
|
22.2.2 Lernziele. 164 |
|
22.2.3 Lösung. 165 |
|
22.2.4 Ergebnis Programmlauf 166 |
|
22.2.5 Betrachtete Themen. 167 |
|
22.2.6 Exkurs: Wiederholung zu records. 167 |
|
22.3 Aufgabe 7 - Vererbung. 169 |
|
22.3.1 Aufgabenstellung. 169 |
|
22.3.2 Lernziele. 169 |
|
22.3.3 Lösung. 171 |
|
22.3.4 Ergebnis Programmlauf 172 |
|
22.3.5 Betrachtete Themen. 172 |
|
22.3.6 Erläuterung. 172 |
|
22.4 Aufgabe 8 - Kapselung. 174 |
|
22.4.1 Aufgabenstellung. 174 |
|
22.4.2 Lernziele. 174 |
|
22.4.3 Lösung. 175 |
|
22.4.4 Betrachtete Themen. 176 |
|
22.4.5 Erläuterung. 176 |
|
22.5 Aufgabe 9 - Overload. 177 |
|
22.5.1 Aufgabenstellung. 177 |
|
22.5.2 Ergebnis Programmlauf: 177 |
|
22.5.3 Lernziele. 177 |
|
22.5.4 Lösung. 177 |
|
22.5.5 Betrachtete Themen. 179 |
|
22.5.6 Erläuterung. 179 |
|
23 Übungsaufgaben Teil 4. 180 |
|
23.1 Aufgabe 10 - Einstieg. 180 |
|
23.1.1 Aufgabenstellung. 180 |
|
23.1.2 Lernziele. 180 |
|
23.1.3 Lösung. 181 |
|
23.1.4 Betrachtete Themen. 181 |
|
23.1.5 Ergebnis Programmlauf 181 |
|
23.2 Aufgabe 11 - Konstruktoren. 182 |
|
23.2.1 Aufgabenstellung. 182 |
|
23.2.2 Lernziele. 182 |
|
23.2.3 Lösung. 183 |
|
23.2.4 Ergebnis Programmlauf 183 |
|
23.2.5 Betrachtete Themen. 183 |
|
23.3 Aufgabe 12 - Array. 184 |
|
23.3.1 Aufgabenstellung. 184 |
|
23.3.2 Lernziele. 184 |
|
23.3.3 Ergebnis Programmlauf 184 |
|
23.3.4 Lösung. 185 |
|
23.3.5 Betrachtete Themen. 185 |
|
23.3.6 Erläuterung. 185 |
|
23.4 Aufgabe 13 - Kapselung. 187 |
|
23.4.1 Aufgabenstellung. 187 |
|
23.4.2 Lernziele. 187 |
|
23.4.3 Lösung. 188 |
|
23.4.4 Ergebnis Programmlauf 188 |
|
23.4.5 Betrachtete Themen. 188 |
|
23.4.6 Erläuterung. 188 |
|
23.5 Aufgabe 14 - Vererbung. 190 |
|
23.5.1 Aufgabenstellung. 190 |
|
23.5.2 Lernziele. 190 |
|
23.5.3 Lösung. 191 |
|
23.5.4 Ergebnis Programmlauf 191 |
|
23.5.5 Betrachtete Themen. 191 |
|
23.5.6 Erläuterung. 191 |
|
23.6 Aufgabe 15 - Override. 193 |
|
23.6.1 Aufgabenstellung. 193 |
|
23.6.2 Lernziele. 193 |
|
23.6.3 Lösung. 194 |
|
23.6.4 Ergebnis Programmlauf 194 |
|
23.6.5 Betrachtete Themen. 194 |
|
23.6.6 Erläuterung. 194 |
|
23.7 Aufgabe 16 - Polymorphie. 196 |
|
23.7.1 Aufgabenstellung. 196 |
|
23.7.2 Ergebnis Programmlauf 196 |
|
23.7.3 Lernziele. 196 |
|
23.7.4 Lösung. 197 |
|
23.7.5 Betrachtete Themen. 197 |
|
23.7.6 Erläuterung. 197 |
|
23.7.7 Exkurs Polymorphie. 198 |
|
24 Übungsaufgaben Teil 5. 201 |
|
24.1 Aufgabe 17 - Abstrakte Klasse. 201 |
|
24.1.1 Aufgabenstellung. 201 |
|
24.1.2 Lernziele. 201 |
|
24.1.3 Lösung. 202 |
|
24.1.4 Ergebnis Programmlauf 202 |
|
24.1.5 Betrachtete Themen. 202 |
|
24.1.6 Exkurs - Abstrakte Klasse. 202 |
|
24.2 Aufgabe 18 - Interface. 204 |
|
24.2.1 Aufgabenstellung. 204 |
|
24.2.2 Lernziele. 204 |
|
24.2.3 Lösung. 205 |
|
24.2.4 Betrachtete Themen. 205 |
|
24.2.5 Erläuterung. 205 |
|
24.2.6 Exkurs - Interface. 206 |
|
24.2.7 Interface vs. abstrakte Klasse. 207 |
|
24.3 Aufgabe 19 - 1:1. 210 |
|
24.3.1 Aufgabenstellung. 210 |
|
24.3.2 Lernziele. 210 |
|
24.3.3 Lösung. 211 |
|
24.3.4 Ergebnis Programmlauf 212 |
|
24.3.5 Betrachtete Themen. 212 |
|
24.3.6 Erläuterung. 212 |
|
24.4 Aufgabe 19b - Bidirektional 214 |
|
24.4.1 Aufgabenstellung. 214 |
|
24.4.2 Lernziele. 214 |
|
24.4.3 Lösung. 214 |
|
24.4.4 Ergebnis Programmlauf 216 |
|
24.4.5 Betrachtete Themen. 216 |
|
24.4.6 Erläuterungen. 216 |
|
24.5 Aufgabe 20 - n:m.. 217 |
|
24.5.1 Aufgabenstellung. 217 |
|
24.5.2 Lernziele. 217 |
|
24.5.3 Lösung. 218 |
|
24.5.4 Betrachtete Themen. 219 |
|
24.5.5 Erläuterung. 220 |
|
24.6 Aufgabe 21 - Klassendiagramm HS. 221 |
|
24.6.1 Aufgabe. 221 |
|
24.6.2 Lernziele. 222 |
|
24.6.3 Lösung. 222 |
|
24.6.4 Ergebnis Programmlauf 225 |
|
24.6.5 Betrachtete Themen. 225 |
|
25 Übungsaufgaben Teil 6. 226 |
|
25.1 Aufgabe 22 - Liste. 226 |
|
25.1.1 Aufgabenstellung. 226 |
|
25.1.2 Lernziele. 227 |
|
25.1.3 Lösung. 227 |
|
25.1.4 Betrachtete Themen. 231 |
|
25.1.5 Anmerkungen. 231 |
|
25.1.6 Exkurs - Verkettete Listen. 232 |
|
25.2 Aufgabe 23 - Unternehmen. 234 |
|
25.2.1 Aufgabenstellung. 234 |
|
25.2.2 Lernziele. 235 |
|
25.2.3 Lösung. 235 |
|
25.2.4 Ergebnis Programmlauf 239 |
|
25.2.5 Betrachtete Themen. 240 |
|
25.2.6 Anmerkung. 240 |
|
25.2.7 Aufgabenstellung. 241 |
|
25.2.8 Lernziele. 241 |
|
25.2.9 Lösung. 242 |
|
25.2.10 Ergebnis Programmlauf 242 |
|
25.2.11 Betrachtete Themen. 243 |
|
25.2.12 Erläuterung. 243 |
|
25.3 Aufgabe 25 - Abteilungszugehörigkeit 244 |
|
25.3.1 Aufgabenstellung. 244 |
|
25.3.2 Ergebnis Programmlauf 244 |
|
25.3.3 Lernziele. 244 |
|
25.3.4 Lösung. 245 |
|
25.3.5 Ergebnis Programmlauf 246 |
|
25.3.6 Betrachtete Themen. 246 |
|
25.3.7 Erläuterung. 246 |
|
25.4 Aufgabe 26 - PC.. 248 |
|
25.4.1 Aufgabenstellung. 248 |
|
25.4.2 Lernziele. 248 |
|
25.4.3 Lösung. 249 |
|
25.4.4 Ergebnis Programmlauf 250 |
|
25.4.5 Betrachtete Themen. 250 |
|
25.4.6 Erläuterung. 250 |
|
25.5 Aufgabe 27 - Projekte. 252 |
|
25.5.1 Aufgabenstellung. 252 |
|
25.5.2 Lernziele. 252 |
|
25.5.3 Lösung. 253 |
|
25.5.4 Ergebnis Programmlauf 254 |
|
25.5.5 Betrachtete Themen. 254 |
|
26 Übungsaufgaben Teil 7. 255 |
|
26.1 Aufgabe 28 - n:m-Beziehung. 255 |
|
26.1.1 Aufgabenstellung. 255 |
|
26.1.2 Lernziele. 255 |
|
26.1.3 Lösung. 256 |
|
26.1.4 Ergebnis Programmlauf 257 |
|
26.1.5 Betrachtete Themen. 257 |
|
26.2 Aufgabe 29 - Rekursive Beziehung. 259 |
|
26.2.1 Aufgabenstellung. 259 |
|
26.2.2 Lernziele. 259 |
|
26.2.3 Ergebnis Programmlauf 259 |
|
26.2.4 Lösung. 260 |
|
26.2.5 Betrachtete Themen. 261 |
|
26.2.6 Erläuterung. 261 |
|
26.3 Aufgabe 30 - Gehaltsauswertung. 262 |
|
26.3.1 Aufgabenstellung. 262 |
|
26.3.2 Lernziele. 262 |
|
26.3.3 Ergebnis Programmlauf 262 |
|
26.3.4 Lösung. 263 |
|
26.3.5 Betrachtete Themen. 264 |
|
26.4 Aufgabe 31 - Projektstatistik. 265 |
|
26.4.1 Aufgabenstellung. 265 |
|
26.4.2 Lernziele. 265 |
|
26.4.3 Ergebnis Programmlauf 265 |
|
26.4.4 Lösung. 266 |
|
26.4.5 Betrachtete Themen. 267 |
|
26.4.6 Erläuterung. 267 |
|
26.5 Aufgabe 32 - Mini-Personalverwaltung. 269 |
|
26.5.1 Aufgabenstellung. 269 |
|
26.5.2 Lernziele. 269 |
|
26.5.3 Lösung. 270 |
|
26.5.4 Ergebnis Programmlauf 274 |
|
26.5.5 Betrachtete Themen. 275 |
|
27 Übungsaufgaben Teil 8. 276 |
|
27.1 Aufgabe 33 - Vererbung. 276 |
|
27.1.1 Aufgabenstellung. 276 |
|
27.1.2 Lernziele. 276 |
|
27.1.3 Ergebnis Programmlauf 276 |
|
27.1.4 Lösung. 277 |
|
27.1.5 Betrachtete Themen. 277 |
|
27.1.6 Erläuterung. 278 |
|
27.2 Aufgabe 34 - Override. 279 |
|
27.2.1 Aufgabenstellung. 279 |
|
27.2.2 Lernziele. 279 |
|
27.2.3 Ergebnis Programmlauf 279 |
|
27.2.4 Lösung. 280 |
|
27.2.5 Betrachtete Themen. 281 |
|
27.2.6 Erläuterung. 281 |
|
27.3 Aufgabe 35 - Overload. 282 |
|
27.3.1 Aufgabenstellung. 282 |
|
27.3.2 Lernziele. 282 |
|
27.3.3 Ergebnis Programmlauf 282 |
|
27.3.4 Lösung. 283 |
|
27.3.5 Betrachtete Themen. 283 |
|
27.3.6 Erläuterung. 284 |
|
27.4 Aufgabe 36 - Abstraktes. 285 |
|
27.4.1 Aufgabenstellung. 285 |
|
27.4.2 Lernziele. 285 |
|
27.4.3 Ergebnis Programmlauf 285 |
|
27.4.4 Lösung. 286 |
|
27.4.5 Betrachtete Themen. 287 |
|
27.4.6 Erläuterung. 287 |
|
28 Übungsaufgaben Teil 9. 288 |
|
28.1 Aufgabe 37 - Interface. 288 |
|
28.1.1 Aufgabenstellung. 288 |
|
28.1.2 Lernziele. 288 |
|
28.1.3 Ergebnis Programmlauf 288 |
|
28.1.4 Lösung. 289 |
|
28.1.5 Betrachtete Themen. 289 |
|
28.1.6 Erläuterung. 290 |
|
28.2 Aufgabe 38 - Mehrere Interfaces. 291 |
|
28.2.1 Aufgabenstellung. 291 |
|
28.2.2 Lernziele. 291 |
|
28.2.3 Ergebnis Programmlauf 291 |
|
28.2.4 Lösung. 292 |
|
28.2.5 Betrachtete Themen. 292 |
|
28.2.6 Erläuterung. 293 |
|
28.3 Aufgabe 39 - Polymorphie. 294 |
|
28.3.1 Aufgabenstellung. 294 |
|
28.3.2 Lernziele. 294 |
|
28.3.3 Ergebnis Programmlauf 294 |
|
28.3.4 Lösung. 295 |
|
28.3.5 Betrachtete Themen. 296 |
|
28.3.6 Ziel der Aufgabe, vertieft 296 |
|
28.4 Aufgabe 40 - Laufzeittyp. 297 |
|
28.4.1 Aufgabenstellung. 297 |
|
28.4.2 Lernziele. 297 |
|
28.4.3 Ergebnis Programmlauf 297 |
|
28.4.4 Lösung. 298 |
|
28.4.5 Betrachtete Themen. 299 |
|
28.4.6 Erläuterung. 299 |
|
28.5 Aufgabe 40a - Angestellte. 300 |
|
28.5.1 Aufgabenstellung. 300 |
|
28.5.2 Lernziele. 300 |
|
28.5.3 Ergebnis Programmlauf 301 |
|
28.5.4 Exkurs - Explizit vs, implizit 301 |
|
28.5.5 Lösung. 302 |
|
28.5.6 Erläuterungen. 305 |
|
28.5.7 Betrachtete Themen. 305 |
|
29 Übungsaufgaben Teil 10. 306 |
|
29.1 Aufgabe 41 - Records. 306 |
|
29.1.1 Aufgabenstellung. 306 |
|
29.1.2 Lernziele. 306 |
|
29.1.3 Lösung. 307 |
|
29.1.4 Betrachtete Themen. 307 |
|
29.1.5 Erläuterung. 307 |
|
29.2 Aufgabe 42 - Projektmitarbeit 309 |
|
29.2.1 Aufgabenstellung. 309 |
|
29.2.2 Lernziele. 310 |
|
29.2.3 Lösung. 311 |
|
29.2.4 Ergebnis Programmlauf 314 |
|
29.2.5 Betrachtete Themen. 314 |
|
29.2.6 Erläuterung. 315 |
|
29.3 Aufgabe 43 - Exception Handling. 316 |
|
29.3.1 Aufgabenstellung. 316 |
|
29.3.2 Lernziele. 316 |
|
29.3.3 Ergebnis Programmlauf 316 |
|
29.3.4 Lösung. 317 |
|
29.3.5 Betrachtete Themen. 317 |
|
29.3.6 Erläuterung. 317 |
|
29.4 Aufgabe 44 - Eigene Exception. 318 |
|
29.4.1 Aufgabenstellung. 318 |
|
29.4.2 Lernziele. 318 |
|
29.4.3 Ergebnis Programmlauf 318 |
|
29.4.4 Lösung. 319 |
|
29.4.5 Betrachtete Themen. 319 |
|
29.4.6 Erläuterung. 320 |
|
29.5 Aufgabe 45 - Generics. 321 |
|
29.5.1 Aufgabenstellung. 321 |
|
29.5.2 Lernziele. 321 |
|
29.5.3 Ergebnis Programmlauf 321 |
|
29.5.4 Lösung. 322 |
|
29.5.5 Betrachtete Themen. 323 |
|
29.5.6 Erläuterung. 323 |
|
30 Übungsaufgaben Teil 11. 325 |
|
30.1 Aufgabe 46 - HashSet 325 |
|
30.1.1 Aufgabenstellung. 325 |
|
30.1.2 Lernziele. 325 |
|
30.1.3 Ergebnis Programmlauf 325 |
|
30.1.4 Lösung. 326 |
|
30.1.5 Betrachtete Themen. 326 |
|
30.1.6 Erläuterung. 327 |
|
30.2 Aufgabe 47 - Maps. 328 |
|
30.2.1 Aufgabenstellung. 328 |
|
30.2.2 Lernziele. 328 |
|
30.2.3 Ergebnis Programmlauf 328 |
|
30.2.4 Lösung. 329 |
|
30.2.5 Betrachtete Themen. 329 |
|
30.2.6 Erläuterung. 330 |
|
30.3 Aufgabe 48 - Streams. 331 |
|
30.3.1 Aufgabenstellung. 331 |
|
30.3.2 Lernziele. 331 |
|
30.3.3 Ergebnis Programmlauf 331 |
|
30.3.4 Lösung. 332 |
|
30.3.5 Betrachtete Themen. 332 |
|
30.3.6 Erläuterung. 333 |
|
30.4 Aufgabe 49 - Lambda. 334 |
|
30.4.1 Aufgabenstellung. 334 |
|
30.4.2 Lernziele. 334 |
|
30.4.3 Ergebnis Programmlauf 334 |
|
30.4.4 Lösung. 335 |
|
30.4.5 Betrachtete Themen. 336 |
|
30.4.6 Erläuterung. 336 |
|
30.5 Aufgabe 50 - Projektmitarbeit 337 |
|
30.5.1 Aufgabenstellung. 337 |
|
30.5.2 Ergebnis Programmlauf 337 |
|
30.5.3 Lernziele. 338 |
|
30.5.4 Lösung. 338 |
|
30.5.5 Betrachtete Themen. 340 |
|
30.5.6 Erläuterung. 340 |
|
31 Exkurs - Zusammenhänge. 343 |
|
31.1 Die Grundidee. 343 |
|
31.2 Arrays. 343 |
|
31.3 Verkettete Listen. 343 |
|
31.4 ArrayList 343 |
|
31.5 LinkedList 344 |
|
31.6 Link-Arrays 344 |
|
31.7 Zusammenfassung. 345 |
|
32 Exkurs - Sammlungen (collection) 346 |
|
32.1 Warum braucht man Sammlungen?. 346 |
|
32.2 Wichtige Sammlungen in Java. 346 |
|
32.2.1 List 346 |
|
32.2.2 Set 346 |
|
32.2.3 Map. 347 |
|
32.3 Sammlungen und Arrays. 347 |
|
32.4 Zusammenhang mit obigen. 347 |
|
33 Exkurs - NoSQL?. 348 |
|
33.1 Vergleich. 348 |
|
33.2 Objekte als Werte. 348 |
|
33.3 Historischer Zusammenhang. 349 |
|
34 Themenindex. 350 |
|
35 Literatur. 354 |
|
H 354 |
|
Staud 354 |
|
U 354 |
|
|
|
Abkürzungsverzeichnis |
|
| Abkürzung |
|
| API |
Application Programming Interface |
| HS |
Hochschule |
| IT |
Informationstechnologie/n |
| JDBC |
Java Database Connectivity |
| JDK |
Java Development Kit. OpenJDK |
| JRE |
Java Runtime Environment |
| KI |
Künstliche Intelligenz |
| OCL |
Object Constraint Language |
| OID |
Objektidentifizierer |
| RDBS |
Relationale Datenbanksysteme |
| UML |
Unified Modeling Language |
| VM |
Virtual Machine. Laufzeitumgebung. Java-Interpreter |
| |
|
|
|
|
|
|
1 Einleitung |
|
|
|
1.1 Konzept |
|
Wie oben schon ausgeführt, ist dieser Text ein Begleittext zu [Staud 2026a], den man auf dieser Web-Seite in der Zeile darüber ansteuern kann und der wichtige Teile der UML 2.5 beschreibt. Dort sind einige Java-Programme eingefügt, die aufzuzeigen, wie wichtige Elemente der objektorientierten Theorie in einer objektorientierten Programmiersprache umgesetzt sind. Es geht also um die Umsetzung ausgewählter Konstrukte und Konzepte der objektorientierten Theorie in einer objektorientierten Sprache (dafür wurde Java gewählt) und somit um die Frage: |
Begleittext zu [Staud 2026a] (oben) |
Wie sind die objektorientierten Konzepte und Konstrukte der UML 2.5 in Java umgesetzt? |
|
In diesem Begleittext werden genau die Elemente von Java erläutert, die für das Verständnis obiger Programme notwendig sind. So sollte z.B. jemand, der objektorientierte oder prozedurale Programmiererfahrung hat, die Java-Programme in [OO2025] nachvollziehen können. |
|
Nicht verwirren lassen: In objektorientierten Programmen (im Gegensatz zu objektorientierten Datenbanken) wird unter Objekten auch die Zusammenstellung von Programmfragmenten für spezifische Aufgaben verstanden. Hier z.B. bei der Klasse File und vielen weiteren (z.B. den sog. Stromklassen, vgl. unten). Es sollten also inhaltlich bedeutsame Objektklassen (Angestellte, ihre Attribute und die mit ihnen zusammenhängenden Methoden) und programmtechnisch notwendige Klassen unterschieden werden. In Java ist dies besonders ausgeprägt. Die gesamte Anwendung besteht aus Klassen, d.h. es müssen auch Vorgänge wie Dateien einrichten/Löschen, in Dateien schreib en, aus Dateien lesen in das Klassen- und Objektkonzept abgebildet werden. Vgl. die Beispiele unten, zu letzterem v.a. die in hsdaten. |
Inhaltlich vs. programm-technisch |
Dies gilt auch für das Hauptprogramm (main), das aus objektorientierter Sicht eine statische Funktion ist. Auch dieses wird, vgl. die Beispiele unten, in eine eigene Klasse gepackt. |
Main |
Keine Einführung in Java |
|
Dieser Text ist keine Einführung in Java. Dafür gibt es umfassende Literatur, siehe z.B. die Literaturliste. Eine umfassende Darstellung, auch mit kleinen Beispielen, findet sich in der API-Dokumentation von Oracle: |
|
https://docs.oracle. com/en/java/java se/21/docs/api/java.base/java/util/regex/Pattern.html |
|
Sollte die Suchmaschine mit der langen Adresse nicht klarkommen, einfach mit |
|
https://docs.oracle.com/en/ |
|
beginnen und im Oracle-Menü weitergehen. |
|
1.2 Bibliotheken |
|
Wie in den Beispielen zu sehen ist, sind in Java viele der benötigten Programmleistungen in Bibliotheken ausgelagert, die bei Bedarf importiert werden können. Zum Beispiel so: |
|
|
import javax.swing.JOptionPane;
|
|
Die wichtigste ist die Java-Standardbibliothek. Ihre einzelnen Pakete (vgl. unten) sind hierarchisch in einer Baumstruktur angeordnet. Die Wurzel ist java, bzw. javax. Danach folgen z.B.: |
|
- java.awt (Abstract Windowing Toolkit). Klassen zur Arbeit mit grafischen Oberflächen.
- java.math. Paket für mathematische Methoden.
- java.util. "Bietet Typen für Datenstrukturen, Raum und Zeit sowie für Teile der Internationalisierung sowie für Zufallszahlen." [Ullenboom 2024, S. 1579]. In den Beispielen hier wird die Klasse java.util.Scanner sehr oft benötigt.
- java.sql und javax.sql. Zur Arbeit mit relationalen Datenbanksystemen.
- java.io und java.nio. "Möglichkeiten zur Ein- und Ausgabe. Dateien werden als Objekte repräsentiert. Datenströme erlauben den sequentiellen Zugriff auf Dateiinhalte." [Ullenboom 2024, S. 1578].
- java.lang. Dieses Paket ist automatisch eingebunden. Enthält u.a. die String-Klasse, die oft benötigt wird.
- javax.swing. Stellt Komponenten für grafische Oberflächen zur Verfügung. Hier wird javax.swing.JoptionPane oft genutzt.
|
|
1.3 Packages |
|
Für die Programmerstellung und -ausführung werden neben dem Java-Compiler eine Vielzahl von Programmbibliotheken benötigt. Diese sind in Paketen organisiert. Pakete bestehen aus inhaltlich zusammenhängenden Klassen für bestimmte Aufgaben, z.B. Bildschirmeingabe, Dateibearbeitung, mathematische Aufgaben. Diese Pakete und/oder Klassen werden mittels Import-Befehlen zum jeweiligen Programm dazugeladen. Vgl. die Programme unten. |
|
Auch die Quellcodedateien eines Projekts werden in Packages zusammengefasst. Entweder durch einen Befehl in der ersten Zeile des Quellprogramms oder, falls dies unterbleibt, in einem default package. Vgl. die Programme unten. |
|
1.4 Formatierung und Schreibweise |
|
Im Text und in den Grafiken wird jeweils ein bestimmtes Schriftformat für Anwendungsbereiche, Objektorientierte Modelle, Klassen, Objekte, Attribute und Methoden verwendet. Außerdem schreibt die UML bei einigen dieser Bezeichner einen bestimmten Aufbau des Wortes bzgl. Kleinschreibung, Großschreibung und Unterstreichung vor. Dieser wird hier schon mal vorgestellt, bei der Einführung des jeweiligen Theorieelements dann erläutert. |
|
Hier die für diesen Text gewählte Formatierung: |
|
- Anwendungsbereiche: Unternehmen (Arial, fett, 11)
- Objektorientierte Modelle: Personalwesen (Arial, fett, Großbuchstaben, 9).
- Klassen: Angestellte (Arial, fett, 9)
- Objekte: Maier:Angestellte (Courier 10, unterstrichen)
- Attribute: datumEinstellung (Arial)
- Methoden/Operationen: einstellen() (Arial 9)
- Programme und Programmfragmente: class Stud {int matrNr; String name; String vName;... (Courier, 10)
|
|
Kommentare in den Programmen |
|
Der doppelte Schrägstrich (//) markiert in Java-Programmen einen Kommentar. Diese können bei der Übernahme der Programme belassen werden. Die in einem Kasten gefassten |
|
Texte in den Programmen |
|
wurden bei der Textbearbeitung in die Programme eingefügt und würden bei der Übernahme der Programme eine Fehlermeldung der Entwicklungsumgebung auslösen. |
|
2 Grundlagen |
|
In den Beispielen wird oftmals der Anwendungsbereich Hochschule gewählt. Abgekürzt mit HS. Klassen sind dann z.B. Studierende (Stud), Attribute sind matrikelNr, name, vName, usw. Siehe die Programmbeispiele unten. |
|
|
|
2.1 Datentypen |
|
Die Datentypen in Java können wie folgt unterschieden werden: |
|
- Elementare Typen: Die elementaren (primitiven) Typen sind in Java eingebaute Datentypen für Zahlen, Unicode-Zeichen und Wahrheitswerte.
- Referenztypen: Mit diesen lassen sich Objektverweise etwa auf Zeichenketten, Datenstrukturen, usw. realisieren.
|
|
Die hier verwendeten elementaren Datentypen von Java sind die Folgenden: |
|
Ganzzahlen |
|
- Byte (Länge 8 Bit)
- Short (16 Bit)
- Int (32 Bit)
- Long ( 64 Bit)
|
|
Fließkommazahlen |
|
- Float (32 Bit)
- Double (64 Bit)
|
|
Sonstige Datentypen |
|
- Boolean (1 Bit)
- Char (16 Bit)
|
|
Nicht-elementare Datentypen |
|
Strings |
|
Sie spielen eine wichtige Rolle, sind aber keine elementaren Datentypen, sondern Verweise auf Objekte. |
|
Arrays |
|
Ein Array (auf deutsch Feld) ist ein Datentyp, der mehrere gleich definierte Werte (Attributsausprägungen, Objekte, ...) zu einer Einheit zusammenfasst. Z.B. mit elementaren Datentypen, aber auch mit komplexeren. In Projekt HS3 wird ein Array genutzt, um zufällig generierte Objekte zu verwalten. Soll das Array mehrdimensional sein, wird an jeder Position des Array ein weiteres Array gespeichert. |
|
2.2 Attribute |
|
Instanzenattribute |
|
In der objektorientierten Theorie sind Attribute meist mit Objekten (Instanzen) verknüpft. Da bedeutet z.B. |
|
|
s100.name
|
|
|
s100.vName
|
|
|
s100.anzSem
|
|
|
s100.gebTag
|
|
dass es eine Klasse Stud (Studierende) gibt mit einer Studierenden (einem Objekt, einer Instanz) s100 und den Attributen name, vName, anzSem (Anzahl Semester) sowie gebTag (Geburtstag) gibt. Der jeweilige Datentyp wird in der Klassendefinition festgelegt. Vgl. Projekt HS5. |
|
Natürlich kann solch ein Instanzenattribut auch im Programm beschrieben werden. Die Variable ii soll hier die Semesteranzahl darstellen. |
|
|
S100.anzSem = ii;
|
|
Die Bedeutung ist wie folgt: das Attribut anzSem (Anzahl Semester) von Objekt s100 erhält den Wert ii. |
|
Klassenattribute |
|
Wie in der UML vorgesehen, kennt Java auch Klassenattribute. Deren Attributsausprägungen beziehen sich auf die jeweilige Klasse als Ganze. In den Beispielen unten wird das Klassenattribut anzSem (Anzahl Semeseter)sehr oft eingesetzt. |
|
|
static int anzStud = 0;
|
|
Obiges ist dann die Deklaration eines Klassenattributs mit Anfangswert. |
|
Variablen |
|
Der Umgang mit Variablen entspricht weitgehend dem der prozeduralen Programmiersprachen. Die folgenden Situationen kommen in den Beispielprogrammen vor: |
|
|
int i = 0; //Integer-Variable
|
|
|
short ii = (short) i; //Umwandlung integer in short integer
|
|
|
boolean fertig = false; //boolesche Variable
|
|
2.3 Logische Operatoren |
|
In vielen Programmen müssen Bedingungen überprüft werden. Das Ergebnis einer Bedingung ist immer einer der beiden Wahrheitswerte |
|
- true (wahr)
- false (falsch)
|
|
Zur Verknüpfung oder Veränderung solcher Bedingungen verwendet Java logische Operatoren. Sie werden beispielsweise in if-Anweisungen oder while-Schleifen eingesetzt. Die wichtigsten logischen Operatoren sind: |
|
Logische Operatoren |
|
| Operator |
Bedeutung |
Beispiel |
| ! |
Nicht (Negation) |
!fertig |
| amp;amp; |
Und |
alter >= 18 amp;amp; alter <= 65 |
| || |
Oder |
note == 1 || note == 2 |
| ^ |
Exklusives Oder (XOR) |
a ^ b |
| |
|
|
Nicht (!) |
|
Der Operator Nicht kehrt den Wahrheitswert um. |
|
|
boolean fertig = false;
|
|
|
|
|
|
if (!fertig) {
|
|
|
System.out.println("Programm läuft weiter.");
|
|
|
}
|
|
Da fertig den Wert false besitzt, wird aus !fertig der Wert true. |
|
Und |
|
Der Operator Und liefert nur dann true, wenn beide Bedingungen erfüllt sind. |
|
|
if (alter >= 18 amp;amp; alter <= 65) {
|
|
|
System.out.println("Alter liegt im zulässigen Bereich.");
|
|
|
}
|
|
Die Bedingung ist also nur wahr, wenn beide Vergleiche gleichzeitig zutreffen. |
|
Oder (||) |
|
Der Operator Oder liefert true, wenn mindestens eine der Bedingungen erfüllt ist. |
|
|
if (note == 1 || note == 2) {
|
|
|
System.out.println("Sehr gutes oder gutes Ergebnis.");
|
|
|
}
|
|
Hier genügt es, wenn eine der beiden Bedingungen wahr ist. |
|
Exklusives Oder (^) |
|
Der Operator XOR (Exclusive OR) liefert true, wenn genau eine der beiden Bedingungen wahr ist. |
|
|
boolean a = true;
|
|
|
boolean b = false;
|
|
|
|
|
|
System.out.println(a ^ b);
|
|
führt zu folgender Ausgabe: |
|
|
true
|
|
Sind dagegen beide Bedingungen wahr oder beide falsch, liefert ^ den Wert false. Insgesamt gelten folgende Wahrheitswerte: |
|
Wahrheitswerte |
|
| A |
B |
A amp;amp; B |
A || B |
A ^ B |
| false |
false |
false |
false |
false |
| false |
true |
false |
true |
true |
| true |
false |
false |
true |
true |
| true |
true |
true |
true |
false |
| |
2.4 Referenzen |
|
In einem Text zur Objektorientierung mit Java ist oftmals von Referenzen die Rede. Deshalb soll der Begriff hier geklärt werden. Grundsätzlich gilt: |
|
Eine Referenz ist immer ein Verweis auf ein Objekt. |
|
Der einfachste Fall |
|
Beispiel mit der Klasse Stud (Studierende), die im Text oftmals verwendet wird: |
|
|
Stud s1 = new Stud();
|
|
Hier ist |
|
|
Stud s1;
|
|
eine Referenzvariable. Sie enthält einen Verweis auf ein Objekt der Klasse Stud. |
|
Referenzen bei Vererbung |
|
Nehmen wir Vererbung hinzu, wieder mit einem Beispiel, das hier im Text öfters vorkommt: Superklasse Fahrzeug, Subklassen PKW und LKW. Jetzt schreibt man |
|
|
Fahrzeug f;
|
|
Die Referenzvariable besitzt den Typ |
|
|
Fahrzeug
|
|
Nun kann sie auf verschiedene Objekte zeigen. |
|
|
f = new PKW();
|
|
oder |
|
|
f = new LKW();
|
|
Die Referenz bleibt dieselbe. Nur das Objekt ändert sich. Dies funktioniert, weil ein PKW ein spezielles Fahrzeug ist, ebenso ein LKW. Deshalb darf eine Fahrzeug-Referenz auf beide zeigen. |
|
Polymorphie |
|
Dies führt zum Konzept der Polymorphie. Wird |
|
|
f.fahren();
|
|
aufgerufen, schaut Java nicht nur auf den Typ der Referenz |
|
|
Fahrzeug
|
|
sondern auf das Objekt. Zeigt |
|
|
f
|
|
auf einen PKW, wird |
|
|
PKW.fahren()
|
|
aufgerufen. Zeigt dieselbe Referenz später auf einen LKW, wird |
|
|
LKW.fahren()
|
|
aufgerufen. |
|
Somit gilt: Bei der Polymorphie unterscheidet man zwischen dem Typ der Referenzvariablen und der Klasse des Objekts. Der Typ der Referenzvariablen wird bereits beim Übersetzen des Programms festgelegt. Die Klasse des Objekts kann sich während des Programmlaufs ändern. Welche überschriebene Methode tatsächlich ausgeführt wird, richtet sich nach der Klasse des Objekts. |
|
Referenztyp und Objekttyp |
|
Dies führt zur Unterscheidung von Referenz- und Objekttyp. Bei |
|
|
Fahrzeug f = new PKW();
|
|
gibt es zwei Typen. Den Referenztyp |
|
|
Fahrzeug
|
|
und den Objekttyp |
|
|
PKW
|
|
Diese beiden müssen nicht identisch sein. |
|
Definition |
|
Damit kann der Begriff Referenz wie folgt definiert werden: |
|
Eine Referenz ist eine Variable, die nicht das Objekt selbst enthält, sondern einen Verweis auf ein Objekt. Mehrere Referenzen können auf dasselbe Objekt zeigen. Bei Vererbung kann eine Referenz der Oberklasse auch auf Objekte ihrer Unterklassen verweisen. |
|
2.5 Der Begriff "Typ" in Java |
|
In diesem Text ist oft von Typ als objektorientiertem Konstrukt die Rede. Deshalb hier eine Klärung. |
|
Ganz allgemein bedeutet Typ in Java folgendes: Ein Typ legt fest, welche Werte eine Variable annehmen darf und welche Operationen auf diesen Werten zulässig sind. |
|
Beispiele: |
|
|
int alter;
|
|
|
double gehalt;
|
|
|
String name;
|
|
Hier sind |
|
|
|
|
jeweils Typen. Sie bestimmen, |
|
- welche Werte gespeichert werden können,
- welche Methoden oder Operationen verwendet werden dürfen.
|
|
Das ist sozusagen der einfache Fall, der sich auch in der andernorts üblichen Bezeichnung Datentyp äußert. Interessanter ist der folgende Fall. |
|
Typen bei Objekten |
|
Auch Klassen sind Typen. Betrachten wir: |
|
|
Stud s;
|
|
Hier ist Stud der Typ der Variablen s. Das bedeutet, s darf nur auf Objekte der Klasse Stud (oder einer Unterklasse von Stud) verweisen. |
|
Typen bei Referenzvariablen |
|
In obigem Abschnitt liegt die Referenzvariable Fahrzeug f vor. Dabei ist Fahrzeug der Typ der Referenzvariablen. Der Compiler weiß dadurch: |
|
- f darf auf Fahrzeuge zeigen,
- also auch auf PKW oder LKW,
- und es dürfen nur Methoden aufgerufen werden, die in Fahrzeug bekannt sind.
|
|
Nun wird geschrieben: f = new PKW(); Damit gilt: Der Typ der Referenzvariablen Fahrzeug und die Klasse des Objekts von PKWsind zwei verschiedene Dinge. |
|
Definition |
|
Damit kann man den Begriff Typ in Java wie folgt definieren: |
|
|
3 Konsolenarbeit |
|
|
|
3.1 Ausgeben auf Konsole |
|
Die Ausgabe von Daten auf der Konsole erfolgt mit dem Befehl System.out.print in seinen Varianten, z.B.: |
|
|
System.out.print("Matrikelnummer: "); //ohne Zeilenvorschub
|
|
|
System.out.println(); //mit Zeilenvorschub
|
|
|
System.out.printf("MNr: " + mNr);
|
|
Printf bedeutet: als erstes wird ein String verlangt, dann können beliebig viele weitere Übergabewerte folgen. Vgl. [Ullenboom 2024, S. 471]. |
|
Die Ausgabe von Objektdaten auf der Konsole erfolgt entsprechend: |
|
|
System.out.println(stud.matrikelNr);
|
|
|
System.out.println(stud.vName + " " + stud.name);
|
|
|
System.out.println(stud.plz + " " + stud.ort);
|
|
|
System.out.println(stud.strasse + " " + stud.hausnummer);
|
|
Oben: Das Objekt stud mit einigen seiner Attribute. Vgl. zur Klasse Stud die Programme unten, z.B. HS1. |
|
3.2 Lesen von der Konsole |
|
Mit java.util.scanner |
|
Für das Lesen von der Konsole (z.B. Benutzerangaben) gibt es unterschiedliche Varianten. Die einfachste ist die mit der Klasse java.util.Scanner. Eine einfache zeilenweise Konsoleneingabe mit Einlesen der Eingabe in eine Variable kann mit ... |
|
|
java.util.Scanner(System.in)
|
|
realisiert werden. Der Quellcode sieht dann z.B. so aus (vgl. HS5): |
|
|
...
|
|
|
System.out.println("Objekt eingeben (j/n): ");
|
|
|
String s = new java.util.Scanner(System.in).nextLine();
|
|
|
|
|
|
switch(s) {
|
|
|
case "j":
|
|
|
System.out.println("Eingabe:");
|
|
|
System.out.print("Matrikelnummer: ");
|
|
|
int mNr = new java.util.Scanner(System.in).nextInt();
|
|
|
...
|
|
Auf dem Bildschirm ergibt sich das mit Windows 11 wie folgt: |
|

|
|
Weitere Beispiele |
|
|
String e1 = new java.util.Scanner(System.in).nextLine();//String einlesen
|
|
|
int int i = new java.util.Scanner(System.in).nextInt();
|
|
|
double dd = new java.util.Scanner(System.in).nextDouble();//Datentyp double einlesen
|
|
Zu beachten ist die zum Datentyp passende Methodenbezeichnung. |
|
Mit dem Swing-Paket |
|
Das Swing-Paket erlaubt grafisch gestaltete Eingabefenster. Im Quellcode muss folgendes eingegeben werden: |
|
|
import javax.swing.JOptionPane;
|
|
... |
|
|
String eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Ihre Wahl");
|
|
Dann sieht das Eingabefenster so aus: |
|

|
|
Varianten: |
|
|
eingabe = JOptionPane.showInputDialog("Welcher Student (0 / 1)?");
|
|
|
int nr = Integer.parseInt(eingabe);
|
|
Dabei liefert parseInt die Umwandlung der Stringvariablen in eine Integervariable. |
|
Anmerkung |
|
Diese Option steht nur zur Verfügung, falls in Eclipse das module-info.java eingerichtet ist: |
|

|
|
In der Datei steht, bei diesem Beispiel und im einfachsten Fall: |
|
|
/**
|
|
|
*
|
|
|
*/
|
|
|
/**
|
|
|
*
|
|
|
*/
|
|
|
module HS1 {
|
|
|
requires java.desktop;
|
|
|
}
|
|
4 Klassen, Objekte, Methoden |
|
Hier nun ein Blick auf das Einrichten von Klassen, das Instanziieren von Objekten und den Einsatz von Methoden. |
|
|
|
4.1 Klassen einrichten |
|
4.1.1 Grundlagen |
|
Mit Angabe der Attribute (Instanzvariablen) und dem Standardkonstruktor, einfachste Form (vgl. HS2, Stud.java): |
|
|
public class Studierende {
|
|
|
public String matrikelNr;
|
|
|
public String name;
|
|
|
public String vName; //Vorname
|
|
|
public String plz;
|
|
|
public String ort;
|
|
|
public String strasse;
|
|
|
public int hausnummer;
|
|
|
}
|
|
Mit Instanzattributen, einem Klassenattribut, einem ausgewiesenen Konstruktor und einer Methode (vgl. HS1, Stud.java): |
|
|
public class Stud { //Beginn der Klassendefinition
|
|
|
public int mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName; //Vorname
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
|
|
|
Klassenattribut/statisches Attribut mit Anfangswert. Static bedeutet: Es ist ein Klassenattribut. D.h. seine Attributsausprägungen beziehen sich auf die Klasse als Ganzes, nicht auf einzelne Objekte. Programmiertechnisch bedeutet dies, dass seine Werte ohne Objektaufruf bearbeitet und aufgerufen werden können. |
|
|
static int anzStud = 0
|
|
|
|
|
Konstruktor, bei dem das Klassenatttribut für die Anzahl der Objekte der Klasse hochgezählt wird. |
|
|
public Stud () {
|
|
|
anzStud++;
|
|
|
}
|
|
|
|
|
Instanzmethode zum Ausgeben der Daten eines Objekts: |
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
4.1.2 Sichtbarkeit |
|
Wie in der UML vorgesehen, kann auch in Java der Zugriff auf die Attribute und Methoden einer Klasse durch Sichtbarkeitsmodifizierer kontrolliert werden: |
Modifier |
- Public (öffentliches Attribut, öffentliche Variable, öffentliche Methode) bedeutet, auf die Klasse kann vom Paket aus, von abgeleiteten Klassen und von außerhalb zugegriffen werden.
- Protected (internes Attribut, interne Variable, interne Methode) bedeutet, es kann vom Paket aus und von abgeleiteten Klassen zugegriffen werden.
- Paketsichtbar (package-private) ist eingestellt, falls kein Modifizierer angegeben wird. Diese Sichtbarket bedeutet, dass nur von anderen Klassen im gleichen Paket auf die Klasse zugegriffen werden kann.
- Private (privates Attribut, private Variable, private Methode) bedeutet, es kann nur innerhalb der Klasse zugegriffen werden.
|
|
Damit ist auch ein zentrales Anliegen der objektorientierten Theorie, die Möglichkeit der Methoden- und Datenkapselung, erfüllt. Daten, die auf Attributen/Variablen beruhen, und Methoden sollten nicht unberechtigt geändert bzw. aufgerufen werden können. Die Modifier Protected und Private erlauben dies in adäquater abgestufter Form. |
Kapseln |
Das Ganze wird noch verfeinert durch die Getter- und Setter-Methoden, die sozusagen trotz Kapselung den Zugriff über definierte Methoden erlauben: |
Getter, Setter |
- Eine Getter-Methode erlaubt trotz Zugriffsbeschränkungen den Zugriff auf die aktuelle Attributsausprägung eines Objekts.
- Eine Setter-Methode erlaubt trotz Zugriffsbeschränkungen das Beschreiben einer Attributsausprägung eines Objekts.
|
|
Beidesmal über Methoden, die bei der Klasse definiert sein müssen. Betrachten wir beispielhaft eine Klasse Stud (Studierende), wie sie unten in den Programmen sehr häufig vorkommt: |
Vgl. auch Projekt HS8 |
|
public class Stud {
|
|
|
public String mNr; //Matrikelnummer
|
|
|
private String name;
|
|
... |
|
Hier soll der Namen mit private gekapselt sein. Bei der Klasse werden dann die Getter- und Setter-Methoden in einfachster Form so hinterlegt: |
|
|
//Getter
|
|
|
public String getName(){
|
|
|
return name;
|
|
|
}
|
|
|
//Setter
|
|
|
public void setName(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
Dann kann im Hauptprogramm (also im selben Paket) der Name mit den Methoden getName() bzw. setName() gelesen oder überschrieben werden. Vgl. Projekt HS8. |
|
Pakete: Zusammenfassung der Klassen eines Projekts. Vgl. die Programme unten. Das Schlüsselwort ist package, die Deklaration erfolgt in der ersten Zeile des Programms, z.B. mit package hochschule. |
|
4.2 Objekte einrichten - Konstruktoren |
|
Hier einige Beispiele für Konstruktoren aus den folgenden Programmen. |
|
(1) Der Standardkonstruktor (vgl. HS4), der automatisch aufgerufen wird: |
|
|
Noten n1 = new Noten();
|
|
n1 ist die Bezeichnung des neuen Objekts. |
|
(2) Ein Konstruktor mit einer Klassenvariablen, die bei jeder Objekterzeugung hochgezählt wird (anzStud = Anzahl Studierende): |
|
|
public Stud () {
|
|
|
anzStud++;
|
|
|
}
|
|
(3) Der Standardkonstruktor mit anschließendem Beschreiben des Objekts: |
|
|
public class HS2 {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s0 = new Stud(); //Aufruf Konstruktor
|
|
|
s0.mNr = 12345;
|
|
|
s0.name = "Sauer";
|
|
|
s0.vName = "Otto";
|
|
|
s0.anzSem = 5;
|
|
|
s0.gebTag = "21.09.2002";
|
|
|
|
|
(4) Instanziierung mit Beschreiben des Objekts beim Aufruf des Konstruktors (vgl. HS4, HP): |
|
Aufruf im HP: |
|
|
Stud s0 = new Stud("1111", "Maier", "Klara", 5, "21.09.2002");
|
|
Konstruktor in Klasse Stud: |
|
|
public Stud (String mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
anzStud++;
|
|
|
}
|
|
Zu beachten ist das keyword this, das die Zuordnung der Parameterwerte auf die Attribute des Objektes realisiert. |
|
(5) Verschachtelte Konstruktoren: |
|
|
stud1 = new BufferedReader (new FileReader("C:/Meine Dateien/" + dateiBez + ".txt"));
|
|
Der eine Konstruktor ist Parameter im anderen. Näheres dazu in Abschnitt 6.1. |
|
Abschließend noch das Einlesen von Objektdaten von der Konsole: |
|
|
eingabe = JOptionPane.showInputDialog("Matrikelnummer:");
|
|
|
stud.matrikelNr = eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Name:");
|
|
|
stud.name = eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Vorname:");
|
|
|
stud.vName = eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Postleitzahl:");
|
|
|
stud.plz = eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Ort:");
|
|
|
stud.ort = eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Straße:");
|
|
|
stud.strasse = eingabe;
|
|
|
eingabe = JOptionPane.showInputDialog("Hausnummer: ");
|
|
|
stud.hausnummer = Integer.parseInt(eingabe);
|
|
Klasse Stud mit Objekt stud (vgl. HS1). Mit Einlesen von Konsole. |
|
4.3 Record-Klassen |
|
Java erlaubt die Anlage von sog. Record-Klassen, die wohl von den Datensätzen (records) relationaler Datenbanken motiviert sind. Sie erlauben (für entsprechende Daten) eine schlankere Programmierung, v.a., weil sie eine schlankere Syntax aufweisen und weil einige Methoden gleich bei der Einrichtung durch den Konstruktor angelegt werden. |
Vgl. die Beispiele in den Programmen, z.B. HS6 |
Die Besonderheiten: |
|
- Record-Klassen verwalten für ihre Objekte nur Attribute (hier auch Record-Komponenten genannt).
- Ihre Objekte sind unveränderlich.
- Die Deklaration erfolgt mit dem Schlüsselwort record. Vgl. für die sonstige Syntax das Beispiel in Projekt HS6.
- Ihr Konstruktor übergibt in einer Parameterliste die Attributsausprägungen.
- Er erzeugt die Methoden equals(), toString() und hashCode(). Falls nötig, können sie verändert werden. Weitere Methoden können hinzugefügt werden.
- Für jedes Attribut wird automatisch eine Abfragemethode erstellt.
- Es gibt Schnittstellen, aber keine Vererbung
|
|
Die Methode equals() wird zum Vergleich von records verwendet. Sie sieht zwei records als gleich an, wennn sie vom gleichen Typ sind und falls jede Komponente denselben Wert hat. Dies leistet hier der Gleichheitsoperator nicht. |
|
Der Zugriff auf die Instanzvariablen erfolgt über Methoden mit derselben Bezeichnung wie das jeweilige Attrbut. Gibt es also ein Attribut name, steht die Methode name() zur Verfügung. |
|
Das Beispiel in HS6 stellt dieses Programmierkonstrukt dar. |
|
Vgl. [Ullenboom 2024, S. 897], [Kofler 2023, S. 220f] und [Habelitz 2025, S. 387] für weitergehende Beschreibungen. |
|
4.4 Aufruf von Methoden und Attributen |
|
Hier wird gezeigt, wie der Aufruf von Methoden und Attributen in Java geregelt ist. |
|
(1) Aufruf einer Instanzmethode aus dem HP heraus (HS2): |
|
|
public class HS2 {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s0 = new Stud();//Standardkonstruktor
|
|
|
s0.mNr = 12345;
|
|
|
s0.name = "Sauer";
|
|
|
s0.vName = "Otto";
|
|
|
s0.anzSem = 5;
|
|
|
s0.gebTag = "21.09.2002";
|
|
|
System.out.println("\n------\n");
|
|
|
|
|
|
s0.ausgeben();
|
|
|
|
|
In Klasse Stud von HS1 wurde die Methode wie folgt angelegt: |
|
|
public class Stud {
|
|
|
.....
|
|
|
//Methode zum Ausgeben der Daten eines Objekts
|
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
(2) Aufruf eines Attributs (Variablen) einer anderen Klasse (HS4): |
|
|
System.out.println("\nAusgabe der Noten in Klasse HS4:");
|
|
|
System.out.println("Matrikelnummer: " + s1.mNr + "\nName: " + s1.name + "\nVorname: " + s1.vName + "\nFach: " + n1.fach + "\nNote: " + n1.note);
|
|
Mit Objektbezeichnung und Attributsname, verknüpft durch einen Punkt, wird die jeweilige Attributsausprägung angefordert. |
|
Das führt zu folgender Ausgabe: |
|

|
|
5 Prozedurales |
|
Java ist umfassend objektorientert. Es gibt nur Klassen, auch das Hauptprogramm ("main") wird in eine Klasse gepackt. Aber auch eine solche Programmiersprache benötigt prozedurale Komponenten, wenn es um die Realisierung von Methoden geht, um die dynamischen Aspekte der Anwendung. Es sind die üblichen von C und anderen prozeduralen Sprachen bekannten Konstrukte. Deren Ausprägung in Java wird hier kurz vorgestellt. |
|
|
|
5.1 Schleifen und Verzweigungen |
|
Eine While-Schleife mit enthaltener Switch-Verzweigung von Projekt HS2: |
|
|
boolean fertig = false;
|
|
|
while (!fertig) {
|
|
|
System.out.println(" ");
|
|
|
System.out.println("1 = Eingabe");
|
|
|
System.out.println("2 = Ausgabe");
|
|
|
System.out.println("3 = StudDaten wechseln");
|
|
|
System.out.println("4 = Programm beenden");
|
|
|
eingabe = JOptionPane.showInputDialog("Ihre Wahl");
|
|
|
int auswahl = Integer.parseInt(eingabe);
|
|
Oben: Menü auf der Konsole. Lesen der Nutzereingabe. |
|
|
|
|
|
switch(auswahl) {
|
|
Beginn der Switch-Verzweigungen, wie man es kennt mit case x und break. |
|
|
case 1:
|
|
|
eingabe = JOptionPane.showInputDialog("Matrikelnummer:");
|
|
|
stud.matrikelNr = eingabe;
|
|
|
.....
|
|
|
break;
|
|
|
case 2:
|
|
|
System.out.println(stud.matrikelNr);
|
|
|
System.out.println(stud.vName + " " + stud.name);
|
|
|
System.out.println(stud.plz + " " + stud.ort);
|
|
|
System.out.println(stud.strasse + " " + stud.hausnummer);
|
|
|
break;
|
|
|
case 3:
|
|
|
eingabe = JOptionPane.showInputDialog("Welcher Student (0 oder 1)?");
|
|
|
int nr = Integer.parseInt(eingabe);
|
|
|
|
|
Verzweigung mit if/else. |
|
|
if (nr == 0) {
|
|
|
stud = stud0;
|
|
|
}
|
|
|
else if (nr ==1) {
|
|
|
stud = stud1;
|
|
|
} else {
|
|
|
System.out.println("Eingabefehler!");
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
case 4:
|
|
|
fertig = true;
|
|
|
break;
|
|
|
default:
|
|
|
System.out.println("Eingabefehler!");
|
|
|
}
|
|
|
}
|
|
Vgl. für weitergehende Informationen die Projektbeschreibung unten (HS2). |
|
5.2 Das Try/Catch-Konstrukt |
|
In Java wird ein Programmierkonstrukt angeboten, das kurz so beschrieben werden kann: Der Konstrollfluss wird unterteilt in einen Abschnitt mit dem gewünschten Ablauf ("try") und einen, der im Fehlerfall bei Laufzeitfehlern aktiv wird ("catch"). |
|
Der Try-Block kann unterschiedlich lang sein. Auch sehr kurz, z.B. für einen Einlesevorgang mit While-Schleife (hsdaten/Klasse Lesen) oder eine Arbeit mit dem Dateisystem, wie in hsdaten/Schreiben. Natürlich muss es ein zusammenhängender Abschnitt sein, so dass die Fehlermeldung im Catch-Block aussagekräftig ist. |
Vgl. die Beispiele im Projekt hsdaten. |
Die folgende Abbildung erläutert die Syntax am Beispiel eines Programmfragments von hsdaten/Erstellen.java. Mit try und catch werden die beiden Abschnitte getrennt. Im Try-Block findet sich ein Programmabschnitt, bei dem eine Datei in einem bestimmten Verzeichnis (hier unter Windows) eingerichtet werden soll. Der Fehler, dass die Datei bereits existiert, wird direkt im Programm abgefangen und dem Nutzer gemeldet. Eventuelle Laufzeitfehlermeldungen werden im Catch-Block ausgeführt. Dies sind erstmal vordefinierte Meldungen, die aber spezifiziert werden können. Vgl. Kapitel 7 und die dort gegebenen Hinweise. |
|

|
|
Abbildung 5.2-1: Das Try/Catch-Konstrukt in Java. |
|
Vgl. Kapitel 9 in [Habelitz 2025] für eine weitergehende Beschreibung. Für zahlreiche Beispiele vgl. die Projekte unten, v.a. hsdaten. |
|
6 Textdateien bearbeiten |
|
|
|
6.1 Einleitung |
|
Für das Lesen aus und das Schreiben in Dateien werden (Daten-)Stromklassen benötigt, mit denen es möglich ist, "die abstrakten Methoden von Reader, Writer, InputStream und OutputStream auf Dateien abzubilden" [Ullenboom 2024, S. 1919]. Solche Stromklassen sind |
(Daten-)Strom-klassen |
- FileInputStream,
- FileReader und
- FileOutputStream.
|
|
Die hier zur Arbeit mit Textdateien benötigten Programme, werden im Projekt hsdaten vorgestellt: |
|
- Erstellen.java zum Erstellen einer TXT-Datei in einem beliebigen Verzeichnis mit der Klasse File.
- Schreiben.java für das Schreiben eines Variablentextes in eine Datei mit der Klasse FileWriter.
- Schreiben2.java für das Schreiben in eine Datei mit den Klassen FileWriter und BufferedWriter.
- Lesen.java für das Lesen einer TXT-datei mit der Klasse BufferedReader.
- ErzeugLoesch.java für das Erzeugen, Beschreiben und Löschen einer TXT-Datei mit den Klassen FileWriter, BufferedWriter und einer grafischen Eingabe mit JOptionPane.showInputDialog.
- Anhaengen.java für das Anhängen von Daten in eine TXT-Datei. Dateneingabe mit Scanner.
- EinlesenCSV.java für das Lesen und Ausgeben einer CSV-Datei. Dateneingabe mit Scanner
- Loeschen.java für das Löschen einer Datei. Dateneingabe mit Scanner.
|
|
6.2 Paket java.io |
|
Die gesamte für die Arbeit mit Dateien notwendige Funktionalität ist im Paket java.io vorhanden. Davon werden hier nur die Lese- und Schreibvorgänge mit TXT-Dateien benötigt. Es geht also um Eingabeströme (Eingeben in die Datei) und Ausgabeströme (Lesen aus der Datei). Außerdem um das Einrichten und Arbeiten mit Verzeichnissen und Dateien. |
Vgl. die Abbildung unten. |
Die benötigten Komponenten von java.io müssen im jeweiligen Programm importiert werden. Entweder als Ganzes mit |
|
|
Import java.io.*
|
|
oder über die Klassen, z.B: so: |
|
|
import java.io.BufferedReader;
|
|
|
import java.io.FileReader;
|
|
|
import java.io.FileWriter;
|
|
Zu den Klassen vgl. unten. |
|
6.3 Zugriffe mit Streams |
|
Bei den Eingabe- und Ausgabeströmen bzgl. Textdateien wird zwischen Character Streams und Byte Streams unterschieden: |
|
- Character Streams bestehen aus 16-Bit-Einheiten mit Char-Zeichen, kodiert nach Unicode.
- Byte Streams bestehen aus 8-Bit-Einheiten mit dem Datentyp Byte.
|
|
Die Basisfunktionalität wird durch abstrakte Klassen bereitgestellt. Dies sind Reader und Writer für Character Streams und InputStream sowie ExportStream für Byte Streams. Die eigentliche Arbeit leisten dann davon abgeleitete Klassen, die jeweils in ihrer Bezeichnung die der abstrakten Klasse enthalten. Zum Beispiel: |
|
- BufferedInputStream
- BufferedReader
- BufferedWriter
- FileWriter
- FileReader
|
|
6.4 Klasse File |
|
Die abstrakte Klasse File aus dem Paket java.io stellt die für den Umgang mit Dateien und Verzeichnissen benötigte Funktionalität zur Verfügung. Ein Objekt dieser Klasse repräsentiert jeweils ein Verzeichnis oder eine Datei. Im Fall von Dateien enthält das Objekt Daten wie Bezeichnung, Pfad, Größe, usw., nicht aber die Inhalte der Datei. |
File |
Eine wichtige der Klasse File zugeordnete Methode ist createNewFile(). Vgl. [hsdaten, Erstellen.java]. Mit dem Konstruktor |
|
|
Public File(String pathname)
|
|
wird ein Objekt von File im angegebenen Zugriffspfad eingerichtet. |
|
Die davon abgeleiteten Klassen tragen auch hier in ihrer Bezeichnung die der abstrakten Klasse. Zum Beispiel: |
|
- FileWriter. Richtet ein Objekt ein, mit dem in Dateien geschrieben werden kann. Es stellt die Verbindung her zu einer Datei aus dem Dateisystem des jeweiligen Rechners. Wichtige Methoden dieser Klasse sind write(), close().
- FileReader. (vgl. hsdaten/Lesen.java). Dessen "Objekte" stellen eine Verbindung zu einer Datei her, so dass ein zeilenweiser Lesezugriff ermöglicht wird.
- BufferedReader. Liest mit seiner Methode readLine() zeilenweise aus einer vom FileReader bereitgestellten Datei. Wenn das Ende der Datei erreicht ist, liefert readLine() als Ergebnis null.
- BufferedWriter. Liefert einen Eingabestrom, der "gepuffert" Unicode-Zeichen schreibt.
|
|
"Gepuffert" (buffered) meint hier, das der Ein- und Ausgabestrom nicht direkt ausgeführt wird. Die Daten werden also nicht zeitgleich mit der Lese- oder Schreibanweisung ausgeführt, sondern in einen Puffer geschrieben und erst transportiert, wenn der Puffer voll ist oder der Stream geschlossen wird. |
|
Beispiele |
|
hsdaten, Schreiben.java |
|
|
String dateiBez = "stud003";
|
|
|
stud1 = new FileWriter("C:/Meine Dateien/" + dateiBez + ".txt");
|
|
|
String text = "Sinnspruch Nummer 3\n"
|
|
|
+ "Der Weg ist weit, der Weg ist lang,"
|
|
|
+ " doch uns wird - wie immer - nicht bang";
|
|
|
stud1.write(text);
|
|
|
stud1.close();
|
|
Erläuterung: |
|
- Im obigen Beispiel wird zuerst die Dateibezeichnung in eine String-Variable geschrieben.
- In der zweiten Zeile wird ein Objekt der Klasse FileWriter erzeugt mit den Angaben zum Verzeichnis und zur Datei.
- Dann wird die Stringvariable text beschrieben
- Anschließend wird mit der Instanzmethode write() in das Objekt stud1 der Text der String-Variablen geschrieben.
- Abschließend wird das Objekt stud1 wieder geschlossen.
|
|
Das Ergebnis (mit Notepad): |
|

|
|
hsdaten, Schreiben2.java, EinlesenCSV.java |
|
Hier nun ein Beispiel für den Einsatz der Klasse BufferedWriter bei einem Schreibvorgang. Zuerst wird ein FileWriter-Objekt erzeugt. Durch Verzicht auf Angabe eines Verzeichnissses, wird die Datei im Standardverzeichnis (hier, mit Windows 11: c:/eclipse/hsdaten) angelegt. |
|
Der Schreibvorgang soll mit BufferedWriter realisiert werden (obwohl diese Datenmenge dies nicht nahelegt). Dazu wird ein BufferedWriter-Objekt buwr erzeugt, das als Input das zuvor erstellte FileWriter-Objekt fiwr hat: |
|
|
FileWriter fiwr = new FileWriter("stud07.txt");
|
|
|
BufferedWriter buwr = new BufferedWriter(fiwr);
|
|
Danach kann dann in das Objekt (die Datei) buwr geschrieben werden. In hsdaten/schreiben2 geschieht dies mit den Methoden write() und newLine(). |
|
Das Zusammenwirken der beiden Klassen kann auch verschachtelt programmiert werden. Im folgenden Beispiel aus hsdaten/EinlesenCSV geht es um einen Lesevorgang. Gelesen wird aus der Datei mitarbeiter.csv. Die Verschachtelung erfolgt auf Basis der Konstruktoren der beiden Klassen. Der Konstruktor von BufferedReader erhält als Parameter die Instanziierung von FileReader, die als Parameter den Dateinamen über die Variable fileName hat. |
|
|
String fileName = "mitarbeiter.csv";
|
|
|
stud1 = new BufferedReader(new FileReader(fileName ));
|
|
java.util.Formatter |
|
Die unten auch verwendete Klasse java.util.Formatter dient (hier) dazu, die Eingaben in eine Textdatei zu formatieren. Hier ein Beispiel aus hsdaten/Anhaengen.java: |
|
|
File datei = new File("C:/Meine Dateien/" + fileName + ".txt");
|
|
|
FileWriter writer = new FileWriter(datei, true);
|
|
|
Formatter formatter = new Formatter(writer)) {
|
|
Er benötigt ein Objekt der Klasse FileWriter als Parameter und stellt dann die benötigte Programmfunktionalität bereit. Die Methode format erlaubt dann die Spezifizierung: |
|
|
formatter.format("%s%n", newInput);
|
|
Vgl. die weiteren Ausführungen hierzu in hsdaten/Anhaengen.java. |
|
Die folgende Abbildung zeigt die hier verwendeten Klassen im Überblick. |
|

|
|
Abbildung 6.4-1: Klassen für Dateibearbeitung |
|
Da die IO-Klassen Systemressourcen benötigen, sollte man die entsprechenden Objekte schließen, wenn sie nicht mehr benötigt werden. Dies geschieht mit der Methode close(). |
|
Für weitergehende Beschreibungen vgl. die Literatur, z.B.: |
|
- [Ullenboom 2022, Abschnitt 20.4.4] für eine Beschreibung der Basisklase Writer und Abschnitt 20.4.6 für eine Beschreibung der Basisklasse Reader.
- [Ratz 2018, Kapitel 17] enthält eine verständliche und fundierte Darstellung der "Ein- und Ausgabe über I/O-Streams".
|
7 Exceptions |
|
Exceptions bedeutet hier Laufzeitfehler. Sie wurden in den unten gezeigten Programmen v.a. mit dem Try/catch-Konstrukt bei Zugriffen auf Dateien eingesetzt (IOExceptions). Exception ist auch eine Klasse, deren Objekte Fehlermeldungen sind. Die allgemeinste Fehlermeldung hat die Bezeichnung e. Sie kann auf den konkreten Fall zugeschnitten werden. |
|
In den jeweiligen Programmen muss diese Klasse mit import java.io.IOException importiert werden. Dies ist unten auch geschehen, v.a. für die Arbeit mit dem Dateisystem: |
|
- Zum Melden des Scheiterns der Methode createNewFile() (hsdaten/Erstellen.java) in einer Try/catch-Situation.
- Falls das Einrichten einer Datei und/oder des Schreibens in die Datei schief geht (hsdaten/Schreiben.java), ebenfalls in einer Try/catch-Situation.
- Beim Start eines Programms mit Dateizugriffen (hsdaten/Schreiben2.java).
|
|
Vgl. für eine ausführliche Beschreibung [Habelitz 2025, Kapitel 9]. |
|
|
|
8 Projekt HS1 - Objekterzeugung |
|
HS1 steht für das erste Projekt zum Anwendungsbereich Hochschule. Die Programme mit den Bezeichnungen HS1-HS9 und hsdaten dienen zur exemplarischen Darstellung wichtiger Theorieelemente. Dabei werden, gemäß dem Konzept dieses Textes, die Ausführungen zur Theorie gleich ergänzt mit aussagekräftigen Programmen. |
|
Aufbau der Beschreibungen |
|
Der Aufbau dieser Projektbeschreibungen ist immer gleich: Zuerst das Hauptprogramm (Klasse HP), dann die inhaltlichen Klassen. Viele Programme werden im Text zum einen ohne Erläuterungen angegeben, zum Kopieren und für den schnellen Überblick. Zum anderen aber auch mit Erläuterungen, für das schnelle Verstehen. Im letzten Abschnitt wird jeweils ein exemplarischer Programmlauf angegeben. In einem abschließenden Abschnitt werden jeweils die betrachteten Themen aufgelisted. |
|
Bei diesen Beispielsprojekten erfasst die Klasse HP den Programmablauf. Dazu wird wie immer in Java ein Hauptprogramm ("main") eingerichtet: |
|
|
public static void main(String[] args)
|
|
Zum Projekt HS1 |
|
Hier geht es schlicht darum, eine einfache Klasse Stud (Studierende) anzulegen, Objekte zu erzeugen und mit ihnen zu arbeiten. Die Klasse Stud beschreibt Studierende, ein weiterer Programmteil, sozusagen das Hauptprogramm (HP) beschreibt die dynamischen Aspekte, hier lediglich einige Handlungen mit den Objekten. |
|
Die Java-Erschaffer haben festgelegt, dass alle Programmelemente in Java-Programmen als Klassen angelegt werden müssen. Der gesamte Programmcode einer Anwendung ist also in Klassen gepackt, auch wenn dies manchmal keine Klassen im eigentlichen Sinn sind, wie schon das Beispiel hier mit dem Hauptprogramm ("main") und seinem Ablauf zeigt. |
|
Demonstriert wird in HS1: |
|
- Die Objekterzeugung (new Stud())
- Der Einsatz von Konstruktoren (mehrere Varianten)
- Das direktes Setzen von Attributen
- Der Einsatz eines Klassenattributs (anzStud)
|
|
|
|
8.1 Klasse HP (Hauptprogramm; main) |
|
Gleich zu Beginn wird ein Objekt erzeugt, s0 ("s" steht für Student/in). Dabei wird der Standardkonstruktorr verwendet. In der Klasse Stud ist zu sehen, dass es möglich ist, dem Standardkonstruktor ein Klassenattribut mit einer Wertezuweisung zuzuordnen. |
|
Nacheinander werden vier unterschiedliche Konstruktoren, die in der Klasse Stud angelegt sind, eingesetzt. Java wählt jeweils den geeigneten aus. D.h.: |
|
Eine Klasse kann verschiedene Konstruktoren besitzen. |
|
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
Auch das jeweilige Hauptprogramm (HP / main) muss in eine Klasse gepackt sein, vgl. die Anmerkung oben. |
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
Objekt s0 wird mit dem Standardkonstruktor erzeugt (instanziiert), das Klassenattribut anzStud (Anzahl Studierende) wird bearbeitet. Vgl. Klasse Stud. |
|
|
Stud s0 = new Stud();
|
|
|
System.out.println("s0 ohne Daten, nach Instanziierung:\n");
|
|
Zur Veranschaulichung die Ausgabe der Objektdaten: Nach der Instanziierung sind die Attribute mit Default-Werten beschrieben. Das Klassenattribut anzStud hat den Wert 1. Unten wird gezeigt, dass der Werte des Klassenattributs bei jeder Instanziierung um 1 erhöht wird. |
|
|
s0.ausgeben();
|
|
Dasselbe wie oben, jetzt für das zweite Objekt s1. Das Klassenattribut hat jetzt den Wert 2. |
|
|
Stud s1 = new Stud();
|
|
|
System.out.println("");
|
|
|
System.out.println("s1 ohne Daten, nach Instanziierung:\n");
|
|
|
s1.ausgeben();
|
|
Objekt s0 wird beschrieben. Dies ist einfach. Objekt- und Attributsbezeichnung identifizieren den konkreten Informationsträger, ansonsten Zuweisung wie bei Attributen. |
|
|
s0.mNr = 12345;
|
|
|
s0.name = "Sauer";
|
|
|
s0.vName = "Otto";
|
|
|
s0.anzSem = 5;
|
|
|
s0.gebTag = "21.09.2002";
|
|
|
|
|
|
System.out.println("");
|
|
|
System.out.println("s0 beschrieben:\n");
|
|
Das Objekt s0 wird mit der Instanzmethode ausgeben() aus der zum Projekt gehörenden Klasse Stud auf der Konsole ausgegeben. Innerhalb desselben Projekts genügt der Aufruf ohne Klassenangabe. Bei jedem Aufruf der Methode wird der Wert des hochgezählten Attributs anzStud ausgegeben. Siehe Programmlauf. |
|
|
s0.ausgeben();
|
|
Auch das Objekt s1 wird beschrieben und ausgegeben. |
|
|
s1.mNr = 98765;
|
|
|
s1.name = "Widder";
|
|
|
s1.vName = "Andrea";
|
|
|
s1.anzSem = 2;
|
|
|
s1.gebTag = "2.7.2005";
|
|
System.out.println(""); ist in Java plattformunabhängig gültig. Auf allen Plattformen (Windows, Linux, macOS, usw.) wird eine Leerzeile ausgegeben. |
|
|
System.out.println("");
|
|
|
System.out.println("s1 beschrieben:\n");
|
|
|
s1.ausgeben();
|
|
Nun der zweite Konstruktor, siehe Klasse Stud. Hier werden alle Attribute in der Parameterliste beschrieben. |
|
|
Stud s2 = new Stud(1111, "Maier", "Klara", 5, "21.09.2002");
|
|
|
System.out.println("\ns2 mit Daten vom Konstruktoraufruf:\n");
|
|
|
s2.ausgeben();
|
|
Der dritte Konstruktor, siehe Klasse Stud, erhält nur einen Teil der Attributsausprägungen über die Parameterliste: mNr, name, vName. Für die übrigen nimmt er die Standardwerte null bzw. 0. |
|
|
Stud s3 = new Stud(1111, "Maier", "Klara");
|
|
|
System.out.println("\ns3 mit teilweisen Daten vom Konstruktoraufruf:\n");
|
|
|
s3.ausgeben();
|
|
Java entscheidet aufgrund des Konstruktoraufrufs, hier auf Basis der Parameterliste, welcher der Konstruktoren aus der Klasse Stud verwendet wird. |
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
Stud s0 = new Stud(); //Objekt s0, Standardkonstruktor
|
|
|
|
|
|
System.out.println("s0 ohne Daten, nach Instanziierung:\n");
|
|
|
s0.ausgeben();
|
|
|
|
|
|
Stud s1 = new Stud();
|
|
|
System.out.println("");
|
|
|
System.out.println("s1 ohne Daten, nach Instanziierung:\n");
|
|
|
s1.ausgeben();
|
|
|
|
|
|
s0.mNr = 12345;
|
|
|
s0.name = "Sauer";
|
|
|
s0.vName = "Otto";
|
|
|
s0.anzSem = 5;
|
|
|
s0.gebTag = "21.09.2002";
|
|
|
System.out.println("");
|
|
|
System.out.println("s0 beschrieben:\n");
|
|
|
s0.ausgeben();
|
|
|
|
|
|
s1.mNr = 98765;
|
|
|
s1.name = "Widder";
|
|
|
s1.vName = "Andrea";
|
|
|
s1.anzSem = 2;
|
|
|
s1.gebTag = "2.7.2005";
|
|
|
System.out.println("");
|
|
|
System.out.println("s1 beschrieben:\n");
|
|
|
s1.ausgeben();
|
|
|
|
|
|
Stud s2 = new Stud(1111, "Maier", "Klara", 5, "21.09.2002");
|
|
|
System.out.println("\ns2 mit Daten vom Konstruktoraufruf:\n");
|
|
|
s2.ausgeben();
|
|
|
|
|
|
Stud s3 = new Stud(1111, "Maier", "Klara");
|
|
|
System.out.println("\ns3 mit teilweisen Daten
|
|
|
vom Konstruktoraufruf:\n");
|
|
|
s3.ausgeben();
|
|
|
}
|
|
|
}
|
|
8.2 Klasse Stud |
|
Klasse Stud mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
Beginn der Klassendefinition |
|
|
public class Stud {
|
|
Inhaltliche Attribute (Instanzattribute) zur Beschreibung der Objekte (Instanzen). |
|
|
public int mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName; //Vorname
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
Definition eines Klassenattributs (statisches Attribut) mit Anfangswert. Static fixiert die Unveränderlichkeit, int legt den Datentyp fest und anzStud = 0 einen Anfangswert. |
|
|
static int anzStud = 0;
|
|
Aufruf Konstruktor 1. Der Standardkonstruktor trägt Standardwerte in die Attribute des Objekts ein (o, null). Ergänzt hier durch den Wert des Klassenattributs anzStud. |
|
|
public Stud () {
|
|
|
anzStud++;
|
|
|
}
|
|
Aufruf Konstruktor 2, siehe Klasse Stud. Hier werden alle Attribute in der Parameterliste beschrieben |
|
|
public Stud (int mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
anzStud++;
|
|
|
}
|
|
Aufruf Konstruktor 3, siehe Klasse Stud. Dieser legt nur einen Teil der Attributsausprägungen in der Parameterliste fest: mNr, name, vName. Für die übrigen nimmt er die Standardwerte false, null oder 0. |
|
|
public Stud (int mNr, String name, String vName) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
anzStud++;
|
|
|
}
|
|
Instanzmethode zum Ausgeben der Daten eines Objekts. Das Klassenattribut anzStud gibt jeweils an, wieviele Objekte angelegt sind. Vgl. Programmlauf. |
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
System.out.println("Anzahl Studierende: " + anzStud);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Stud ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud { //Beginn der Klassendefinition
|
|
|
public int mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName; //Vorname
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
|
static int anzStud = 0;
|
|
|
public Stud () {
|
|
|
anzStud++; //Zähler für die Objekte der Klasse
|
|
|
}
|
|
|
public Stud (int mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
anzStud++;
|
|
|
}
|
|
|
public Stud (int mNr, String name, String vName) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
anzStud++;
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
System.out.println("Anzahl Studierende: " + anzStud);
|
|
|
}
|
|
|
}
|
|
8.3 Ergebnis Programmlauf |
|
|
s0 ohne Daten, nach Instanziierung:
|
|
|
|
|
|
Matrikelnummer: 0
|
|
|
Name: null
|
|
|
Vorname:null
|
|
|
Erreichtes Semester: 0
|
|
|
Geburtstag: null
|
|
|
Anzahl Studierende: 1
|
|
|
|
|
|
s1 ohne Daten, nach Instanziierung:
|
|
|
|
|
|
Matrikelnummer: 0
|
|
|
Name: null
|
|
|
Vorname:null
|
|
|
Erreichtes Semester: 0
|
|
|
Geburtstag: null
|
|
|
Anzahl Studierende: 2
|
|
|
|
|
|
s0 beschrieben:
|
|
|
|
|
|
Matrikelnummer: 12345
|
|
|
Name: Sauer
|
|
|
Vorname:Otto
|
|
|
Erreichtes Semester: 5
|
|
|
Geburtstag: 21.09.2002
|
|
|
Anzahl Studierende: 2
|
|
|
|
|
|
s1 beschrieben:
|
|
|
|
|
|
Matrikelnummer: 98765
|
|
|
Name: Widder
|
|
|
Vorname:Andrea
|
|
|
Erreichtes Semester: 2
|
|
|
Geburtstag: 2.7.2005
|
|
|
Anzahl Studierende: 2
|
|
|
|
|
|
s2 mit Daten vom Konstruktoraufruf:
|
|
|
|
|
|
Matrikelnummer: 1111
|
|
|
Name: Maier
|
|
|
Vorname:Klara
|
|
|
Erreichtes Semester: 5
|
|
|
Geburtstag: 21.09.2002
|
|
|
Anzahl Studierende: 3
|
|
|
|
|
|
s3 mit teilweisen Daten vom Konstruktoraufruf:
|
|
|
|
|
|
Matrikelnummer: 1111
|
|
|
Name: Maier
|
|
|
Vorname:Klara
|
|
|
Erreichtes Semester: 0
|
|
|
Geburtstag: null
|
|
|
Anzahl Studierende: 4
|
|
8.4 Betrachtete Themen |
|
- Attribut
- Datentypen
- import
- Instanziierung
- Klasse
- main()
- Objekt
- package x
- Referenzvariable
|
|
9 Projekt HS2 - Objekte und Referenzen |
|
Hier werden zwei Objekte (stud0 und stud1) eingerichtet und bearbeitet. Es soll deutlich werden, dass bei einer Vorgehensweise wie hier ein Objekt das aktive ist. Um dies zu vereinfachen, werden gleich zwei Objekte angelegt, mit denen dies geprüft werden kann. Es gibt ein Konsolenmenü ... |
|

|
|
... mit einer grafischen Eingabe per JOptionPane.showInputDialog (siehe Programmlauf). |
|
Da im Programm schon zwei Objekte angelegt sind, kann der Punkt 3 gleich ausprobiert werden. Dazu wird zuerst 2 angefordert, was zur Anzeige des aktiven Objekts führt. Dann wird mit 3 das Objekt gewechselt und wiederum mit 2 das jetzt aktive Objekt angezeigt. |
|
Mit 1 können neue Objekte eingegeben werden, die dann jeweils das aktive sind. Wie zu sehen ist, werden immer nur zwei Objekte bereitgehalten. |
|
|
|
9.1 Klasse HP |
|
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
Anmelden der Klasse javax.swing für die grafische Eingabe. |
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class HP {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
String eingabe;
|
|
Erzeugen zweier Objekte mit dem Standardkonstruktor. |
|
|
Stud stud0 = new Stud();
|
|
|
Stud stud1 = new Stud();
|
|
Weiteres Objekt, mit Referenzcharakter. Zeigt aktuell auf das "aktive Objekt". |
|
|
Stud stud = stud0;
|
|
Daten zum Testen. Initialisierung von stud0. |
|
|
stud0.matrikelNr = "12345";
|
|
|
stud0.name = "Erster";
|
|
|
stud0.vName= "Paul";
|
|
|
stud0.plz = "7878";
|
|
|
stud0.ort="Weingarten";
|
|
|
stud0.strasse="Hinterm Berg";
|
|
|
stud0.hausnummer=99;
|
|
Initialisierung von stud1. |
|
|
stud1.matrikelNr = "67890";
|
|
|
stud1.name = "Zweite";
|
|
|
stud1.vName= "Viola";
|
|
|
stud1.plz = "8989";
|
|
|
stud1.ort="Ravensburg";
|
|
|
stud1.strasse="Hauptstr.";
|
|
|
stud1.hausnummer=88;
|
|
Damit nicht gleich zum Ausprobieren Daten eingegeben werden müssen, werden stud0 und stud1 mit Daten beschrieben. So ist es möglich, gleich nach dem Start die Ausgabe mit dem aktiven Objekt anzufordern (es kommt stud0), dann mit Punkt 3 das aktive Objekt zu wechseln (auf 1) und dieses wieder auszugeben. Das ist dann stud1. |
|
|
boolean fertig = false;
|
|
Beginn einer While-Schleife. Ende siehe unten. |
|
|
while (!fertig) {
|
|
|
System.out.println("\nEingabe von Daten \nin die Studierendendatei");
|
|
Menüauswahl auf Konsole. Anzeige siehe unten. |
|
|
System.out.println("1 = Eingabe");
|
|
|
System.out.println("2 = Ausgabe");
|
|
|
System.out.println("3 = Aktives Objekt wechseln");
|
|
|
System.out.println("4 = Programm beenden");
|
|
Eingabe über Dialogfenster in die String-Variable Eingabe. |
|
|
eingabe = JOptionPane.showInputDialog("Ihre Wahl");
|
|
Die String-Variable eingabe wird in einen Integer-Wert gewandelt ("parseInt") und in die Integer-Variable auswahl geschrieben. |
|
|
int auswahl = Integer.parseInt(eingabe);
|
|
|
System.out.println("\nEingegeben wurde: " + auswahl + "\n");
|
|
Verzweigung mit switch auf Basis der Nutzereingaben, die in Integerwerte gewandeltl wurden. |
|
|
switch(auswahl) {
|
|
|
case 1:
|
|
Studierendendaten eingeben. Bespielt wird Objekt stud. Es erfolgt jeweils eine grafische Anzeige der Eingabeaufforderung (vgl. unten) und das Übertragen der Nutzereingabe in die String-Variable eingabe. Diese wird in das entsprechende Objektattribut geschrieben. Für die Hausnummer wurde die Umwandlung des Strings in eine Integerzahl vorgenommen (mit parseInt). |
|
|
stud.matrikelNr = JOptionPane.showInputDialog("Matrikelnummer:");
|
|
|
stud.name = JOptionPane.showInputDialog("Name:");
|
|
|
stud.vName = JOptionPane.showInputDialog("Vorname:");
|
|
|
stud.plz = JOptionPane.showInputDialog("PLZ:");
|
|
|
stud.ort = JOptionPane.showInputDialog("Ort:");
|
|
|
stud.strasse = JOptionPane.showInputDialog("Straße:");
|
|
|
stud.hausnummer = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Hausnummer:")
|
|
|
);
|
|
break wird für jede Case-Variante verlangt. Damit wird die Switch-Verzweigung verlassen. |
|
|
break;
|
|
|
case 2:
|
|
Diese Wahl führt zur Ausgabe der Studierendendaten des jeweils "aktiven" Objekts. |
|
|
System.out.println(stud.matrikelNr);
|
|
|
System.out.println(stud.vName + " " + stud.name);
|
|
|
System.out.println(stud.plz + " " + stud.ort);
|
|
|
System.out.println(stud.strasse + " " + stud.hausnummer);
|
|
|
break;
|
|
|
case 3:
|
|
Aktives Objekt wechseln |
|
|
int nr = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Welcher Student (0 oder 1)?")
|
|
|
);
|
|
|
if (nr == 0) {
|
|
|
stud = stud0; // Referenz zeigt jetzt auf stud0
|
|
|
System.out.println("Jetzt ist Student 0 aktiv.");
|
|
|
} else if (nr == 1) {
|
|
|
stud = stud1; // Referenz zeigt jetzt auf stud1
|
|
|
System.out.println("Jetzt ist Student 1 aktiv.");
|
|
|
} else {
|
|
|
System.out.println("Fehler: Bitte 0 oder 1 eingeben!");
|
|
|
}
|
|
|
break;
|
|
|
case 4:
|
|
Programm beenden |
|
|
fertig = true;
|
|
|
break;
|
|
|
default:
|
|
Fehler bei falscher Menüeingabe |
|
|
System.out.println("Ungültige Eingabe!");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
String eingabe;
|
|
|
Stud stud0 = new Stud();
|
|
|
Stud stud1 = new Stud();
|
|
|
Stud stud = stud0;
|
|
|
stud0.matrikelNr = "12345";
|
|
|
stud0.name = "Erster";
|
|
|
stud0.vName = "Paul";
|
|
|
stud0.plz = "7878";
|
|
|
stud0.ort = "Weingarten";
|
|
|
stud0.strasse = "Hinterm Berg";
|
|
|
stud0.hausnummer = 99;
|
|
|
|
|
|
stud1.matrikelNr = "67890";
|
|
|
stud1.name = "Zweite";
|
|
|
stud1.vName = "Viola";
|
|
|
stud1.plz = "8989";
|
|
|
stud1.ort = "Ravensburg";
|
|
|
stud1.strasse = "Hauptstr.";
|
|
|
stud1.hausnummer = 88;
|
|
|
|
|
|
boolean fertig = false;
|
|
|
while (!fertig) {
|
|
|
System.out.println("\nEingabe von Daten \nin die Studierendendatei");
|
|
|
System.out.println("\n1 = Eingabe");
|
|
|
System.out.println("2 = Ausgabe");
|
|
|
System.out.println("3 = Aktives Objekt wechseln");
|
|
|
System.out.println("4 = Programm beenden");
|
|
|
|
|
|
eingabe = JOptionPane.showInputDialog("Ihre Wahl");
|
|
|
int auswahl = Integer.parseInt(eingabe);
|
|
|
System.out.println("\nEingegeben wurde: " + auswahl + "\n");
|
|
|
switch (auswahl) {
|
|
|
case 1:
|
|
|
stud.matrikelNr = JOptionPane.showInputDialog("Matrikelnummer:");
|
|
|
stud.name = JOptionPane.showInputDialog("Name:");
|
|
|
stud.vName = JOptionPane.showInputDialog("Vorname:");
|
|
|
stud.plz = JOptionPane.showInputDialog("PLZ:");
|
|
|
stud.ort = JOptionPane.showInputDialog("Ort:");
|
|
|
stud.strasse = JOptionPane.showInputDialog("Straße:");
|
|
|
stud.hausnummer = Integer.parseInt(
|
|
|
OptionPane.showInputDialog("Hausnummer:")
|
|
|
);
|
|
|
break;
|
|
|
case 2:
|
|
|
System.out.println("\n--- Studentendaten ---");
|
|
|
System.out.println(stud.matrikelNr);
|
|
|
System.out.println(stud.vName + " " + stud.name);
|
|
|
System.out.println(stud.plz + " " + stud.ort);
|
|
|
System.out.println(stud.strasse + " " + stud.hausnummer);
|
|
|
break;
|
|
|
case 3:
|
|
|
int nr = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Welcher Student (0 oder 1)?")
|
|
|
);
|
|
|
|
|
|
if (nr == 0) {
|
|
|
stud = stud0; // Referenz zeigt jetzt auf stud0
|
|
|
System.out.println("Jetzt ist Student 0 aktiv.");
|
|
|
} else if (nr == 1) {
|
|
|
stud = stud1; // Referenz zeigt jetzt auf stud1
|
|
|
System.out.println("Jetzt ist Student 1 aktiv.");
|
|
|
} else {
|
|
|
System.out.println("Fehler: Bitte 0 oder 1 eingeben!");
|
|
|
}
|
|
|
break;
|
|
|
case 4:
|
|
|
fertig = true;
|
|
|
break;
|
|
|
default:
|
|
|
System.out.println("Ungültige Eingabe!");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
9.2 Klasse Stud |
|
Diese Klasse besteht nur aus der Klassendefinition. |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
|
public String matrikelNr; //Instanzvariablen
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public String plz;
|
|
|
public String ort;
|
|
|
public String strasse;
|
|
|
public int hausnummer;
|
|
|
}
|
|
9.3 Ergebnis Programmlauf |
|
Nach dem Start des Programms erscheint das Konsolenmenü und die grafische Eingabeaufforderung: |
|

|
|
|
|

|
|
|
|
Ein Programmlauf: |
|
|
Eingabe von Daten
|
|
|
in die Studierendendatei
|
|
|
|
|
|
1 = Eingabe
|
|
|
2 = Ausgabe
|
|
|
3 = Aktives Objekt wechseln
|
|
|
4 = Programm beenden
|
|
|
|
|
|
Eingegeben wurde: 2
|
|
|
|
|
|
|
|
|
--- Studierendendaten ---
|
|
|
12345
|
|
|
Paul Erster
|
|
|
7878 Weingarten
|
|
|
Hinterm Berg 99
|
|
|
|
|
|
Eingabe von Daten
|
|
|
in die Studierendendatei
|
|
|
|
|
|
1 = Eingabe
|
|
|
2 = Ausgabe
|
|
|
3 = Aktives Objekt wechseln
|
|
|
4 = Programm beenden
|
|
|
|
|
|
Eingegeben wurde: 3
|
|
|
|
|
|
Jetzt ist Student 1 aktiv.
|
|
|
|
|
|
Eingabe von Daten
|
|
|
in die Studierendendatei
|
|
|
|
|
|
1 = Eingabe
|
|
|
2 = Ausgabe
|
|
|
3 = Aktives Objekt wechseln
|
|
|
4 = Programm beenden
|
|
|
|
|
|
Eingegeben wurde: 2
|
|
|
|
|
|
|
|
|
--- Studierendendaten ---
|
|
|
67890
|
|
|
Viola Zweite
|
|
|
8989 Ravensburg
|
|
|
Hauptstr. 88
|
|
|
|
|
|
Eingabe von Daten
|
|
|
in die Studierendendatei
|
|
|
|
|
|
1 = Eingabe
|
|
|
2 = Ausgabe
|
|
|
3 = Aktives Objekt wechseln
|
|
|
4 = Programm beenden
|
|
|
|
|
|
Eingegeben wurde: 4
|
|
Wird Eingabe gewählt, werden die einzelnen Adresselemente abgefragt (mit JoptionPane.showInputDialog(...)) und die neue Adresse wird zum aktiven Objekt. |
|
9.4 Anmerkungen zum Programm |
|
Objekte und Referenzen |
|
|
Stud stud = stud0;
|
|
"stud" ist kein neues Objekt, sondern zeigt auf stud0. Dies wird hier Referenz genannt. Stud0 ist das aktive Objekt. |
|
Mit |
|
|
stud = stud1;
|
|
zeigt stud auf ein anderes Objekt. Alle Änderungen betreffen dann stud1 statt stud0. Dieses wird zum aktiven Objekt. Der Begriff "aktives Objekt" soll helfen zu verstehen: |
|
- dass mehrere Objekte existieren,
- aber immer nur eines aktuell benutzt wird, weil die Referenzvariablegerade auf dieses Objekt zeigt.
|
|
Statt "aktives Objekt" könnte man methodisch genauer sagen: "Das aktuell referenzierte Objekt" oder "Das Objekt, auf das die Referenzvariablestud zeigt". |
|
JoptionPane |
|
JoptionPane ist eine Klasse aus der Java-Bibliothek zur einfachen Erstellung von Dialogfenstern. Sie gehört zum Paket javax.swing. Darum wird in HS2 zu Beginn geschrieben: |
|
|
import javax.swing.JOptionPane;
|
|
Mit JOptionPane können Programme einfach |
|
- Eingaben abfragen
- Meldungen anzeigen
- Warnungen ausgeben
- Auswahlfenster darstellen
|
|
ohne selbst grafische Fenster programmieren zu müssen. In HS2 wird JOptionPane zur Eingabe verwendet. Zum Beispiel: |
|
|
eingabe = JOptionPane.showInputDialog("Ihre Wahl");
|
|
Dadurch erscheint ein kleines Eingabefenster. showInputDialog() liefert immer einen String, auch wenn der Benutzer eine Zahl eingibt. Darum benötigt HS2: |
|
|
Integer.parseInt(eingabe);
|
|
Damit wird ein String in eine Ganzzahl (int) umgewandelt. |
|
Typische Methoden von JOptionPane sind: |
|
- JOptionPane.showInputDialog(...) für Benutzereingaben.
- JOptionPane.showMessageDialog(null, "Hallo") für Meldungsfenster.
- JOptionPane.showConfirmDialog(...) für ein Bestätigungsfenster.
|
|
Methodischer Hintergrund |
|
JOptionPane ist eine Klasse der GUI-Bibliothek Swing. GUI bedeutet Graphical User Interface (grafische Benutzeroberfläche). |
|
9.5 Betrachtete Themen |
|
- Aktives Objekt (aktuell referenziertes Objekt)
- Benutzereingaben mit JOptionPane.showInputDialog()
- Erzeugen von Objekten mit new
- Import-Anweisungen
- Instanzvariablen
- Klassen und Objekte
- Konsolenausgabe mit System.out.println()
- Lokale Variablen
- Methoden
- Methodenaufruf
- Methodensignatur
- Objektreferenzen
- Objektzustand
- Parameterlose Methoden
- Referenzvariablen
- switch-Anweisung
- Umschalten zwischen Objekten durch Zuweisung einer Referenz
- Umwandlung von String nach int mit Integer.parseInt()
- Verzweigungen mit if und else if
- while-Schleife
- Zusammenarbeit mehrerer Klassen
|
|
10 Projekt HS3 - Array mit Objekten |
|
Array mit Objekten, zufallsgeneriert |
|
In diesem Projekt werden mehrere Objekte mit zufallsgenerierten fiktiven Daten erzeugt. Damit man nicht die Objekte einzeln im Progamm instanziieren muss, wird ein Array zu Hilfe genommen, in dem die Objekte per Programm angelegt werden. Ein solches Array wird auch komplexes Objekt genannt. |
|
Im Programm HP wird zuerst gefragt, wieviele Objekte generiert werden sollen, dann wird ein Array mit dieser Länge angelegt. In diesem werden dann gleich viele Objekte mit Leereinträgen erstellt. Diese haben die Attributsausprägungen 0 (für numerische Instanzvariablen), null (für Strings) und false (für boolesche Attribute). Damit liegt also ein Array mit Objekten vor. Wie üblich, sind die Positionen des Arrays nummeriert, beginnend mit 0. Wenn es also 50 Objekte sind, haben diese die Nummerierungen 0 bis 49 und die Adressen studiosi[i] für i gleich 0 bis 49. Über diese Array-Adresse können die Objekte angesprochen werden. |
studiosi[] |
Für die zu generierenden Objekte liegen zwei String-Arrays vor, einer mit 20 Nachnamen, einer mit 20 Vornamen. Auf deren Basis werden mit Hilfe der Methode java.util.Random() zufällige Namen und Vornamen erzeugt. Auch die übrigen Attributsausprägungen werden zufällig generiert. |
|
Wichtige Aspekte sind hier also: |
|
- Erzeugen eines Arrays aus Objekten (komplexes Objekt)
- Nutzung der Methode Random
|
|
Außerdem werden mit Hilfe der Klasse javax.swing.JoptionPane grafische Eingabemöglichkeiten genutzt: |
|

|
|
|
|
In diesem Beispiel wird, wie immer in dieser Lernhilfe, nicht die Nutzereingabe und "Tiefensemantik" kontrolliert. Z.B. könnte das Programm zwei gleiche Namenskombinationen oder Matrikelnummern erzeugen. |
|
|
|
10.1 Klasse HP |
|
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
Benötigte Klassen importieren |
|
|
import java.util.Random;
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
Überschrift ausgeben |
|
|
System.out.println("--- Objekte mit generierten Daten anlegen ---\n");
|
|
|
|
|
1. Benutzer nach Anzahl der Objekte fragen |
|
|
|
Eingabefenster anzeigen |
|
|
String eingabe =
|
|
|
JOptionPane.showInputDialog(
|
|
|
"Wieviele Objekte (maximal 100):");
|
|
Texteingabe in eine ganze Zahl umwandeln |
|
|
int ianz = Integer.parseInt(eingabe);
|
|
|
|
|
Eingabe prüfen |
|
|
if (ianz < 1 || ianz > 100) {
|
|
|
System.out.println(
|
|
|
"Fehler: Die Anzahl muss zwischen 1 und 100 liegen.");
|
|
|
|
|
Programm beenden |
|
|
return;
|
|
|
}
|
|
|
|
|
Kontrollausgabe ausgeben |
|
|
System.out.println("Anzulegende Objekte: " + ianz);
|
|
|
System.out.println();
|
|
|
|
|
2. Array für Studierende erzeugen |
|
|
Stud[] studiosi = new Stud[ianz];
|
|
|
|
|
3. Datenfelder vorbereiten |
|
|
|
|
Zur Verfügung gestellte Nachnamen |
|
|
String[] namen = {
|
|
|
"Ritter", "Knecht", "Maier", "Müller",
|
|
|
"Stauder", "Siskor", "Oduro", "Picarda",
|
|
|
"Ricker", "Maistro", "Studer", "Saskor",
|
|
|
"Podur", "Prickel", "Bond", "Jones",
|
|
|
"Riker", "Nobel"
|
|
|
};
|
|
Zur Verfügung gestellte Vornamen |
|
|
String[] vornamen = {
|
|
|
"Paul", "Frieder", "Angelika", "Karolin",
|
|
|
"Xian", "Ezri", "Jadzia", "Miriam",
|
|
|
"Elfriede", "Josef", "Guiseppe", "Angie",
|
|
|
"Frieda", "Andrea", "Ludwig", "Ricardo",
|
|
|
"Lisa", "Friedrich"
|
|
|
};
|
|
|
|
|
4. Objekte erzeugen, d.h. für jedes Feld im Array ein Stud-Objekt erzeugen |
|
|
for (int i = 0; i < studiosi.length; i++) {
|
|
|
studiosi[i] = new Stud();
|
|
|
}
|
|
|
System.out.println("Inhalte generieren und Objekte ausgeben");
|
|
Zufallszahlengenerator erzeugen |
|
|
Random r = new Random();
|
|
5. Daten generieren |
|
|
int nr = 0;
|
|
|
while (nr < studiosi.length) {
|
|
|
System.out.println();
|
|
|
System.out.println("Objekt Nr = " + nr);
|
|
Matrikelnummer erzeugen. Zufallszahl zwischen 10000 und 19999 |
|
|
studiosi[nr].mNr = r.nextInt(10000, 20000);
|
|
Nachnamen erzeugen. Zufälligen Namen aus dem Array wählen. |
|
|
studiosi[nr].name = namen[r.nextInt(namen.length)];
|
|
Vornamen erzeugen. |
|
|
studiosi[nr].vName = vornamen[r.nextInt(vornamen.length)];
|
|
Anzahl Semester erzeugen. Zufallszahl zwischen 1 und 19. |
|
|
studiosi[nr].anzSem = r.nextInt(1, 20);
|
|
6. Geburtsdatum erzeugen |
|
|
|
|
Monat zwischen 1 und 12 |
|
|
int monat = r.nextInt(1, 13);
|
|
Variable für den Tag |
|
|
int tag;
|
|
Prüfen, wie viele Tage der Monat hat |
|
|
if (monat == 2) {
|
|
|
tag = r.nextInt(1, 29);
|
|
|
}
|
|
Monate mit 30 Tagen |
|
|
else if (monat == 4 ||
|
|
|
monat == 6 ||
|
|
|
monat == 9 ||
|
|
|
monat == 11) {
|
|
Tag 1 bis 30 |
|
|
tag = r.nextInt(1, 31);
|
|
|
}
|
|
Monate mit 31 Tagen |
|
|
else {
|
|
|
tag = r.nextInt(1, 32);
|
|
|
}
|
|
Jahr zwischen 1995 und 2006 |
|
|
int jahr =
|
|
|
r.nextInt(1995, 2007);
|
|
Datum als String zusammensetzen |
|
|
studiosi[nr].gebTag = tag + "." + monat + "." + jahr;
|
|
7. Objekt ausgeben, Methode der Klasse Stud aufrufen |
|
|
studiosi[nr].ausgeben();
|
|
Zum nächsten Objekt wechseln |
|
|
nr++;
|
|
|
}
|
|
8. Gesamtanzahl ausgeben |
|
|
System.out.println(
|
|
|
"\nAnzahl Studierende: " + Stud.anzStud + "\n");
|
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
import java.util.Random;
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
System.out.println("--- Objekte mit generierten Daten anlegen ---\n");
|
|
|
String eingabe = JOptionPane.showInputDialog("Wieviele Objekte (maximal 100):");
|
|
|
int ianz = Integer.parseInt(eingabe);
|
|
|
|
|
|
if (ianz < 1 || ianz > 100) {
|
|
|
System.out.println("Fehler: Die Anzahl muss zwischen 1 und 100 liegen.");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
System.out.println("Anzulegende Objekte: " + ianz);
|
|
|
System.out.println();
|
|
|
|
|
|
Stud[] studiosi = new Stud[ianz];
|
|
|
|
|
|
String[] namen = {
|
|
|
"Ritter", "Knecht", "Maier", "Müller", "Stauder",
|
|
|
"Siskor", "Oduro", "Picarda", "Ricker", "Maistro",
|
|
|
"Müller", "Studer", "Saskor", "Podur", "Prickel",
|
|
|
"Ricker", "Bond", "Jones", "Riker", "Nobel"
|
|
|
};
|
|
|
|
|
|
String[] vornamen = {
|
|
|
"Paul", "Frieder", "Angelika", "Karolin", "Xian",
|
|
|
"Ezri", "Jadzia", "Miriam", "Elfriede", "Josef",
|
|
|
"Guiseppe", "Angie", "Frieda", "Andrea", "Karolin",
|
|
|
"Ludwig", "Ricardo", "Andrea", "Lisa", "Friedrich"
|
|
|
};
|
|
|
for (int i = 0; i < studiosi.length; i++) {
|
|
|
studiosi[i] = new Stud();
|
|
|
}
|
|
|
System.out.println("Inhalte generieren und Objekte ausgeben");
|
|
|
Random r = new Random();
|
|
|
int nr = 0;
|
|
|
while (nr >= 0 amp;amp; nr < studiosi.length) {
|
|
|
System.out.println();
|
|
|
System.out.println("Objekt Nr = " + nr);
|
|
|
studiosi[nr].mNr = r.nextInt(10000, 20000);
|
|
|
studiosi[nr].name = namen[r.nextInt(namen.length)];
|
|
|
studiosi[nr].vName = vornamen[r.nextInt(vornamen.length)];
|
|
|
studiosi[nr].anzSem = r.nextInt(1, 20);
|
|
|
int monat = r.nextInt(1, 13);
|
|
|
int tag;
|
|
|
|
|
|
if (monat == 2) {
|
|
|
tag = r.nextInt(1, 29);
|
|
|
} else if (monat == 4 || monat == 6 || monat == 9 || monat == 11) {
|
|
|
tag = r.nextInt(1, 31);
|
|
|
} else {
|
|
|
tag = r.nextInt(1, 32);
|
|
|
}
|
|
|
int jahr = r.nextInt(1995, 2007);
|
|
|
|
|
|
studiosi[nr].gebTag = tag + "." + monat + "." + jahr;
|
|
|
studiosi[nr].ausgeben();
|
|
|
nr++;
|
|
|
}
|
|
|
System.out.println("\nAnzahl Studierende: " + Stud.anzStud + "\n");
|
|
|
}
|
|
|
}
|
|
10.2 Klasse Stud |
|
Klasse Stud mit Erläuterungen |
|
|
package hochschule;
|
|
Klassenattribut und statisches Attribut mit Anfangswert. |
|
|
public class Stud {
|
|
|
public int mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
|
static int anzStud = 0;
|
|
|
|
|
Konstruktor mit Klassenattribut. |
|
|
public Stud () {
|
|
|
anzStud++;
|
|
|
}
|
|
Methode zum Ausgeben der Daten eines Objekts |
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
Klasse Stud ohne Erläuterungen |
|
|
package hochschule;
|
|
|
public class Stud {
|
|
|
public int mNr;
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public int anzSem;
|
|
|
public String gebTag;
|
|
|
static int anzStud = 0;
|
|
|
public Stud () {
|
|
|
anzStud++;
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
10.3 Ergebnis Programmlauf |
|
Hier wurden aus Platzgründen nur drei Objekte angefordert. |
|
|
---Objekte mit generierten Daten anlegen
|
|
|
|
|
|
Anzulegende Objekte: 3
|
|
|
|
|
|
Inhalte generieren und Objekte ausgeben
|
|
|
|
|
|
Objekt Nr = 0
|
|
|
Matrikelnummer: 17591
|
|
|
Name: Saskor
|
|
|
Vorname: Jadzia
|
|
|
Erreichtes Semester: 17
|
|
|
Geburtstag: 27.10.2006
|
|
|
|
|
|
Objekt Nr = 1
|
|
|
Matrikelnummer: 16863
|
|
|
Name: Ricker
|
|
|
Vorname: Miriam
|
|
|
Erreichtes Semester: 14
|
|
|
Geburtstag: 13.3.2005
|
|
|
|
|
|
Objekt Nr = 2
|
|
|
Matrikelnummer: 15464
|
|
|
Name: Oduro
|
|
|
Vorname: Ezri
|
|
|
Erreichtes Semester: 3
|
|
|
Geburtstag: 20.0.2002
|
|
|
|
|
|
Anzahl Studierende: 3
|
|
10.4 Beschreibung des Programms |
|
Das Projekt HS3 erweitert das Programm HS2: Statt nur mit zwei Studierenden wird jetzt mit vielen gleichzeitig gearbeitet. Die Daten werden automatisch erzeugt und in einem Array gespeichert. |
|
Zusätzlich gibt es das statische Attribut (Klassenattribut) static int anzStud. Diese Variable zählt, wie viele Studierende insgesamt erzeugt wurden. |
|
Der Konstruktor ist |
|
|
public Stud() {
|
|
|
anzStud++;
|
|
|
}
|
|
Jedes Mal, wenn ein Objekt erzeugt wird, wird der Zähler erhöht. |
|
Die Methode ausgeben() gibt alle Daten eines Studierenden aus: |
|
|
studiosi[nr].ausgeben();
|
|
Das ist eine typische Objektmethode. |
|
Im Hauptprogramm (HP) passiert die eigentliche Verarbeitung. |
|
Schritt 1: Anzahl der Objekte festlegen |
|
|
eingabe = JOptionPane.showInputDialog("Wieviele Objekte...");
|
|
Der Benutzer gibt ein, wie viele Studierendendaten erzeugt werden sollen. |
|
Schritt 2: Array erzeugen |
|
|
Stud[] studiosi = new Stud[ianz];
|
|
Das ist ein Array (Feld) für mehrere Objekte. Es ist zuerst leer, enthält nur Platz für Objekte. |
|
Schritt 3: Objekte erzeugen |
|
|
for (int i = 0; i < studiosi.length; i++) {
|
|
|
studiosi[i] = new Stud();
|
|
|
}
|
|
Jetzt werden die Objekte tatsächlich erstellt. Ergebnis: studiosi[0], studiosi[1], ... sind "echte Studierende". |
|
Schritt 4: Zufallsdaten erzeugen |
|
- Mit Random r = new Random() kann man Zufallszahlen erzeugen.
- Matrikelnummern: r.nextInt(10000, 20000) ergibt eine Zahl zwischen 10000 und 19999
- Namen auswählen: namen[r.nextInt(20)]; wählt zufällig den Nachnamen aus einer Liste
- Vornamen auswählen: vornamen[r.nextInt(20)];
- Semester: r.nextInt(1, 20);
|
|
Datum erzeugen |
|
- Monat wird zufällig gewählt
- Tag hängt vom Monat ab
- Jahr wird zufällig bestimmt
|
|
Daraus wird ein String gebaut wie: 12.5.2001 |
|
Schritt 5: Verarbeitungsschleife |
|
|
while (nr >= 0 amp;amp; nr < studiosi.length){...}
|
|
Diese Schleife geht über alle Objekte. Für jedes Objekt geschieht: |
|
- Daten erzeugen
- Daten speichern
- Daten ausgeben
|
|
Mit |
|
|
studiosi[nr].ausgeben();
|
|
werden die Daten der Objekte angezeigt. Die Methode ist in der Klasse Stud definiert. |
|
Am Ende erfolgt die Ausgabe der Gesamtanzahl aller erzeugten Objekte: |
|
|
System.out.println("Anzahl Studierende: " + Stud.anzStud);
|
|
Mit der Klasse Random ein Zufallszahlengenerator erzeugt werden. So wie hier: |
|
|
Random r = new Random();
|
|
D.h., das instanziierte Objekt r von Random() ist ein Zufallszahlengenerator. Man kann sich r wie eine kleine Maschine vorstellen, die immer neue Zufallszahlen liefert. Z.B. eine zufällige Matrikelnummer: |
|
|
studiosi[nr].mNr = r.nextInt(10000, 20000);
|
|
Oder, so wie oben, einen zufälligen Namen aus einem Array: |
|
|
studiosi[nr].name = namen[r.nextInt(namen.length)];
|
|
10.5 Betrachtete Themen |
|
- Arrays von Objekten
- Erzeugen zufälliger Testdaten
- Erzeugen mehrerer Objekte mit new
- Referenztypen
- Primitive Datentypen
- Typ einer Variablen
- Typ eines Objekts
- Objektreferenzen in Arrays
- Array-Index
- Durchlaufen eines Arrays
- for-Schleife
- while-Schleife
- Zufallszahlen mit Random
- Erzeugen zufälliger Testdaten
- Klassenattribute (statische Attribute)
- static-Attribut
- Konstruktor
- Automatisches Zählen erzeugter Objekte
- Objektmethoden
- Methodenaufruf
- Benutzereingaben mit JOptionPane.showInputDialog()
- Umwandlung von String nach int mit Integer.parseInt()
- Konsolenausgabe mit System.out.println()
- Zusammenarbeit mehrerer Klassen
|
|
11 Projekt HS4 - Aufrufe über Klassengrenzen |
|
Hier werden Aufrufe über Klassengrenzen hinweg demonstriert, darunter auch eine, die zur Verknüpfung von Inhalten führt. Neben der Klasse mit dem HP liegen zwei inhaltlich motivierte Klassen vor: Stud (Studierende) und Noten. |
|
|
|
11.1 Klasse HP |
|
Zu Beginn werden mittels zweier Konstruktoraufrufe die Objekte (Studierenden) s0 und s1 instanziiert und deren Daten ausgegeben. Anschließend erfolgt der Konstruktoraufruf zur Klasse Noten. Auch hier werden die Daten per Parameteraufruf eingetragen. Abschließend wird die Ausgabe verknüpfter Daten gezeigt. Insgesamt erfolgt hier an folgenden Stellen ein Aufruf einer anderen Klasse: |
|
- s0.ausgeben() ruft im HP eine Methode der Klasse Stud auf.
- s1.name, usw. fordert im HP aus Stud die Daten des Objekts an.
- n1.fach fordert von Noten das Studienfach der Notenvergabe an, usw.
|
|
In Stud ist ein Klassenattribut eingefügt: anzStud. Es hält die Anzahl der Studierenden (die Anzahl der Objekte von Stud) fest. Das Hochzählen erfolgt im Konstruktor von Stud. |
Klassen-
attribut |
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
Konstruktor für das Objekt s0. Die Attribute des Objekts werden über die Parameterliste des Konstruktors befüllt. Vgl. Stud für den entsprechenden Aufbau des Konstruktors. |
|
|
Stud s0 = new Stud("123", "Maier", "Klara", 5, "21.09.2002");
|
|
|
System.out.println("Ausgabe der Daten in HP mit Methode der Klasse Stud:");
|
|
Aufruf der Instanzmethode ausgeben() der Klasse Stud.java. |
|
|
s0.ausgeben();
|
|
Ein weiteres Objekt von Stud entsteht und wird ausgegeben. |
|
|
Stud s1 = new Stud("234", "Müller", "Ulla", 5, "1.1.1999");
|
|
|
s1.ausgeben();
|
|
Konstruktor der Klasse Noten mit Dateneingabe per Parameter,. Es entsteht Objekt n1. EinfWI bedeutet: Einführung in die Wirtschaftsinformatik. Dann erfolgt der Aufruf der Instanzenmethode ausgNote() zur Ausgabe der Noten. |
|
|
Noten n1 = new Noten("234", "EinfWI", 1);
|
|
|
n1.ausgNote();
|
|
Mit den folgenden Befehlen werden, von HP aus, verknüpfte Daten von s1 und n1 ausgegeben. Das Beispiel ist aus didaktischen Gründen stark fokussiert auf die Aufruf- und Konstruktorthematik. In Wirklichkeit müssten natürlich die passenden Studierenden und Noten zuerst gesucht werden. |
|
|
System.out.println("\nAusgabe der Noten in Klasse HP:");
|
|
|
System.out.println("Matrikelnummer: " + s1.mNr + "\nName: " + s1.name + "\nVorname: " + s1.vName + "\nFach: " + n1.fach + "\nNote: " + n1.note);
|
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s0 = new Stud("123", "Maier", "Klara", 5, "21.09.2002");
|
|
|
System.out.println("Ausgabe der Daten in HP mit Methode der Klasse Stud:");
|
|
|
s0.ausgeben();
|
|
|
Stud s1 = new Stud("234", "Müller", "Ulla", 5, "1.1.1999");
|
|
|
s1.ausgeben();
|
|
|
Noten n1 = new Noten("123", "EinfWI", 1);
|
|
|
n1.ausgNote();
|
|
|
System.out.println("\nAusgabe der Noten in Klasse HP:");
|
|
|
System.out.println("Matrikelnummer: " + s1.mNr + "\nName: "
|
|
|
+ s1.name + "\nVorname: " + s1.vName + "\nFach: " + n1.fach
|
|
|
+ "\nNote: " + n1.note);
|
|
|
}
|
|
|
}
|
|
11.2 Klasse Noten |
|
Die Klasse Noten erfasst mit den Attributen mNr (Matrikelnummer), fach (Studienfach) und Note (erreichte Note in Klausur, mündlicher Prüfung, Hausarbeit, usw.) die Noten der Studierenden. |
|
Der Konstruktor ist wiederum so angelegt, dass die Attributsausprägungen (Werte) gleich beim Aufruf übergeben werden. Eine Methode ausgNote() erlaubt es, die Noten eines Studierenden bzgl. eines Faches anzeigen zu lassen. |
|
Klasse Noten mit Erläuterungen |
|
|
package hochschule;
|
|
Ein Konstruktor mit Werteübergabe in der Parameterliste. Damit entsteht dann nicht ein unbeschriebenes Objekt mit 0, null und false, sondern gleich eines mit beschriebenen Attributsausprägungen. Der Aufruf im HP ist wie folgt: Noten n1 = new Noten("12345", "EinfWI", 1). Zu beachten ist die Zuweisung der übergebenen Werte an die Attribute des Objekts mittels this. |
|
|
public class Noten {
|
|
|
public String mNr; //Matrikelnummer
|
|
|
public String fach; //Studienfach
|
|
|
public int note;
|
|
|
public Noten(String matrNr, String fach, int note)
|
|
|
{
|
|
|
this.mNr = matrNr;
|
|
|
this.fach = fach;
|
|
|
this.note = note;
|
|
|
}
|
|
Definition der Instanzmethode ausgNote() ("Noten ausgeben") Diese steht dann im gesamten Programm zur Verfügung, dank package hochschule. Aufruf im HP z.B. so: n1.ausgNote(). |
|
|
void ausgNote() {
|
|
|
System.out.println("\nAusgabe der Daten in Klasse Noten:");
|
|
|
System.out.println("Student (Matrikelnummer): " + mNr);
|
|
|
System.out.println("Fach: " + fach);
|
|
|
System.out.println("Note: " + note);
|
|
|
}
|
|
|
}
|
|
Klasse Noten ohne Erläuterungen |
|
|
package hochschule;
|
|
|
public class Noten {
|
|
|
public String mNr;
|
|
|
public String fach;
|
|
|
public int note;
|
|
|
public Noten(String matrNr, String fach, int note)
|
|
|
{
|
|
|
this.mNr = matrNr;
|
|
|
this.fach = fach;
|
|
|
this.note = note;
|
|
|
}
|
|
|
void ausgNote() {
|
|
|
System.out.println("\nAusgabe der Daten in Klasse Noten:");
|
|
|
System.out.println("Student (Matrikelnummer): " + mNr);
|
|
|
System.out.println("Fach: " + fach);
|
|
|
System.out.println("Note: " + note);
|
|
|
}
|
|
|
}
|
|
11.3 Klasse Stud |
|
Die Klasse Stud enthält neben den Attributen mNr (Matrikelnummer), name (Name), vName (Vorname), gebTag (Geburtstag) und anzSem (erreichtes Semester) das Klassenattribut anzStud (Anzahl Studierende). Diese wird bei der Einrichtung auf einen Anfangswert gesetzt. |
|
Die hier gewählte Konstruktorvariante zeigt die Erstellung eines Objekts mit Hilfe der Parameterliste. Wie der zugehörige Aufruf aussieht, zeigt die Klasse HP. Die Einträge der im Aufruf übergebenen Werte erfolgt mit Hilfe des Key Words this. Außerdem wird hier wiederum gleich beim Konstruktor das Attribut anzStud um 1 hochgezählt. |
|
Die Klasse hat außerdem die Methode ausgeben(), mit der die Daten des gerade erstellten Objekts auf der Konsole angezeigt werden. |
|
Klasse Stud mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
Instanzenattribute zur Beschreibung der Objekte. |
|
|
public String mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
Klassenattribut (statisches Attribut) mit Anfangswert: |
|
|
static int anzStud = 0;
|
|
Konstruktor mit Parameterliste. Zu beachten ist das Eintragen der Parameterwerte mittel this in die Attribute. Der Aufruf im HP ist hier wie folgt: Stud s0 = new Stud("1111", "Maier", "Klara", 5, "21.09.2002"). Das Klassenattribut anzStud() wird bei jedem Konstruktoraufruf um 1 erhöht. |
|
|
public Stud (String mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
anzStud++; //Zähler für Klassenattribut
|
|
|
}
|
|
Methode zum Ausgeben der Daten eines Objekts. Der Aufruf im HP ist z.B. wie folgt: s1.ausgeben(); |
|
|
void ausgeben() {
|
|
|
System.out.println("\nMatrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
Klasse Stud ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
|
public String mNr;
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public int anzSem;
|
|
|
public String gebTag; //Geburtstag
|
|
|
static int anzStud = 0;
|
|
|
public Stud (String mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr =mNr;
|
|
|
this.name =name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
anzStud++;
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println("\nMatrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
11.4 Ergebnis Programmlauf |
|
|
Ausgabe der Daten in HP mit Methode der Klasse Stud:
|
|
|
|
|
|
Matrikelnummer: 123
|
|
|
Name: Maier
|
|
|
Vorname:Klara
|
|
|
Erreichtes Semester: 5
|
|
|
Geburtstag: 21.09.2002
|
|
|
|
|
|
Matrikelnummer: 234
|
|
|
Name: Müller
|
|
|
Vorname:Ulla
|
|
|
Erreichtes Semester: 5
|
|
|
Geburtstag: 1.1.1999
|
|
|
|
|
|
Ausgabe der Daten in Klasse Noten:
|
|
|
Student (Matrikelnummer): 123
|
|
|
Fach: EinfWI
|
|
|
Note: 1
|
|
|
|
|
|
Ausgabe der Noten in Klasse HP:
|
|
|
Matrikelnummer: 234
|
|
|
Name: Müller
|
|
|
Vorname: Ulla
|
|
|
Fach: EinfWI
|
|
|
Note: 1
|
|
11.5 Beschreibung des Programms |
|
Das Projekt HS4 besteht aus den drei Klassen HP, Stud und Noten. Es zeigt, wie mehrere Klassen in einem Java-Programm zusammenwirken. Außerdem werden Konstruktoraufrufe mittels Parameterübergabe ausführlicher dargestellt. |
|
Das Projekt besteht aus drei Dateien: |
|
- HP.java
- Stud.java
- Noten.java
|
|
Im Projekt werden Studierende erzeugt, deren Daten gespeichert, Noten angelegt und alle Informationen ausgegeben. Dabei wird gezeigt, wie mehrere Klassen zusammenarbeiten. |
|
Die Klasse Noten beschreibt eine einzelne Note. Gespeichert werden: |
|
- Matrikelnummer des Studierenden
- Fach
- Note
|
|
Wichtig: Die 1:n-Beziehung zwischen Studierenden und Noten existiert natürlich, wird aber zunächst nur vereinfacht über die Matrikelnummer bei den Notenobjekten erfasst. Die Beschreibung der Einrichtung einer objektorientierten 1:n-Beziehung folgt später. Dabei erhält die Klasse Stud eine Notenliste: List<Noten> noten = new ArrayList<>(); Damit können dann einem Studierenden mehrere Notenobjekte direkt zugeordnet werden. |
|
Die Klasse Noten besitzt zwei Konstruktoren: |
|
- einen parameterlosen Konstruktor
- einen Konstruktor mit Parametern
|
|
Mit Parametern ergibt sich folgendes: |
|
|
public Noten(String matrNr, String fach, int note)
|
|
Damit werden Werte direkt beim Erzeugen des Objekts übergeben, z.B. so: |
|
|
Noten n1 = new Noten("123", "EinfWI", 1);
|
|
Ohne Parameter ist der Aufruf wie folgt: |
|
|
public Noten()
|
|
Dabei können Standardwerte gesetzt werden, so wie hier: |
|
|
mNr = "000";
|
|
|
fach = "unbekannt";
|
|
|
note = 0;
|
|
Der Aufruf ist: |
|
|
Noten n2 = new Noten();
|
|
Solche Konstruktoren sind nützlich, wenn zunächst ein "leeres" Objekt erzeugt werden soll. |
|
Statische Variable |
|
In der Klasse Stud gibt es eine sog. statische Variable, bzw. ein Klassenattribut: |
|
|
static int anzStud = 0;
|
|
Ein solches bezieht sich nicht auf ein einzelnes Objekt, sondern auf die gesamte Klasse. Hier gibt es an, wie viele Studierenden-Objekte erzeugt wurden. Dafür wird jeweils im Konstruktor um eins erhöht: |
|
|
anzStud++;
|
|
11.6 Betrachtete Themen |
|
- Aufrufe über Klassengrenzen
- Ausgabe von Objektdaten
- Initialisierung von Objektattributen
- Instanzattribute
- Klassen und Objekte
- Klassenattribute (statische Attribute)
- Konstruktoren
- Konstruktoren mit Parameterliste
- Methoden mit Parametern
- Methodenaufruf
- Objekterzeugung mit new
- Objektmethoden
- Objektreferenzen
- Parameter und Argumente
- Parameterübergabe
- Rückgabewerte
- static-Attribut
- this-Referenz
- Vorbereitung einer 1:n-Beziehung
- Zusammenarbeit mehrerer Klassen
- Zusammenarbeit von Stud- und Notenobjekten
|
|
12 Projekt HS5 - Eingaben |
|
Benutzereingaben verarbeiten und daraus Objekte erzeugen. |
|
Hier werden mit java.util.Scanner Konsoleneingaben (Integerwerte und Strings) gelesen. Vgl. Abschnitt 3.1. Dann wird ein Objekt erzeugt und mit den eingelesenen Daten bespielt. Mithilfe der Instanzmethode ausgeben() aus Stud.java wird dann dieses Objekt auf dem Bildschirm angezeigt. Abschließend wird das Hochzählen einer Klassenvariablen demonstriert. |
|
|
|
12.1 Klasse HP |
|
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
Scanner-Objekt erzeugen. Mit Scanner können Daten über die Tastatur eingelesen werden. System.in bedeutet: Eingabe von der Konsole. |
|
|
Scanner scanner = new Scanner(System.in);
|
|
Benutzer fragen, ob ein Objekt angelegt werden soll. |
|
|
System.out.print("Objekt eingeben (j/n): ");
|
|
Eingabe als Zeichenkette einlesen. |
|
|
String s = scanner.nextLine();
|
|
Auswahl abhängig von der Eingabe. switch überprüft den Inhalt der Variablen s. |
|
|
switch (s) {
|
|
Falls der Benutzer "j" eingibt: |
|
|
case "j":
|
|
|
System.out.println("Eingabe:");
|
|
Matrikelnummer abfragen. nextLine() liefert zunächst einen String. Integer.parseInt(...) wandelt den String in eine Ganzzahl um. |
|
|
System.out.print("Matrikelnummer: ");
|
|
|
int mNr = Integer.parseInt(scanner.nextLine());
|
|
Namen einlesen. |
|
|
System.out.print("Name: ");
|
|
|
String name = scanner.nextLine();
|
|
Vorname einlesen. |
|
|
System.out.print("Vorname: ");
|
|
|
String vName = scanner.nextLine();
|
|
Aktuelles Semester einlesen. |
|
|
System.out.print("Aktuelles Semester: ");
|
|
|
int anzSem = Integer.parseInt(scanner.nextLine());
|
|
Geburtstag einlesen. |
|
|
System.out.print("Geburtstag: ");
|
|
|
String gebTag = scanner.nextLine();
|
|
Neues Objekt der Klasse Stud erzeugen. Der parameterlose Konstruktor wird aufgerufen. |
|
|
Stud s100 = new Stud();
|
|
Die eingegebenen Werte werden den Attributen zugewiesen. Das Objekt s100 wird dadurch beschrieben. |
|
|
s100.mNr = mNr;
|
|
|
s100.name = name;
|
|
|
s100.vName = vName;
|
|
|
s100.anzSem = anzSem;
|
|
|
s100.gebTag = gebTag;
|
|
Ausgabeüberschrift. |
|
|
System.out.println("\n--Objekt mit externer Methode anzeigen:\n");
|
|
Methode ausgeben() der Klasse Stud aufrufen. Die Methode gibt die Daten des Objekts aus. |
|
|
s100.ausgeben();
|
|
|
System.out.println();
|
|
Ende dieses case-Zweigs. |
|
|
break;
|
|
Falls nicht "j" eingegeben wurde. Programmabbruch melden. |
|
|
default:
|
|
|
System.out.println("Abbruch");
|
|
|
break;
|
|
|
}
|
|
Scanner schließen. Dadurch werden Systemressourcen freigegeben. |
|
|
scanner.close();
|
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
Scanner scanner = new Scanner(System.in);
|
|
|
System.out.print("Objekt eingeben (j/n): ");
|
|
|
String s = scanner.nextLine();
|
|
|
switch (s) {
|
|
|
case "j":
|
|
|
System.out.println("Eingabe:");
|
|
|
System.out.print("Matrikelnummer: ");
|
|
|
int mNr = Integer.parseInt(scanner.nextLine());
|
|
|
System.out.print("Name: ");
|
|
|
String name = scanner.nextLine();
|
|
|
System.out.print("Vorname: ");
|
|
|
String vName = scanner.nextLine();
|
|
|
System.out.print("Aktuelles Semester: ");
|
|
|
int anzSem = Integer.parseInt(scanner.nextLine());
|
|
|
System.out.print("Geburtstag: ");
|
|
|
String gebTag = scanner.nextLine();
|
|
|
Stud s100 = new Stud();
|
|
|
s100.mNr = mNr;
|
|
|
s100.name = name;
|
|
|
s100.vName = vName;
|
|
|
s100.anzSem = anzSem;
|
|
|
s100.gebTag = gebTag;
|
|
|
System.out.println("\n-----Objekt mit externer Methode anzeigen:\n");
|
|
|
s100.ausgeben();
|
|
|
System.out.println();
|
|
|
break;
|
|
|
default:
|
|
|
System.out.println("Abbruch");
|
|
|
break;
|
|
|
}
|
|
|
scanner.close();
|
|
|
}
|
|
|
}
|
|
12.2 Klasse Stud |
|
Klasse Stud mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
|
public int mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
Klassenattribut/statisches Attribut anzStud mit Anfangswert. |
|
|
static int anzStud = 0;
|
|
Konstruktor mit Klassenattribut als Zähler. Bei jedem Aufruf wird er um 1 höher gesetzt. |
|
|
public Stud() {
|
|
|
anzStud++; //Zähler für Klassenattribut
|
|
|
}
|
|
Methode zum Ausgeben der Daten eines Objekts. |
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
Klasse Stud ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
|
public int mNr; //Matrikelnummer
|
|
|
public String name;
|
|
|
public String vName;
|
|
|
public int anzSem; //Erreichtes Semester
|
|
|
public String gebTag; //Geburtstag
|
|
|
static int anzStud = 0;
|
|
|
public Stud () {
|
|
|
anzStud++; //Zähler für Klassenattribut
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
12.3 Ergebnis Programmlauf |
|
|
Objekt eingeben (j/n):
|
|
|
j
|
|
|
Eingabe:
|
|
|
Matrikelnummer: 12345
|
|
|
Name: Studer
|
|
|
Vorname: Guiseppe
|
|
|
Aktuelles Semester: 8
|
|
|
Geburtstag: 21.9.2000
|
|
|
|
|
|
-----Objekt mit externer Methode anzeigen:
|
|
|
|
|
|
Matrikelnummer: 12345
|
|
|
Name: Studer
|
|
|
Vorname:Guiseppe
|
|
|
Erreichtes Semester: 8
|
|
|
Geburtstag: 21.9.2000
|
|
12.4 Anmerkungen zum Programm |
|
Der Programmlauf zeigt, dass die Konsoleneingabe mit java.util.Scanner recht schlicht ist. Es gibt die Möglichkeit, mit |
|
|
System.out.println("\nMatrikelnummer:");
|
|
den Cursor auf dem Bildschirm in die nächste Zeile zu stellen, was aber auch nicht überzeugend ist. Deshalb werden hier in den weiteren Programmen noch andere Vorgehensweisen für Eingaben demonstriert. |
|
Das Programm ist bewusst einfach gehalten und dient Lernzwecken: |
|
- Die Attribute sind öffentlich zugänglich
- Es erfolgt keine Fehlerbehandlung bei falschen Eingaben
|
|
Dies müsste in professionellen Anwendungen anders gelöst werden. |
|
12.5 Betrachtete Themen |
|
- Automatisches Zählen erzeugter Objekte
- Einlesen von Benutzereingaben
- Einlesen von Strings mit nextLine()
- Erzeugen eines Scanner-Objekts
- Freigeben von Ressourcen mit close()
- Initialisierung von Objektattributen
- Instanzattribute
- Klasse Scanner
- Klassenattribute (statische Attribute)
- Konsolenausgabe mit System.out.print() und System.out.println()
- Konsoleneingaben mit Scanner
- Methodenaufruf
- Objekterzeugung mit new
- Objektmethoden
- Parameterloser Konstruktor
- static-Attribut
- switch-Anweisung
- System.in
- Umwandlung von String nach int mit Integer.parseInt()
- Zusammenarbeit mehrerer Klassen
|
|
13 Exkurs - Nachrichtenverkehr |
|
In der UML spielt der Nachrichtenverkehr zwischen Objekten eine wichtige Rolle bei der Erbringung der Programmleistung. An dieser Stelle nun die Frage: Gibt es in Java auch das Konzept der Nachrichten zwischen Objekten und wie ist es umgesetzt. |
|
Der Hintergrund des Nachrichtenkonzepts der UML ist ja, dass ein Objekt einer Klasse ein Objekt einer anderen Klasse zu einer Aktion aufruft. Dies geschieht in Java durch Methodenaufrufe, wie sie auch hier in den Programmen zu sehen sind. Ein einfaches Beispiel ist, dass aus dem HP der Ausdruck aus einer Klasse Drucker angefordert wird: |
|
|
class Drucker {
|
|
|
void drucken(String text) {
|
|
|
System.out.println(text);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
Drucker d = new Drucker();
|
|
|
d.drucken("Hallo Welt");
|
|
|
}
|
|
|
}
|
|
Hier erhält also das Objekt d der Klasse Drucker die Nachricht |
|
|
drucken("Hallo Welt")
|
|
und führt daraufhin die Methode aus. |
|
Beispiel aus den HS-Projekten: In der Klasse HP aus HS9 liegt vor: |
|
|
s1.addNote(n1);
|
|
Die Methode ist in der Klasse Stud und wird dort für das Objekt s1 ausgeführt. |
|
Im HP des Projekts HS6 wird mittels |
|
|
s1.ausgeben();
|
|
die entsprechende Methode in Stud aufgerufen und für das Objekt s1 ausgeführt. Näheres siehe dort. |
|
Merksatz |
|
Objektorientierte Programme bestehen aus Objekten, die sich gegenseitig über Methodenaufrufe Nachrichten senden und die damit gemeinsam die Aufgabenerledigung realisieren. |
|
|
|
14 Projekt HS6 - Record-Klassen |
|
Hier geht es um Record-Klassen. Vgl. auch Abschnitt 4.7. |
|
|
|
14.1 Projektbeschreibung |
|
Ziel des Projekts |
|
Das Projekt HS6 führt in das Konzept der Records in Java ein. Records sind eine spezielle Form von Klassen, die verwendet werden, um Objekte mit Daten besonders einfach zu beschreiben. Viele Standardfunktionen werden dabei automatisch von Java erzeugt. |
|
Das Projekt zeigt: |
|
- Erzeugen von Record-Objekten
- Arbeiten mit Attributen
- automatische Zugriffsmethoden
- automatische toString()-Methode
- Vergleich von Objekten mit equals()
- eigene Methoden innerhalb eines Records
|
|
Aufbau des Projekts |
|
Das Projekt besteht aus den zwei Programmen HP.java (Hauptprogramm, wie üblich) und Stud.java mit den Records für Studierende. |
|
Im Hauptprogramm werden |
|
- mehrere Record-Objekte erzeugt
- Attributwerte abgefragt
- ganze Objekte ausgegeben
- Objekte miteinander verglichen
|
|
Der Record Stud |
|
Mit dem Record Stud werden Studierende beschrieben. Die Definition lautet: |
|
|
public record Stud(
|
|
|
String name,
|
|
|
String vName,
|
|
|
int plz,
|
|
|
String ort,
|
|
|
int anzSem,
|
|
|
String gebTag)
|
|
Die einzelnen Bestandteile heißen Komponenten des Records. Sie entsprechen den Attributen eines normalen Objekts. Ein Record unterscheidet sich von einer normalen Klasse. Java erzeugt automatisch: |
|
- einen Konstruktor
- Zugriffsmethoden
- toString()
- equals()
- hashCode()
|
|
Dadurch wird der Quellcode deutlich kürzer. |
|
Erzeugen von Record-Objekten |
|
Im Hauptprogramm werden drei Objekte erzeugt: |
|
|
Stud s1 = new Stud(...);
|
|
|
Stud s2 = new Stud(...);
|
|
|
Stud s3 = new Stud(...);
|
|
Beim Aufruf von new wird automatisch der Konstruktor des Records verwendet. Die Werte (Attributsausprägungen) werden direkt als Parameter übergeben. |
|
Zugriff auf einzelne Werte |
|
Für jede Komponente erzeugt Java automatisch eine Zugriffsmethode. Für die Komponente: |
|
|
String name
|
|
entsteht automatisch die Methode: |
|
|
name()
|
|
Beispiel: |
|
|
System.out.println(s1.name());
|
|
Damit wird der Nachname des Objekts s1 ausgegeben. |
|
Ausgabe eines gesamten Objekts |
|
Records besitzen automatisch die Methode: |
|
|
toString()
|
|
Damit können alle Inhalte eines Objekts auf einmal ausgegeben werden. Beispiel: |
|
|
System.out.println(s1.toString());
|
|
Die Ausgabe enthält: |
|
- den Record-Namen
- alle Komponenten
- die zugehörigen Werte
|
|
Vergleich von Record-Objekten |
|
Der Vergleich erfolgt mit: |
|
|
equals()
|
|
Beispiel: |
|
|
s2.equals(s3)
|
|
Das Ergebnis ist: |
|
|
true
|
|
weil alle Werte identisch sind. Dagegen liefert: |
|
|
s1.equals(s2)
|
|
den Wert: |
|
|
false
|
|
weil sich mehrere Werte unterscheiden. |
|
14.2 Klasse HP |
|
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
Drei Record-Objekte werden erzeugt. Auch hier wird mit new der Konstruktor angeworfen. Vgl. Record Stud unten. Die records werden per Parameterübergabe beschrieben. |
|
|
Stud s1 = new Stud("Stauder", "Franz", 88888, "Überall", 5, "20.1.2000");
|
|
|
Stud s2 = new Stud("Müller", "Franz", 99999, "Nirgendwo", 13, "1.1.2001");
|
|
|
Stud s3 = new Stud("Müller", "Franz", 99999, "Nirgendwo", 13, "1.1.2001");
|
|
Für jedes Attribut wird bei Records automatisch eine gleichnamige Abfragemethode bereitgestellt. Für name also name(), wie hier gezeigt. |
|
|
System.out.println("\nAusgabe einzelner Attributsausprägungen:\n");
|
|
|
System.out.println("Name: " + s1.name());
|
|
|
System.out.println("Name: " + s2.name());
|
|
Die Methode toString() liefert Ausgaben eines ganzen Record-Objekts mit Attributsbezeichnung und Attributsausprägung. Vgl. Programmlauf. |
|
|
System.out.println("\nAusgabe records s1 ... s3:\n");
|
|
|
System.out.println(s1.toString());
|
|
|
System.out.println(s2.toString());
|
|
|
System.out.println(s3.toString());
|
|
|
System.out.println("\nVergleich der Objekte:\n");
|
|
Der Vergleich von Record-Objekten erfolgt mit der Methode equals(). Eine Abfrage mittels einfacher Gleichsetzung klappt nicht. Vgl. die in Abschnitt 4.7 angegebene Literatur. |
|
|
if (s1.equals(s2))
|
|
|
System.out.println("s1 und s2: Identische Studierende.");
|
|
|
else
|
|
|
System.out.println("s1 und s2: Nicht identische Studierende.");
|
|
|
if (s3.equals(s2))
|
|
|
System.out.println("s3 und s2: Identische Studierende.");
|
|
|
else
|
|
|
System.out.println("s3 und s2: Nicht identische Studieren-de.");
|
|
|
if (s3.equals(s1))
|
|
|
System.out.println("s3 und s1: Identische Studierende.");
|
|
|
else
|
|
|
System.out.println("s3 und s1: Nicht identische Studieren-de.");
|
|
Zur Veranschaulichung hier noch die "klassische" Ausgabe auf der Konsole. |
|
|
System.out.println("\nStudierende/r s1:");
|
|
|
s1.ausgeben();
|
|
|
System.out.println("\nStudierende/r s2:");
|
|
|
s2.ausgeben();
|
|
|
System.out.println("\nStudierende/r s3:");
|
|
|
s3.ausgeben();
|
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s1 = new Stud("Stauder", "Franz", 88888, "Überall", 5, "20.1.2000");
|
|
|
Stud s2 = new Stud("Müller", "Franz", 99999, "Nirgendwo", 13, "1.1.2001");
|
|
|
Stud s3 = new Stud("Müller", "Franz", 99999, "Nirgendwo", 13, "1.1.2001");
|
|
|
System.out.println("\nAusgabe einzelner Attributsausprägungen:\n");
|
|
|
System.out.println("Name: " + s1.name());
|
|
|
System.out.println("Name: " + s2.name());
|
|
|
System.out.println("\nAusgabe records s1 ... s3:\n");
|
|
|
System.out.println(s1.toString());
|
|
|
System.out.println(s2.toString());
|
|
|
System.out.println(s3.toString());
|
|
|
System.out.println("\nVergleich der Objekte:\n");
|
|
|
if (s1.equals(s2))
|
|
|
System.out.println("s1 und s2: Identische Studierende.");
|
|
|
else
|
|
|
System.out.println("s1 und s2: Nicht identische Studierende.");
|
|
|
if (s3.equals(s2))
|
|
|
System.out.println("s3 und s2: Identische Studierende.");
|
|
|
else
|
|
|
System.out.println("s3 und s2: Nicht identische Studieren-de.");
|
|
|
if (s3.equals(s1))
|
|
|
System.out.println("s3 und s1: Identische Studierende.");
|
|
|
else
|
|
|
System.out.println("s3 und s1: Nicht identische Studieren-de.");
|
|
|
System.out.println("\nStudierende/r s1:");
|
|
|
s1.ausgeben();
|
|
|
System.out.println("\nStudierende/r s2:");
|
|
|
s2.ausgeben();
|
|
|
System.out.println("\nStudierende/r s3:");
|
|
|
s3.ausgeben();
|
|
|
}
|
|
|
}
|
|
14.3 Klasse Stud |
|
|
package hochschule;
|
|
|
|
|
Definition des Records Stud. Die in der Klammer angegebenen Bestandteile sind die Komponenten des Records. Java erzeugt daraus automatisch einen Konstruktor sowie Zugriffsmethoden. |
|
|
public record Stud(String name, String vName, int plz, String ort, int anzSem, String gebTag) {
|
|
|
void ausgeben() {
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname: " + vName);
|
|
|
System.out.println("PLZ: " + plz);
|
|
|
System.out.println("Ort: " + ort);
|
|
|
System.out.println("Anzahl Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
14.4 Ergebnis Programmlauf |
|
|
Ausgabe einzelner Attributsausprägungen:
|
|
|
|
|
|
Name: Stauder
|
|
|
Name: Müller
|
|
|
|
|
|
Ausgabe records s1 ... s3:
|
|
|
|
|
|
Stud[name=Stauder, vName=Franz, plz=88888, ort=Überall, anzSem=5, gebTag=20.1.2000]
|
|
|
Stud[name=Müller, vName=Franz, plz=99999, ort=Nirgendwo, anzSem=13, gebTag=1.1.2001]
|
|
|
Stud[name=Müller, vName=Franz, plz=99999, ort=Nirgendwo, anzSem=13, gebTag=1.1.2001]
|
|
|
|
|
|
Vergleich der Objekte:
|
|
|
|
|
|
s1 und s2: Nicht wertgleiche Studierende.
|
|
|
s3 und s2: Wertgleiche Studierende.
|
|
|
s3 und s1: Nicht wertgleiche Studierende.
|
|
|
|
|
|
Studierende/r s1:
|
|
|
Name: Stauder
|
|
|
Vorname: Franz
|
|
|
PLZ: 88888
|
|
|
Ort: Überall
|
|
|
Anzahl Semester: 5
|
|
|
Geburtstag: 20.1.2000
|
|
|
|
|
|
Studierende/r s2:
|
|
|
Name: Müller
|
|
|
Vorname: Franz
|
|
|
PLZ: 99999
|
|
|
Ort: Nirgendwo
|
|
|
Anzahl Semester: 13
|
|
|
Geburtstag: 1.1.2001
|
|
|
|
|
|
Studierende/r s3:
|
|
|
Name: Müller
|
|
|
Vorname: Franz
|
|
|
PLZ: 99999
|
|
|
Ort: Nirgendwo
|
|
|
Anzahl Semester: 13
|
|
|
Geburtstag: 1.1.2001
|
|
|
|
|
14.5 Betrachtete Themen |
|
- Abfrage einzelner Komponenten mit name(), vName() usw.
- Ausgabe vollständiger Record-Objekte
- automatische equals()-Methode
- automatische hashCode()-Methode
- automatische Konstruktorerzeugung
- automatische toString()-Methode
- automatische Zugriffsmethoden
- boolesche Ausdrücke
- Datenorientierte Klassen
- eigene Methoden in Records
- Erzeugen von Record-Objekten mit new
- if/else-Anweisung
- kompakte Schreibweise für Datenobjekte
- Konsolenausgabe mit System.out.println()
- Konstruktoraufruf
- Methode ausgeben()
- Objektreferenzen
- Package-Konzept
- Parameterübergabe an den Record-Konstruktor
- Record-Klassen
- Record-Komponenten
- Schlüsselwort record
- Unterschied zwischen equals() und ==
- Unterschied zwischen Record und normaler Klasse
- unveränderliche Objektdaten
- Vergleich von Record-Objekten
- wertbasierte Gleichheit
- Zugriffsmethoden ohne get-Präfix
|
|
14.6 Exkurs - Record vs. Klasse |
|
Ein Record ist in Java eine besondere Form einer Klasse. Jeder Record ist gleichzeitig auch eine Klasse, aber nicht jede Klasse ist ein record. Intern wird für einen Record automatisch eine Klasse erzeugt. Das bedeutet |
|
|
public record Stud(...)
|
|
entspricht ungefähr |
|
|
public final class Stud,
|
|
allerdings mit automatisch erzeugtem Zusatzcode. |
|
Der Record-Kopf gibt die Komponenten des Records an: |
|
|
(String name, String vName, int plz, String ort, int anzSem, String gebTag)
|
|
Java erzeugt daraus automatisch: |
|
- private finale Attribute
- einen Konstruktor
- Getter-Methoden
- toString()
- equals()
- hashCode()
|
|
Intern entsteht ungefähr: |
|
|
private final String name;
|
|
|
private final String vName;
|
|
|
private final int plz;
|
|
|
...
|
|
Java erzeugt auch automatisch einen Konstruktor, etwa so: |
|
|
public Stud(String name, String vName, int plz, String ort, int anzSem, String gebTag) {
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
...
|
|
|
}
|
|
Ebenso entsteht für jede Komponente auch eine Zugriffsmethode, die den ansonsten üblichen Getter-Methoden entspricht: |
|
|
name()
|
|
|
vName()
|
|
|
plz()
|
|
|
ort()
|
|
|
anzSem()
|
|
|
gebTag()
|
|
Der Methodenaufruf erfolgt dann z.B. so: |
|
|
s1.name()
|
|
Merksatz |
|
Ein Record ist eine spezielle Klasse zur einfachen Verwaltung unveränderlicher Daten. |
|
14.7 Exkurs - Methode hashCode() |
|
Die Methode hashCode() liefert zu einem Objekt eine ganze Zahl (int), die als eine Art "numerischer Fingerabdruck" des Objekts dient. Sie wird vor allem für Datenstrukturen verwendet wie: |
|
- HashMap
- HashSet
- Hashtable
|
|
Dort hilft der Hashcode dabei, Objekte schnell wiederzufinden. Einfaches Bild: |
|
- Der Hashcode bestimmt, in welches "Fach" oder welchen "Behälter" ein Objekt einsortiert wird.
- Dadurch muss später nicht die gesamte Sammlung durchsucht werden.
|
|
Beispiel: |
|
- String s1 = "Hallo";
- System.out.println(s1.hashCode());
|
|
Ausgabe z.B.: |
|
|
69609650
|
|
Damit wurde in Java eine alte Dateitechnik herangezogen, die der Direktzugriffsdateien/Hashing. Vgl. für eine Kurzbeschreibung: |
|
|
https://www.staud.info/rm2/rm_t_1.php#Abschnitt22.5
|
|
Wichtig ist, in einem "Behälter" sind tatsächlich mehrere Objekte, dort muss also weiterhin sequentiell gesucht werden. Trotzdem reduziert sich der insgesamt notwendige Suchaufwand enorm. |
|
15 Projekt HS7 - Vererbung, Attribute |
|
Hier wird an einem einfachen Beispiel die Umsetzung des Vererbungskonzepts in Java gezeigt. Dies erfolgt anhand des folgenden Auschnitts aus der Vererbungshierarchie von Abbildung 6.5-1 aus [Staud 2019] und anhand von Attributen. |
|
Die Superklasse ist Fahrzeuge, zwei Subklassen davon sind PKW und LKW, eine weitere Subklasse, jetzt aber von PKW, ist VAN. Attribute sind unten in den Programmen angegeben. |
|

|
|
Abbildung 14.7-1: Generalisierung / Spezialisierung mit Vererbung. Quelle: Auszug aus [Staud 2019, Abbildung 14.7-2] |
|
Darstellung |
|
Bei diesem Projekt betrachten wir zuerst die Klassen der Generalisierung / Spezialisierung mit ihrer Vererbungshierarchie, dann das HP (Hauptprogramm). Auch hier werden die Beispiele ganz einfach gehalten und auf die aktuelle Fragestellung zugeschnitten. |
|
|
|
15.1 Klasse Fahrzeuge |
|
Klasse Fahrzeuge mit Erläuterungen |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class Fahrzeuge {
|
|
|
int fzNr = 0;
|
|
|
float listenPreis = 0.0F;
|
|
Eingeschränkte Sichtbarkeit mit private. |
|
|
private float marktPreis = 0.0f;
|
|
|
String hersteller;
|
|
|
String bez;
|
|
|
int baujahr;
|
|
|
String datumZul;
|
|
|
double gewicht;
|
|
Mögliche Einträge in antrieb: d = Diesel, b = Benzin, e = Elektro, h = Hybrid |
|
|
char antrieb = 'n'
|
|
|
int kw;
|
|
|
String getriebe;
|
|
Der Marktpreis des jeweiligen Objekts kann von den anderen Klassen wegen Sichtbarkeit private nicht direkt abgefragt werden. Deshalb die folgende Methode. Diese wird dann von HP aufgerufen. |
|
|
void marktPreis() {
|
|
|
System.out.println("Derzeitiger Marktpreis vor EINTRAGEN: " + marktPreis);
|
|
|
}
|
|
Eintragen in private marktPreis. |
|
|
void marktPreisEintragen(float marktPreis) {
|
|
|
this.marktPreis = marktPreis;
|
|
|
System.out.println("Derzeitiger Marktpreis nach EINTRAGEN: " + marktPreis);
|
|
|
}
|
|
|
}
|
|
Klasse Fahrzeuge ohne Erläuterungen |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class Fahrzeuge {
|
|
|
int fzNr = 0;
|
|
|
float listenPreis = 0.0F;
|
|
|
private float marktPreis = 0.0f;
|
|
|
String hersteller;
|
|
|
String bez;
|
|
|
int baujahr;
|
|
|
String datumZul;
|
|
|
double gewicht;
|
|
|
char antrieb = 'n';
|
|
|
int kw;
|
|
|
String getriebe;
|
|
|
|
|
|
void marktPreis() {
|
|
|
System.out.println("Derzeitiger Marktpreis vor EINTRAGEN: " + marktPreis);
|
|
|
}
|
|
|
|
|
|
void marktPreisEintragen(float marktPreis) {
|
|
|
this.marktPreis = marktPreis;
|
|
|
System.out.println("Derzeitiger Marktpreis nach EINTRAGEN: " + marktPreis);
|
|
|
}
|
|
|
}
|
|
15.2 Klasse PKW |
|
Diese Subklasse von Fahrzeuge enthält Attribute, die spezifisch sind für PKW oder die im jeweiligen Kontext nur für PKW erhoben werden sollen. |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class PKW extends Fahrzeuge {
|
|
|
String garantie = "nicht erfasst";
|
|
|
String typ;
|
|
|
int autonomStufe;
|
|
15.3 Klasse LKW |
|
Klasse LKW mit Erläuterungen |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class LKW extends Fahrzeuge {
|
|
Spezifische Attribute für LKW. Erbt alle Attribute und Methoden von Fahrzeuge. |
|
|
double ladeKap;
|
|
|
int zahlAchsen;
|
|
|
String zustand = "---";
|
|
Konstruktor mit Datenübergabe per Parameter. Aufruf siehe HP. |
|
|
public LKW(int fzNr, float listenPreis, String hersteller, String bez, int baujahr, String datumZul, double gewicht, char antrieb, int kw, String getriebe, double ladeKap, int zahlAchsen, String zustand) {
|
|
|
this.fzNr = fzNr;
|
|
|
this.listenPreis = listenPreis;
|
|
|
this.hersteller = hersteller;
|
|
|
this.bez = bez;
|
|
|
this.baujahr = baujahr;
|
|
|
this.datumZul = datumZul;
|
|
|
this.gewicht = gewicht;
|
|
|
this.antrieb = antrieb;
|
|
|
this.kw = kw;
|
|
|
this.getriebe = getriebe;
|
|
|
this.ladeKap = ladeKap;
|
|
|
this.zahlAchsen = zahlAchsen;
|
|
|
this.zustand = zustand;
|
|
|
}
|
|
Standardkonstruktor. Ist voreingestellt da und muss normalerweise nicht angegeben werden. Hier aber notwendig, weil oben ein spezifischer Konstruktor angegeben wurde. |
|
|
public LKW() {
|
|
|
}
|
|
|
}
|
|
Klasse LKW ohne Erläuterungen |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class LKW extends Fahrzeuge {
|
|
|
double ladeKap;
|
|
|
int zahlAchsen;
|
|
|
String zustand = "---";
|
|
|
public LKW(int fzNr, float listenPreis, String hersteller,
|
|
|
String bez, int baujahr, String datumZul, double gewicht,
|
|
|
char antrieb, int kw, String getriebe, double ladeKap,
|
|
|
int zahlAchsen, String zustand) {
|
|
|
this.fzNr = fzNr;
|
|
|
this.listenPreis = listenPreis;
|
|
|
this.hersteller = hersteller;
|
|
|
this.bez = bez;
|
|
|
this.baujahr = baujahr;
|
|
|
this.datumZul = datumZul;
|
|
|
this.gewicht = gewicht;
|
|
|
this.antrieb = antrieb;
|
|
|
this.kw = kw;
|
|
|
this.getriebe = getriebe;
|
|
|
this.ladeKap = ladeKap;
|
|
|
this.zahlAchsen = zahlAchsen;
|
|
|
this.zustand = zustand;
|
|
|
}
|
|
|
public LKW() {
|
|
|
}
|
|
|
}
|
|
15.4 Klasse VAN |
|
Klasse VAN mit Erläuterungen |
|
Subklasse von PKW. Diese kann also die Attribute und Methoden von PKW und von Fahrzeuge erben. Sie selbst enthält Attribute, die spezifisch sind für VANs oder die im jeweiligen Kontext nur für VANs erhoben werden sollen. |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class VAN extends PKW {
|
|
|
int maxPers = 0;
|
|
|
boolean bank = false;
|
|
Konstruktor mit Übergabe der Werte beim Aufruf. |
|
|
public VAN(int maxPers, boolean bank) {
|
|
|
this.maxPers = maxPers;
|
|
|
this.bank = bank;
|
|
|
}
|
|
Methode ausgeben() in VAN mit Zugriff auf die Attribute von Superklassen (übergeordneten Klassen). Alle folgenden Attribute geerbt von Fahrzeuge. |
|
|
void ausgeben() {
|
|
|
System.out.println("Inventarnummer: " + fzNr);
|
|
|
System.out.println("Hersteller: " + hersteller);
|
|
|
System.out.println("Bezeichnung: " + bez);
|
|
|
System.out.println("Baujahr: " + baujahr);
|
|
|
System.out.println("Datum der Erstzulassung: " + datumZul);
|
|
|
System.out.println("Antriebsart: " + antrieb);
|
|
|
System.out.println("Listenpreis: " + listenPreis);
|
|
|
System.out.println("Gewicht: " + gewicht);
|
|
|
System.out.println("Nennleistung: " + kw);
|
|
|
System.out.println("Getriebe: " + getriebe);
|
|
Die nächsten drei Attribute stammen von der Klasse PKW. |
|
|
System.out.println("Garantie: " + garantie);
|
|
|
System.out.println("Typ: " + typ);
|
|
|
System.out.println("Automatisches Fahren, Stufe: " + autonomStufe);
|
|
Die nächsten zwei von der Klasse VAN. |
|
|
System.out.println("Maximale Anzahl Personen: " + maxPers);
|
|
|
System.out.println("Bank: " + bank);
|
|
|
}
|
|
|
}
|
|
Klasse VAN ohne Erläuterungen |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class VAN extends PKW {
|
|
|
int maxPers = 0;
|
|
|
boolean bank = false;
|
|
|
public VAN(int maxPers, boolean bank) {
|
|
|
this.maxPers = maxPers;
|
|
|
this.bank = bank;
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println("Inventarnummer: " + fzNr);
|
|
|
System.out.println("Hersteller: " + hersteller);
|
|
|
System.out.println("Bezeichnung: " + bez);
|
|
|
System.out.println("Baujahr: " + baujahr);
|
|
|
System.out.println("Datum der Erstzulassung: " + datumZul);
|
|
|
System.out.println("Antriebsart: " + antrieb);
|
|
|
System.out.println("Listenpreis: " + listenPreis);
|
|
|
System.out.println("Gewicht: " + gewicht);
|
|
|
System.out.println("Nennleistung: " + kw);
|
|
|
System.out.println("Getriebe: " + getriebe);
|
|
|
System.out.println("Garantie: " + garantie);
|
|
|
System.out.println("Typ: " + typ);
|
|
|
System.out.println("Automatisches Fahren, Stufe: " + autonomStufe);
|
|
|
System.out.println("Maximale Anzahl Personen: " + maxPers);
|
|
|
System.out.println("Bank: " + bank);
|
|
|
}
|
|
|
}
|
|
15.5 Klasse HP |
|
Im Hauptprogramm (Klasse HP) wird die Nutzung des Vererbungsmechanismus demonstriert. Zuerst mit Hilfe des Konstruktors von VAN, dessen Objekte von zwei übergeordneten Klassen die Attribute übernehmen. Dann mit der Klasse LKW, die von der Superklasse erbt. Abschließend wird ein Objekt von Fahrzeuge instanziiert, das von keiner anderen Klasse erbt. Außerdem sind mehrere Methodenaufrufe entlang der Vererbungsbeziehungen eingefügt. |
|
Nicht vergessen: "requires java.desktop;" eintragen in module-info.java |
|
|
package fahrzeuge;
|
|
|
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
VAN van1 = new VAN(1, false);
|
|
|
String eingabe;
|
|
|
|
|
|
System.out.println("\nKonstruktor mit Klasse VAN");
|
|
|
System.out.println("(geerbt wird von PKW und Fahrzeuge):");
|
|
|
System.out.println();
|
|
|
System.out.println("Ausgabe des Objekts der Klasse VAN im HP \nOHNE DATEN mit Methode aus VAN:\n");
|
|
|
van1.ausgeben();
|
|
|
|
|
|
System.out.println("\nBeschreiben aller Attribute des Objekts der Klasse VAN im HP\n");
|
|
|
van1.fzNr = 1007;
|
|
|
van1.listenPreis = 50000;
|
|
|
van1.hersteller = "VW";
|
|
|
van1.bez = "Touran";
|
|
|
van1.baujahr = 2020;
|
|
|
van1.datumZul = "1.1.2020";
|
|
|
van1.gewicht = 3.5D;
|
|
|
van1.antrieb = 'd';
|
|
|
van1.kw = 150;
|
|
|
van1.getriebe = "Automatik";
|
|
|
van1.garantie = "3 Jahre";
|
|
|
van1.typ = "L";
|
|
|
van1.autonomStufe = 1;
|
|
|
van1.maxPers = 10;
|
|
|
van1.bank = true;
|
|
|
|
|
|
System.out.println(
|
|
|
"\n===========Ausgabe des Objekts der Klasse VAN im HP \nMIT DATEN und der Methode aus VAN:\n");
|
|
|
van1.ausgeben();
|
|
|
|
|
|
System.out.println("\n==========Methoden in Fahrzeuge aufrufen:==========\n");
|
|
|
van1.marktPreis();
|
|
|
System.out.println("Marktpreis festlegen");
|
|
|
eingabe = JOptionPane.showInputDialog("Neuer Marktpreis: ");
|
|
|
float marktPreis = Float.parseFloat(eingabe);
|
|
|
van1.marktPreisEintragen(marktPreis);
|
|
|
|
|
|
System.out.println("\n=====Methodeneinsatz für Preiserhöhung=====");
|
|
|
System.out.println("Bisheriger Preis: " + van1.listenPreis);
|
|
|
eingabe = JOptionPane.showInputDialog("Gewünschte Preiserhöhung in %: ");
|
|
|
int erhPreis = Integer.parseInt(eingabe);
|
|
|
|
|
|
System.out.println("Alter Preis: " + van1.listenPreis);
|
|
|
System.out.println("Gewünschte Erhöhung: " + erhPreis + "%");
|
|
|
|
|
|
van1.listenPreis = (van1.listenPreis / 100) * (100 + erhPreis);
|
|
|
System.out.println("Neuer Preis: " + van1.listenPreis);
|
|
|
|
|
|
System.out.println("\n==========Konstruktor von Klasse LKW==========");
|
|
|
System.out.println("(geerbt wird nur von Fahrzeuge):\n");
|
|
|
|
|
|
LKW lkw1 = new LKW();
|
|
|
System.out.println("Daten von Objekt LKW1: \n");
|
|
|
lkw1.fzNr = 123456;
|
|
|
System.out.println("Fahrzeugnummer: " + lkw1.fzNr);
|
|
|
lkw1.listenPreis = 150299.90F;
|
|
|
System.out.println("Listenpreis: " + lkw1.listenPreis);
|
|
|
lkw1.antrieb = 'd';
|
|
|
|
|
|
if (lkw1.antrieb == 'd')
|
|
|
System.out.println("Antrieb: Diesel");
|
|
|
else if (lkw1.antrieb == 'b')
|
|
|
System.out.println("Antrieb: Benzin");
|
|
|
else if (lkw1.antrieb == 'e')
|
|
|
System.out.println("Antrieb: Elektro");
|
|
|
else if (lkw1.antrieb == 'h')
|
|
|
System.out.println("Antrieb: Hybrid");
|
|
|
else
|
|
|
System.out.println("Antrieb: unbekannt");
|
|
|
|
|
|
lkw1.datumZul = "1.1.2010";
|
|
|
System.out.println("Datum Erstzulassung: " + lkw1.datumZul);
|
|
|
lkw1.gewicht = 7.5D;
|
|
|
System.out.println("Gewicht: " + lkw1.gewicht);
|
|
|
lkw1.ladeKap = 40.5;
|
|
|
System.out.println("Ladekapazität: " + lkw1.ladeKap);
|
|
|
lkw1.zahlAchsen = 6;
|
|
|
System.out.println("Anzahl Achsen: " + lkw1.zahlAchsen);
|
|
|
lkw1.zustand = "Schlecht";
|
|
|
System.out.println("Zustand des LKW: " + lkw1.zustand);
|
|
|
|
|
|
LKW lkw2 = new LKW(12345, 50000.60F, "BMW", "xyzhybrid",
|
|
|
2022, "1.1.2022", 1500, 'h', 240, "Automatik", 40.5, 4,
|
|
|
"Toll");
|
|
|
|
|
|
System.out.println("\nDaten von Objekt LKW2: \n");
|
|
|
System.out.println("Fahrzeugnummer: " + lkw2.fzNr);
|
|
|
System.out.println("Listenpreis2: " + lkw2.listenPreis);
|
|
|
System.out.println("Antrieb: " + lkw2.antrieb);
|
|
|
System.out.println("Datum Erstzulassung: " + lkw2.datumZul);
|
|
|
System.out.println("Gewicht: " + lkw2.gewicht);
|
|
|
System.out.println("Ladekapazität: " + lkw2.ladeKap);
|
|
|
System.out.println("Anzahl Achsen: " + lkw2.zahlAchsen);
|
|
|
System.out.println("Zustand des LKW: " + lkw2.zustand);
|
|
|
|
|
|
System.out.println("\n==========Konstruktor von Klasse Fahrzeuge==========");
|
|
|
System.out.println("(nichts wird geerbt):\n");
|
|
|
|
|
|
Fahrzeuge fz1 = new Fahrzeuge();
|
|
|
fz1.datumZul = "1.1.2016";
|
|
|
System.out.println("Zulassung: " + fz1.datumZul);
|
|
|
fz1.fzNr = 12345;
|
|
|
System.out.println("Fahrzeugnummer: " + fz1.fzNr);
|
|
|
fz1.antrieb = 'b';
|
|
|
System.out.println("Antrieb: " + fz1.antrieb);
|
|
|
fz1.listenPreis = 120900.00F;
|
|
|
System.out.println("Preis: " + fz1.listenPreis);
|
|
|
fz1.gewicht = 2.0D;
|
|
|
System.out.println("Gewicht: " + fz1.gewicht);
|
|
|
fz1.kw = 140;
|
|
|
System.out.println("Motorleistung (kW): " + fz1.kw);
|
|
|
fz1.getriebe = "Schalter";
|
|
|
System.out.println("Getriebe: " + fz1.getriebe);
|
|
|
fz1.baujahr = 2020;
|
|
|
System.out.println("Baujahr: " + fz1.baujahr);
|
|
|
}
|
|
|
}
|
|
15.6 Ergebnis Programmlauf |
|
Folgende zwei Eingabefenster kommen zum Einsatz: |
|

|
|
|
|
|

|
|
|
|
Bildschirmausgabe: |
|
|
Konstruktor mit Klasse VAN
|
|
|
(geerbt wird von PKW und Fahrzeuge):
|
|
|
|
|
|
Ausgabe des Objekts der Klasse VAN im HP
|
|
|
OHNE DATEN mit Methode aus VAN:
|
|
|
|
|
|
Inventarnummer: 0
|
|
|
Hersteller: null
|
|
|
Bezeichnung: null
|
|
|
Baujahr: 0
|
|
|
Datum der Erstzulassung: null
|
|
|
Antriebsart: n
|
|
|
Listenpreis: 0.0
|
|
|
Gewicht: 0.0
|
|
|
Nennleistung: 0
|
|
|
Getriebe: null
|
|
|
Garantie: nicht erfasst
|
|
|
Typ: null
|
|
|
Automatisches Fahren, Stufe: 0
|
|
|
Maximale Anzahl Personen: 1
|
|
|
Bank: false
|
|
|
|
|
|
Beschreiben aller Attribute des Objekts der Klasse VAN im HP
|
|
|
|
|
|
|
|
|
======Ausgabe des Objekts der Klasse VAN im HP
|
|
|
MIT DATEN und der Methode aus VAN:
|
|
|
|
|
|
Inventarnummer: 1007
|
|
|
Hersteller: VW
|
|
|
Bezeichnung: Touran
|
|
|
Baujahr: 2020
|
|
|
Datum der Erstzulassung: 1.1.2020
|
|
|
Antriebsart: d
|
|
|
Listenpreis: 50000.0
|
|
|
Gewicht: 3.5
|
|
|
Nennleistung: 150
|
|
|
Getriebe: Automatik
|
|
|
Garantie: 3 Jahre
|
|
|
Typ: L
|
|
|
Automatisches Fahren, Stufe: 1
|
|
|
Maximale Anzahl Personen: 10
|
|
|
Bank: true
|
|
|
|
|
|
=====Methoden in Fahrzeuge aufrufen:=====
|
|
|
|
|
|
Derzeitiger Marktpreis vor EINTRAGEN: 0.0
|
|
|
Marktpreis festlegen
|
|
|
Derzeitiger Marktpreis nach EINTRAGEN: 40000.0
|
|
|
|
|
|
=====Methodeneinsatz für Preiserhöhung=====
|
|
|
Bisheriger Preis: 50000.0
|
|
|
Alter Preis: 50000.0
|
|
|
Gewünschte Erhöhung: 10%
|
|
|
Neuer Preis: 55000.0
|
|
|
|
|
|
=====Konstruktor von Klasse LKW=====
|
|
|
(geerbt wird nur von Fahrzeuge):
|
|
|
|
|
|
Daten von Objekt LKW1:
|
|
|
|
|
|
Fahrzeugnummer: 123456
|
|
|
Listenpreis: 150299.9
|
|
|
Antrieb: Diesel
|
|
|
Datum Erstzulassung: 1.1.2010
|
|
|
Gewicht: 7.5
|
|
|
Ladekapazität: 40.5
|
|
|
Anzahl Achsen: 6
|
|
|
Zustand des LKW: Schlecht
|
|
|
|
|
|
Daten von Objekt LKW2:
|
|
|
|
|
|
Fahrzeugnummer: 12345
|
|
|
Listenpreis2: 50000.6
|
|
|
Antrieb: h
|
|
|
Datum Erstzulassung: 1.1.2022
|
|
|
Gewicht: 1500.0
|
|
|
Ladekapazität: 40.5
|
|
|
Anzahl Achsen: 4
|
|
|
Zustand des LKW: Toll
|
|
|
|
|
|
=====Konstruktor von Klasse Fahrzeuge=====
|
|
|
(nichts wird geerbt):
|
|
|
|
|
|
Zulassung: 1.1.2016
|
|
|
Fahrzeugnummer: 12345
|
|
|
Antrieb: b
|
|
|
Preis: 120900.0
|
|
|
Gewicht: 2.0
|
|
|
Motorleistung (kW): 140
|
|
|
Getriebe: Schalter
|
|
|
Baujahr: 2020
|
|
15.7 Betrachtete Themen |
|
- Arithmetische Berechnungen
- Attribute
- Benutzereingaben mit JOptionPane
- Boolesche Werte (boolean)
- Eigene Attribute von Subklassen
- Geerbte Attribute
- Geerbte Methoden
- Generalisierung
- Hauptprogramm (main())
- Kapselung
- Klassen
- Konsolenausgaben mit System.out.println()
- Konstruktor mit Parametern
- Konstruktoren
- Mehrstufige Spezialisierung von Klassen
- Mehrstufige Vererbung
- Methoden
- Methodenaufrufe
- Objekte
- Objekte instanziieren (new)
- Objektorientierte Modellierung
- Primitive Datentypen
- private
- Referenzdatentypen (String)
- Sichtbarkeit von Attributen
- Spezialisierung
- Standardkonstruktor
- Subklasse
- Superklasse
- Typumwandlung mit Float.parseFloat()
- Typumwandlung mit Integer.parseInt()
- Vererbung (extends)
- Vererbungshierarchie
- Verwendung von this
- Verzweigungen mit if - else if - else
- Wiederverwendung von Programmcode durch Vererbung
- Zeichenwerte (char)
- Zugriff auf geerbte Attribute
|
|
15.8 Projektbeschreibung |
|
15.8.1 Ziel des Projekts |
|
Das Projekt HS7 dient der weiteren Einführung in die objektorientierte Programmierung mit Java. Im Mittelpunkt stehen folgende Konzepte: |
|
- Klassen und Objekte
- Vererbung
- Konstruktoren
- geerbte Attribute und Methoden
- Spezialisierung von Klassen
- einfache Methodenaufrufe
|
|
Das Projekt zeigt anhand verschiedener Fahrzeugtypen, wie gemeinsame Eigenschaften in einer Superklasse zusammengefasst und von Subklassen übernommen werden können. |
|
15.8.2 Aufbau des Projekts |
|
Das Projekt besteht aus fünf Klassen: |
|
|
|
| Klasse |
Bedeutung |
| Fahrzeuge |
Superklasse mit allgemeinen Fahrzeugdaten |
| PKW |
Subklasse von Fahrzeuge |
| VAN |
Subklasse von PKW |
| LKW |
Subklasse von Fahrzeuge |
| HP |
Hauptprogramm mit main() |
| |
|
|
Zur Vererbungsstruktur vgl. Kapitelanfang. Es gilt also: |
|
- Ein
PKW ist ein spezielles Fahrzeug.
- Ein
VAN ist ein spezieller PKW.
- Ein
LKW ist ebenfalls ein spezielles Fahrzeug.
|
|
D.h., Fahrzeuge ist Superklasse von PKW und LKW, PKW ist Superklasse von VAN. |
|
15.8.3 Beschreibung der einzelnen Klassen |
|
Klasse Fahrzeuge |
|
Die Klasse Fahrzeuge bildet die Superklasse des Projekts. Sie enthält allgemeine Attribute, die für alle Fahrzeuge gelten, zum Beispiel: |
|
- int fzNr;
- float listenPreis;
- String hersteller;
- String bez;
|
|
Zusätzlich enthält die Klasse: |
|
|
private float marktPreis;
|
|
Dieses Attribut ist privat und kann deshalb nicht direkt von außen verändert werden. Der Zugriff erfolgt über Methoden: |
|
- void marktPreis()
- void marktPreisEintragen(float marktPreis)
|
|
Damit wird das Prinzip der Kapselung vorbereitet. |
|
Klasse PKW |
|
Die Klasse PKW erbt von Fahrzeuge: |
|
|
public class PKW extends Fahrzeuge
|
|
Zusätzlich besitzt ein PKW weitere Eigenschaften: |
|
|
String garantie;
|
|
|
String typ;
|
|
|
int autonomStufe;
|
|
Außerdem enthält die Klasse die Methode: |
|
|
void komfortAnzeige()
|
|
Damit wird gezeigt, dass Subklassen eigene Methoden ergänzen können. |
|
Klasse VAN |
|
Die Klasse VAN erweitert die Klasse PKW: |
|
|
public class VAN extends PKW
|
|
Ein VAN besitzt zusätzliche Attribute: |
|
|
int maxPers;
|
|
|
boolean bank;
|
|
Die Klasse enthält: |
|
- einen Konstruktor mit Parametern
- die Methode ausgeben()
|
|
Die Methode ausgeben() gibt sowohl eigene als auch geerbte Attribute aus. Dadurch wird sichtbar, dass ein Objekt der Klasse VAN alle Eigenschaften der Superklasse besitzt. |
|
Klasse LKW |
|
Die Klasse LKW erbt direkt von Fahrzeuge: |
|
|
public class LKW extends Fahrzeuge
|
|
Zusätzliche Attribute sind: |
|
|
double ladeKap;
|
|
|
int zahlAchsen;
|
|
|
String zustand;
|
|
Die Klasse besitzt: |
|
- einen parameterlosen Konstruktor
- einen Konstruktor mit vielen Parametern
|
|
Damit wird der Einsatz verschiedener Konstruktoren demonstriert. |
|
Klasse HP |
|
Die Klasse HP enthält die Methode: |
|
|
public static void main(String[] args)
|
|
Sie dient als Hauptprogramm zum Testen aller Klassen. Im Hauptprogramm werden: |
|
- Objekte erzeugt
- Attribute beschrieben
- Methoden aufgerufen
- Konstruktoren getestet
- Ausgaben auf der Konsole erzeugt
|
|
15.8.4 Ablauf des Programms |
|
Erzeugen eines VAN-Objekts |
|
|
VAN van1 = new VAN(1, false);
|
|
Zunächst werden nur die Attribute gesetzt, die im Konstruktor von VAN vorkommen. Danach erfolgt eine Ausgabe ohne weitere Daten. |
|
Beschreiben der geerbten Attribute |
|
Anschließend werden zahlreiche geerbte Attribute beschrieben: |
|
|
van1.fzNr = 1007;
|
|
|
van1.hersteller = "VW";
|
|
|
van1.listenPreis = 50000;
|
|
Damit wird gezeigt, dass ein VAN auf geerbte Eigenschaften zugreifen kann. |
|
Methodenaufrufe |
|
Es werden Methoden aus der Superklasse Fahrzeuge verwendet: |
|
|
van1.marktPreis();
|
|
|
van1.marktPreisEintragen(marktPreis);
|
|
Dadurch wird deutlich: Subklassen erben nicht nur Attribute, sondern auch Methoden. |
|
Preisänderung |
|
Im Hauptprogramm wird eine prozentuale Preiserhöhung berechnet. Dabei wird der Umgang mit Benutzereingaben und Berechnungen gezeigt. |
|
Arbeiten mit LKW-Objekten |
|
Es werden zwei LKW-Objekte erzeugt: |
|
|
LKW lkw1 = new LKW();
|
|
|
LKW lkw2 = new LKW(...);
|
|
Dadurch wird der Unterschied zwischen: |
|
- parameterlosen Konstruktoren
- Konstruktoren mit Parametern
|
|
sichtbar. |
|
Arbeiten mit einem Fahrzeuge-Objekt |
|
Zum Schluss wird ein Objekt der Superklasse direkt erzeugt: |
|
|
Fahrzeuge fz1 = new Fahrzeuge();
|
|
Dadurch wird gezeigt: |
|
- Auch Superklassen können selbst Objekte erzeugen.
- Subklassen erweitern lediglich die vorhandenen Eigenschaften.
|
|
16 Projekt HS7a - Override und Overload |
|
Hier nun, ganz auf den Punkt gebracht, ein Beispiel zu Override und Overload. Bei den beiden Klassen handelt es sich um gekürzte Versionen von HS7. |
|
Zu beachten ist die Vererbungshierarchie. Die Klasse PKW erbt von der Klasse Fahrzeuge, d.h. die Klasse PKW übernimmt die Attribute fzNr und hersteller sowie grundsätzlich auch die Methode ausgeben() aus der Superklasse. |
|
|
|
16.1 Klasse HP |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
Ein Objekt der Klasse PKW wird eingerichtet und beschrieben: |
|
|
PKW p1 = new PKW();
|
|
|
p1.fzNr = 1001;
|
|
|
p1.hersteller = "VW";
|
|
|
p1.sitzplaetze = 5;
|
|
|
|
|
|
System.out.println("--- Normale Ausgabe ---");
|
|
|
p1.ausgeben();
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
System.out.println("--- Ausgabe mit Überschrift ---");
|
|
|
p1.ausgeben("Daten des PKW:");
|
|
Oben wird einmal die Methode ohne bzw. mit Parametertext ausgegeben. |
|
|
}
|
|
|
}
|
|
16.2 Klasse Fahrzeuge |
|
|
package fahrzeuge;
|
|
|
|
|
|
class Fahrzeuge {
|
|
|
int fzNr;
|
|
|
String hersteller;
|
|
|
|
|
|
void ausgeben() {
|
|
|
System.out.println("Fahrzeugnummer: " + fzNr);
|
|
|
System.out.println("Hersteller: " + hersteller);
|
|
|
}
|
|
|
}
|
|
16.3 Klasse PKW |
|
|
package fahrzeuge;
|
|
|
|
|
|
class PKW extends Fahrzeuge {
|
|
|
int sitzplaetze;
|
|
Override: Methode aus Fahrzeuge wird überschrieben |
|
|
@Override
|
|
|
void ausgeben() {
|
|
|
System.out.println("Ausgabe aus der Klasse PKW:");
|
|
|
System.out.println("Fahrzeugnummer: " + fzNr);
|
|
|
System.out.println("Hersteller: " + hersteller);
|
|
|
System.out.println("Sitzplätze: " + sitzplaetze);
|
|
|
}
|
|
Overload: gleicher Methodenname, aber anderer Parameter |
|
|
void ausgeben(String titel) {
|
|
|
System.out.println(titel);
|
|
|
ausgeben();
|
|
|
}
|
|
|
}
|
|
16.4 Ergebnis Programmlauf |
|
|
--- Normale Ausgabe ---
|
|
|
Ausgabe aus der Klasse PKW:
|
|
|
Fahrzeugnummer: 1001
|
|
|
Hersteller: VW
|
|
|
Sitzplätze: 5
|
|
|
|
|
|
--- Ausgabe mit Überschrift ---
|
|
|
Daten des PKW:
|
|
|
Ausgabe aus der Klasse PKW:
|
|
|
Fahrzeugnummer: 1001
|
|
|
Hersteller: VW
|
|
|
Sitzplätze: 5
|
|
16.5 Betrachtete Themen |
|
- Annotation @Override
- Attribute
- Ausgabe mit System.out.println()
- Dynamische Bindung bei überschriebenen Methoden
- Einfache Polymorphie durch Methodenüberschreibung
- Instanziierung von Objekten (new)
- Klassen und Objekte
- Methoden
- Methoden mit Parametern
- Methoden ohne Parameter
- Methodenaufruf
- Superklasse und Subklasse
- Objektorientierte Spezialisierung
- Pakete (package)
- Überladen von Methoden (Overload)
- Überschreiben von Methoden (Override)
- Vererbung (extends)
- Wiederverwendung von Methoden
- Zugriff auf geerbte Attribute
|
|
16.6 Exkurs: Override vs. Overload |
|
Die Superklasse Fahrzeuge enthält zwei Attribute und eine Methode ausgeben(). Die Klasse PKW enthält ebenfalls zwei Attribute und eine Methode ausgeben(). Die Methode gibt die Daten des Fahrzeugs aus. |
|
Override - Überschreiben einer Methode |
|
Die Superklasse Fahrzeuge besitzt also bereits die Methode void ausgeben(). In PKW wird dieselbe Methode nochmals geschrieben: |
|
- @Override
- void ausgeben()
|
|
Das wird Override genannt. Die Methode der Superklasse wird in der Subklasse durch eine neue Version ersetzt. Damit können bei einer Ausgabe in PKW die Attribute von Fahrzeuge ergänzt werden. Die Methode wird neu definiert, erweitert und an die Subklasse angepasst. |
|
Die optionale Angabe @Override ist eine sog. Annotation. Sie bedeutet: "Diese Methode überschreibt eine Methode der Superklasse." Der Compiler prüft dadurch, ob wirklich eine passende Methode existiert, ob der Methodenname korrekt geschrieben wurde und ob die Parameter identisch sind. |
|
Overload - Überladen einer Methode |
|
Nun gibt es in PKW zusätzlich: |
|
|
void ausgeben(String titel)
|
|
Damit existieren zwei gleichnamige Methoden, die sich in den Parametern unterscheiden. Dies wird Overload genannt. Die Idee hinter Overload ist, dass eine Methode unterschiedlich verwendet werden kann. Hier z.B. einmal so: |
|
|
p1.ausgeben();
|
|
und zum anderen so: |
|
|
p1.ausgeben("Daten des PKW:");
|
|
Der Methodenname bleibt also gleich, aber die Nutzung wird erweitert. Welche Methode aufgerufen wird, entscheidet Java anhand der Parameter. |
|
Tabellarischer Vergleich |
|
| Override |
Overload |
| Gleiche Methodensignatur |
Gleicher Methodenname |
| Vererbung erforderlich |
Vererbung nicht erforderlich |
| Methode der Superklasse wird ersetzt |
Zusätzliche Variante der Methode |
| Laufzeitentscheidung (Polymorphie) |
Compilerentscheidung |
| Beispiel: ausgeben() in PKW |
Beispiel: ausgeben() und ausgeben(String titel) |
| |
|
|
17 Projekt HS8 - Kapselung |
|
Hier werden an einfachen Beispielen die Möglichkeiten gezeigt, den Zugriff auf Attribute und Methoden zu kontrollieren. Vgl. auch Abschnitt 4.1. |
|
|
|
17.1 Klasse HP |
|
Klasse HP mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
S1 wird mit dem Standardkonstruktor erzeugt. |
|
|
Stud s1 = new Stud();
|
|
|
System.out.println("Leeres Objekt von HP aus mit Methode aus Stud ausgeben:");
|
|
Folgendes klappt, weil die Methode ausgeben() in Stud paketsichtbar ist. Wird kein Modifizierer angegeben, gilt in Java die Paketsichtbarkeit. Da HP und Stud beide im Package hochschule liegen, darf HP diese Methode aufrufen. Auch protected wäre hier erlaubt. Würde man ausgeben() dagegen private machen, wäre die Methode von HP aus nicht sichtbar. Ausprobieren!! |
|
|
s1.ausgeben();
|
|
S0 wird erzeugt (instanziiert) und über den Konstruktor mit Daten versorgt. |
|
|
Stud s0 = new Stud("123", "Maier", "Klara", 5, "21.09.2002");
|
|
|
System.out.println("\nBeschriebenes Objekt von HP aus mit Methode aus Stud ausgeben:");
|
|
Folgendes klappt wiederum, weil der Zugriff aus demselben Package kommt und der Modifizierer der Methode ausgeben() dies erlaubt. |
|
|
s0.ausgeben();
|
|
Das Attribut gebTag kann wegen Sichtbarkeit public abgefragt werden. |
|
|
System.out.println("\nDie Ausgabe des Geburtstags klappt: " + s0.gebTag);
|
|
Zwei Fehlschläge, verursacht durch den Sichtbarkeitsmodizierer. |
|
|
System.out.println("\nDas klappt nicht: s0.name= 'Erwin'");
|
|
|
System.out.println("\nDas auch nicht: System.out.println(s0.name ohne Setter= + s0.name)");
|
|
"Getter" hilft. |
|
|
System.out.println("\nDirekte Abfrage s0.name mit Getter-Methode: " + s0.getName());
|
|
"Setter" ebenso. |
|
|
System.out.println("\nDirektes Beschreiben s0.name mit Setter-Methode (Millifranz): ");
|
|
|
s0.setName("Millifranz");
|
|
|
|
|
|
System.out.println("\nGeänderter Name: " + s0.getName());
|
|
|
}
|
|
|
}
|
|
Klasse HP ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s1 = new Stud();
|
|
|
System.out.println("Leeres Objekt von HP aus mit Methode aus Stud ausgeben:");
|
|
|
s1.ausgeben();
|
|
|
Stud s0 = new Stud("123", "Maier", "Klara", 5, "21.09.2002");
|
|
|
|
|
|
System.out.println("\nBeschriebenes Objekt von HP aus mit Methode aus Stud ausgeben:");
|
|
|
s0.ausgeben();
|
|
|
|
|
|
System.out.println("\nDie Ausgabe des Geburtstags klappt: " + s0.gebTag);
|
|
|
|
|
|
System.out.println("\nDas klappt nicht: s0.name= 'Erwin'");
|
|
|
System.out.println("\nDas auch nicht: System.out.println(s0.name ohne Setter= + s0.name)");
|
|
|
|
|
|
System.out.println("\nDirekte Abfrage s0.name mit Getter-Methode: " + s0.getName());
|
|
|
|
|
|
System.out.println("\nDirektes Beschreiben s0.name mit Setter-Methode (Millifranz): ");
|
|
|
s0.setName("Millifranz");
|
|
|
|
|
|
System.out.println("\nGeänderter Name: " + s0.getName());
|
|
|
}
|
|
|
}
|
|
17.2 Klasse Stud |
|
Klasse Stud mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
|
private String mNr; // Matrikelnummer
|
|
|
private String name; // privat: Zugriff nur über Getter/Setter
|
|
|
String vName; // Paketsichtbar
|
|
|
private int anzSem; // Erreichtes Semester
|
|
|
public String gebTag; // Geburtstag
|
|
Konstruktor mit Parameterübergabe. Er wird vom HP aufgerufen, in der Klasse Stud (natürlich) ausgeführt, deshalb spielen die Sichtbarkeitsmodifizierer keine Rolle |
|
|
public Stud(String mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr = mNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
}
|
|
Standardkonstruktor. |
|
|
public Stud() {
|
|
|
}
|
|
Getter-Methode. Mit ihr ist es möglich, trotz Sichtbarkeitsmodifizierer private das jeweilige Attribut abzufragen. Siehe HP. |
|
|
public String getName() {
|
|
|
return name;
|
|
|
}
|
|
Setter-Methode. Mit ihr ist es möglich, trotz Sichtbarkeitsmodifizierer private das jeweilige Attribut zu beschreiben. Siehe HP. |
|
|
public void setName(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
Methode zum Ausgeben der Daten eines Objekts. |
|
|
void ausgeben() {
|
|
|
System.out.println("\nMatrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
Klasse Stud ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
public class Stud {
|
|
|
private String mNr; // Matrikelnummer
|
|
|
private String name; // privat: Zugriff nur über Getter/Setter
|
|
|
String vName; // Paketsichtbar
|
|
|
private int anzSem; // Erreichtes Semester
|
|
|
public String gebTag; // Geburtstag
|
|
|
public Stud(String mNr, String name, String vName, int anzSem, String gebTag) {
|
|
|
this.mNr = mNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
this.anzSem = anzSem;
|
|
|
this.gebTag = gebTag;
|
|
|
}
|
|
|
public Stud() {
|
|
|
}
|
|
|
public String getName() {
|
|
|
return name;
|
|
|
}
|
|
|
public void setName(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println("\nMatrikelnummer: " + mNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname:" + vName);
|
|
|
System.out.println("Erreichtes Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
17.3 Ergebnis Programmlauf |
|
|
Leeres Objekt von HP aus mit Methode aus Stud ausgeben:
|
|
|
|
|
|
Matrikelnummer: null
|
|
|
Name: null
|
|
|
Vorname:null
|
|
|
Erreichtes Semester: 0
|
|
|
Geburtstag: null
|
|
|
|
|
|
Beschriebenes Objekt von HP aus mit Methode aus Stud ausgeben:
|
|
|
|
|
|
Matrikelnummer: 123
|
|
|
Name: Maier
|
|
|
Vorname:Klara
|
|
|
Erreichtes Semester: 5
|
|
|
Geburtstag: 21.09.2002
|
|
|
|
|
|
Die Ausgabe des Geburtstags klappt: 21.09.2002
|
|
|
|
|
|
Das klappt nicht: s0.name= 'Erwin'
|
|
|
|
|
|
Das auch nicht: System.out.println(s0.name ohne Setter= + s0.name)
|
|
|
|
|
|
Direkte Abfrage s0.name mit Getter-Methode: Maier
|
|
|
|
|
|
Direktes Beschreiben s0.name mit Setter-Methode (Millifranz):
|
|
|
|
|
|
Geänderter Name: Millifranz
|
|
17.4 Projektbeschreibung |
|
HS8 behandelt vor allem: |
|
- Sichtbarkeit von Attributen
- Zugriffsmodifizierer
- Getter- und Setter-Methoden
- kontrollierten Zugriff auf Objektdaten
|
|
Es wird gezeigt, dass Attribute nicht immer direkt von außen verändert werden können sollen. Im Projekt gibt es wieder zwei Klassen: |
|
- HP als Hauptprogramm
- Stud als Datenklasse für Studierende
|
|
Sichtbarkeit |
|
Im Unterschied zu früheren Projekten sind die Attribute jetzt nicht mehr alle gleich sichtbar. In Stud kommen verschiedene Zugriffsarten vor: |
|
- private String mNr;
- private String name;
- String vName;
- private int anzSem;
- public String gebTag;
|
|
Etwas konkreter: |
|
- private mit private String mNr. Dieses Attribut darf nur innerhalb der Klasse Stud direkt benutzt werden.
|
|
Von HP aus wäre also so etwas nicht erlaubt: |
|
|
s0.mNr = "999";
|
|
oder |
|
|
System.out.println(s0.anzSem);
|
|
- "protected" ist geschützter als public, aber weniger streng als private. Es bedeutet also, sichtbar im selben Package und in Subklassen, auch wenn diese in einem anderen Package liegen.
|
|
Da HP im gleichen Package hochschule liegt, ist der Zugriff hier möglich. Das Projekt zeigt aber zugleich, dass man den Zugriff besser über Methoden steuern kann. |
|
- Paketsichtbar mit dem Beispiel String vName;
|
|
Ohne Modifizierer ist das Attribut im gleichen Package sichtbar. |
|
- public mit public String gebTag; Dieses Attribut darf von überall direkt benutzt werden. Darum funktioniert in HP System.out.println(s0.gebTag);
|
|
Die Sichtbarkeitsmodifizierer zusammengefasst: |
|
|
|
| Modifizierer |
Bedeutung |
| private |
Nur innerhalb der Klasse sichtbar |
| kein Modifizierer |
Paketsichtbar |
| protected |
Paket + Subklassen |
| public |
Überall sichtbar |
| |
|
|
Getter und Setter |
|
Wichtige Komponenten in HS8 sind Getter und Setter: |
|
|
public String getName() { //Getter
|
|
|
return name;
|
|
|
}
|
|
und |
|
|
public void setName(String name) {//Setter
|
|
|
this.name = name;
|
|
|
}
|
|
Damit wird name nicht direkt, sondern über Methoden gelesen und geändert. s0.getName() liefert den aktuellen Namen zurück. s0.setName("Millifranz"); ändert den Namen kontrolliert. Damit kann man später Regeln einbauen, zum Beispiel: |
|
|
public void setName(String name) {
|
|
|
if (name != null amp;amp; !name.isBlank()) {
|
|
|
this.name = name;
|
|
|
}
|
|
|
}
|
|
Dann kann nicht einfach irgendein ungültiger Wert gesetzt werden. Das ist ein wichtiger Schritt in Richtung Kapselung. |
|
17.5 Betrachtete Themen |
|
- Attributzugriff
- Defaultwerte von Attributen (null, 0)
- Getter-Methoden
- Informationsverbergung (Information Hiding)
- Kapselung
- Kapselung von Objektdaten
- Konstruktor mit Parameterübergabe
- Konstruktoren
- kontrollierter Attributzugriff
- Methodenaufruf
- Objektinstanziierung mit new
- Package-Konzept
- Paketsichtbarkeit (package-private)
- private
- protected
- public
- Setter-Methoden
- Sichtbarkeitsmodifizierer
- Standardkonstruktor
- Validierung über Setter
- Zugriffsschutz für Attribute
|
|
17.6 Anmerkung |
|
Hier soll v.a. gezeigt werden, dass Attribute nicht einfach immer public sein sollten. Die spätere Erweiterung |
|
|
public void setName(String name) {
|
|
|
if (name != null amp;amp; !name.isBlank()) {
|
|
|
this.name = name;
|
|
|
}
|
|
|
}
|
|
zeigt dann, dass neben dem Verstecken von Daten auch ein kontrollierter Zugriff mit Plausibilitätsprüfungen mögöich wird: |
|
18 Projekt HS9 - Assoziationen |
|
Hier geht es um folgende Aspekte: |
|
- eine Assoziation zwischen Klassen umzusetzen
- den Umgang mit Objektreferenzen zu üben
- eine 1:n-Beziehung in Java zu modellieren
|
|
Dies erfolgt am Beispiel der Verwaltung von Studierenden und ihren Noten. Die Klassen sind: |
|
- Stud (Studierende) mit Matrikelnummer, Name, Vorname
- Noten mit Fach und Note
|
|
Die Assoziation soll mit Objektreferenzen umgesetzt werden. |
|
|
|
18.1 Klasse HP |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
Konstruktor für Studierendenobjekt |
|
|
Stud s1 = new Stud();
|
|
|
s1.mNr = 1001;
|
|
|
s1.name = "Maier";
|
|
|
s1.vName = "Paul";
|
|
Noten erzeugen |
|
|
Note n1 = new Note("Mathe", 2, s1);
|
|
|
Note n2 = new Note("Informatik", 1, s1);
|
|
|
Noten n3 = new Noten("GPM", 3, s1);
|
|
Verknüpfen von Studierenden und Noten |
|
|
s1.addNote(n1);
|
|
|
s1.addNote(n2);
|
|
|
s1.addNote(n3);
|
|
Ausgabe |
|
|
System.out.println(s1.name + " hat folgende Noten:");
|
|
|
for (Noten n : s1.noten) {
|
|
|
System.out.println(n.fach + ": " + n.note);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
18.2 Klasse Stud |
|
Klasse Stud mit Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
Für die Verwaltung mehrerer Objekte werden Klassen aus der Java-Bibliothek importiert. |
|
|
Import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
Hier wird eine Liste für Noten angelegt. Die Bedeutung im Einzelnen: - List<Noten> "List" ist ein allgemeiner Datentyp für Listen. <Noten> bedeutet: In dieser Liste dürfen nur Objekte der Klasse Noten gespeichert werden. Die Liste funktioniert ähnlich wie ein flexibles Array. Der Unterschied: Die Größe muss nicht vorher festgelegt werden. noten: Bezeichnung der Liste. = new ArrayList<>() Mit "new" wird die Liste tatsächlich erzeugt. ArrayList ist eine konkrete Implementierung von List. In die Liste werdenn später Notenobjekte eingefügt. Anfangs ist die Liste leer. |
|
|
List<Note> noten = new ArrayList<>();
|
|
Methode zum Hinzufügen einer Note Der Parameter n ist ein Objekt der Klasse Noten. noten.add(n); fügt dieses Objekt der Liste hinzu. |
|
|
void addNote(Note n) {
|
|
|
noten.add(n);
|
|
|
}
|
|
|
}
|
|
Klasse Stud ohne Erläuterungen |
|
|
package hochschule;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
List<Note> noten = new ArrayList<>();
|
|
|
|
|
|
void addNote(Note n) {
|
|
|
noten.add(n);
|
|
|
}
|
|
|
}
|
|
18.3 Klasse Note |
|
|
package hochschule;
|
|
|
|
|
|
class Note {
|
|
|
String fach;
|
|
|
int note;
|
|
Objekt der Klasse Stud wird angelegt |
|
|
Stud student;
|
|
Konstruktor mit Parameterübergabe. |
|
|
public Noten(String fach, int note, Stud student) {
|
|
|
this.fach = fach;
|
|
|
this.note = note;
|
|
Damit entsteht die Objetreferenz. |
|
|
this.student = student;
|
|
|
}
|
|
|
}
|
|
18.4 Ergebnis Programmlauf |
|
|
Maier hat folgende Noten:
|
|
|
Mathe: 2
|
|
|
Informatik: 1
|
|
|
GPM: 3
|
|
Dabei bedeutet GPM "Geschäftsprozessmanagement". |
|
18.5 Erläuterungen zum Programm |
|
ForEach-Schleife |
|
Im Programm oben finden sich folgende Zeilen: |
|
|
for (Noten n : s1.noten) {
|
|
|
System.out.println(n.fach + ": " + n.note);
|
|
|
}
|
|
Dies ist eine sogenannte forEach-Schleife. Sie wird benutzt, um nacheinander alle Elemente einer Liste zu durchlaufen. In diesem Projekt bedeutet das: Alle Noten des Studierenden s1 werden ausgegeben. Der Schleifenrumpf: |
|
|
System.out.println(n.fach + ": " + n.note);
|
|
gibt jeweils Fach und Note aus. |
|
Interface |
|
Die Zeile ... |
|
|
List<Note> noten = new ArrayList<>();
|
|
... bedeutet: List<Note> legt den Typ fest. List ist ein Interface aus dem Paket java.util. <Note> bedeutet, die Liste darf nur Objekte vom Typ Note enthalten. |
|
Objektreferenzen |
|
Die Zeile |
|
|
Stud student;
|
|
in der Klasse Note legt eine Referenz auf ein Objekt der Klasse Stud an. Beim Konstruktoraufruf |
|
|
Note n1 = new Note("Mathe", 2, s1);
|
|
wird die Referenz auf den Studierenden s1 an die Note übergeben. Innerhalb des Konstruktors wird sie gespeichert: |
|
|
this.student = student;
|
|
Dadurch bleibt die Verbindung zwischen Studierendem und Note dauerhaft erhalten. |
|
18.6 Betrachtete Themen |
|
- 1:n-Beziehung
- ArrayList<>
- Assoziationen zwischen Klassen
- bidirektionale Beziehung
- ForEach-Schleife
- Generics (<Note>)
- Hinzufügen von Objekten mit add()
- Implementierung ArrayList
- Interface List
- Iteration über Listen
- Java Collections Framework
- Klassenverknüpfungen
- Konstruktor mit Objektreferenz
- List<>
- Listen von Objekten
- Objektorientierte Modellierung von Beziehungen
- Objektreferenzen
- Referenzattribute
- Studierende und Noten
|
|
|
|
19 Projekt hsdaten - Dateien |
|
Umgesetzt mit Eclipse 2026-06. Package immer: hsdaten. |
|
Das folgende Projekt beschreibt den Umgang mit Textdateien. Damit können in einfacher Form Daten gespeichert und bearbeitet werden, nicht wie in Datenbanksystemen, aber immerhin. Sinnvoll wäre ein in Java integriertes objektorientiertes Datenbanksystem. Das liegt aber nicht vor. |
|
Stattdessen bietet Java APIs (Application Programming Interfaces) für zahlreiche unterschiedliche Datenbanksysteme an. Unter anderem für relationale Datenbanksysteme (RDBS) und ihre Datenbanken. Dies ist sinnvoll, da RDBS sehr weit verbreitet sind. Die dafür zur Verfügung gestellten Schnittstellen werden JDBC (Java Database Connectivity) genannt. Vgl. [Ullenboom 2024, Kapitel 21]. |
|
In einer der nächsten Auflagen wird auch das hier vorgestellt, weil (natürlich) viele UML-Elemente auf Datenbestände ausgerichtet sind. |
|
Wobei dies keine wirklich zufriedenstellende Lösung ist. Relationale Datenbanken und objektorientierte sind zwei verschiedene Ansätze zur Lösung der Persistenzfrage, weshalb ihr Zusammenwirken umfangreiche technische und inhaltliche Abstimmungen verlangt. Das wird auch als Object-Relational Impedance Mismatch bezeichnet. |
Mismatch |
In diesem Projekt wird beschrieben, wie eine Textdatei eingerichtet, beschrieben und gelesen wird. Für die Arbeit mit Dateien werden Klassen aus dem Paket java.io benötigt. Eine zentrale Rolle spielt dabei die Klasse java.io.File. |
|
Slash und Backslash bei Verzeichnissen in Java |
|
Beim Arbeiten mit Dateien muss man Java sagen, wo eine Datei gespeichert oder gelesen werden soll. Dazu verwendet man einen Pfad. Beispiel: |
|
|
C:\Meine Dateien\Stud004.txt
|
|
Dieser Pfad besteht aus: |
|
- Laufwerk: C:
- Ordner: Meine Dateien
- Datei: Stud004.txt
|
|
Windows verwendet traditionell den umgekehrten Schrägstrich (Backslash) in Pfaden. Deshalb die Angabe oben. In Java hat allerdings der Backslash eine Sonderbedeutung. Er leitet sogenannte Escape-Sequenzen ein. Zum Beispiel \n für neue Zeile. Darum interpretiert Java einen einzelnen Backslash nicht einfach als gewöhnliches Zeichen, weshalb man schreibt: |
|
|
C:\\Meine Dateien\\Stud004.txt
|
|
Denn: Das Zeichenpaar \\ steht in Java für einen einzelnen Backslash im resultierenden Textaus. |
|
Java akzeptiert allerdings auch normale Schrägstriche. Das funktioniert unter Windows in der Regel problemlos: |
|
|
C:/Meine Dateien/Stud004.txt
|
|
Dieser Pfad, "C:/Meine Dateien/...", wird auch in den folgenden Programmen genutzt. |
|
|
|
19.1 Klasse Erstellen |
|
19.1.1 Das Programm |
|
Hier wird mit Hilfe der Klasse java.io.File zunächst ein Dateiobjekt erzeugt. Dazu wird, wie das folgende Beispiel zeigt, im Konstruktor der Pfad, der Dateiname und evtl. weitere Informationen angegeben. |
|
Die eigentliche Datei wird anschließend durch die Methode createNewFile() angelegt. Sie richtet die Datei im gewählten Verzeichnis ein. Gibt es sie schon, ist der Ausdruck false und es wird angegeben, dass die Datei bereits existiert: |
|
- Datei noch nicht da, datei.createNewFile() ist erfolgreich und im Ausdruck wahr.
- Datei schon da, der Ausdruck hat den Wert false.
Klasse Erstellen mit Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
Klasse File der Klassenbibliothek in das Programm einbinden. |
|
|
import java.io.File;
|
|
|
|
|
|
public class Erstellen {
|
|
|
public static void main(String[] args) {
|
|
Try/Catch-Konstrukt. Vgl. Abschnitt 5.2. |
|
|
try {
|
|
String-Variable einrichten und bespielen. |
|
|
String fileName = "Stud006";
|
|
Konstruktor der Klasse File. Mit ihm wird ein Objekt erzeugt, das auf die angegebene Datei im angegebenen Verzeichnis verweist.Mit diesen Parametern wird das Verzeichnis und der Name der Datei angegeben. Das "Objekt" datei hat verschiedene Instanzmethoden. |
|
|
File datei = new File("C:/Meine Dateien/" + fileName + ".txt");
|
|
createNewFile ist eine Instanzmethode von File. Ist der Ausdruck wahr, kannn Erfolg gemeldet werden. |
|
|
if(datei.createNewFile())
|
|
|
System.out.println("Die Datei wurde erstellt");
|
|
|
else
|
|
|
System.out.println("Die Datei existiert bereits");
|
|
|
}
|
|
|
catch (Exception e) {
|
|
|
System.err.println(e);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Erstellen ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
public class Erstellen {
|
|
|
public static void main(String[] args) {
|
|
|
try {
|
|
|
String fileName = "Stud006";
|
|
|
File datei = new File("C:/Meine Dateien/" + fileName + ".txt");
|
|
|
if(datei.createNewFile())
|
|
|
System.out.println("Die Datei wurde erstellt");
|
|
|
else
|
|
|
System.out.println("Die Datei existiert bereits");
|
|
|
}
|
|
|
catch (Exception e) {
|
|
|
System.err.println(e);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
19.1.2 Anmerkung |
|
Objekt datei |
|
Die Variable |
|
|
File datei
|
|
enthält eine Referenz auf ein Objekt der Klasse File. Dieses Objekt repräsentiert die Datei |
|
|
C:/Meine Dateien/Stud006.txt
|
|
und stellt Methoden bereit, mit denen auf die Datei zugegriffen werden kann. Hier wird insbesondere die Instanzmethode |
|
|
createNewFile()
|
|
verwendet. |
|
19.1.3 Betrachtete Themen |
|
- Arbeiten mit dem Dateisystem
- boolesche Rückgabewerte (true / false)
- Dateinamen zusammensetzen
- Dateipfade
- Dateiverwaltung in Java
- Exception-Behandlung
- Fehlerausgabe mit System.err.println()
- if/else-Anweisung
- Import von Bibliotheksklassen
- Instanziierung von Objekten
- Instanzmethoden
- Klasse File
- Konsolenausgabe mit System.out.println()
- Konstruktoraufruf
- Methode createNewFile()
- Paket java.io
- String-Variablen
- Try/Catch-Konstrukt
|
|
|
19.2 Klasse Schreiben |
|
19.2.1 Das Programm |
|
Vgl. zu den Klassen für das Lesen und Schreiben aus bzw. in Dateien Kapitel 6, Abschnitt 6.2. In dieser Klasse wird mit der Klasse FileWriter ohne Puffern gearbeitet. Außerdem wird die Datei in einem spezifischen Verzeichnis angelegt, nicht im Standardverzeichnis (vgl. Schreiben2.java). |
|
Klasse Schreiben mit Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
Klassen aus dem java.io-Paket. FileWriter: Datenstromklasse zum Schreiben von Zeichen in Textdateien. Java.io.IOException: Diese Klasse hilft, Fehlermeldungen ("exceptions") zu organisieren. |
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
|
|
|
public class Schreiben {
|
|
|
public static void main(String[] args) {
|
|
Die Variable stud1 verweist auf ein Objekt der Klasse FileWriter, über das später Schreibzugriffe auf die Datei erfolgen. |
|
|
FileWriter stud1 = null;
|
|
Beginn des Try/Catch-Abschnitts. Vgl. Abschnitt 5.2. Es gibt dazu auch eine modernere Version: try (FileWriter stud1 = new FileWriter("C:/Meine Dateien/" + dateiBez + ".txt")) { stud1.write(text);} Mit ihr erfolgt das Schließen automatisch. Die hier gewählte Version zeigt aber den Ablauf transparenter. |
|
|
try {
|
|
In einer Stringvariablen wird der Dateiname festgehalten. |
|
|
String dateiBez = "stud003";
|
|
Konstruktor der Klasse FileWriter. Er erzeugt ein Objekt der Klasse FileWriter und stellt die Verbindung zur angegebenen Datei her. Existiert die Datei noch nicht, wird sie automatisch angelegt. |
|
|
stud1 = new FileWriter("C:/Meine Dateien/" + dateiBez + ".txt");
|
|
Text bereitstellen für das Eintragen in die Datei. Mehrere Zeichenketten können mit dem Operator + zu einem längeren String zusammengesetzt werden. \n ist eine Escape-Sequenz und erzeugt einen Zeilenumbruch. |
|
|
String text = "Sinnspruch Nummer 3\n"
|
|
|
+ "Der Weg ist weit, der Weg ist lang,"
|
|
|
+ " doch uns wird - wie immer - nicht bang.";
|
|
Schreiben des Textes über den FileWriter in die Datei stud1. |
|
|
stud1.write(text);
|
|
Schließen der Datei. Durch close() werden noch eventuell ausstehende Schreibvorgänge abgeschlossen und die Verbindung zur Datei ordnungsgemäß beendet. |
|
|
stud1.close();
|
|
|
}
|
|
Für den Fall, dass der Try-Abschnitt scheitert, wird eine Fehlermeldung ausgegeben. IOException ist eine spezielle Exception-Klasse für Ein-/Ausgabeoperationen wie Datei- und Verzeichniszugriffe. |
|
|
catch (IOException fehler) { System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Schreiben ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
|
|
|
public class Schreiben {
|
|
|
public static void main(String[] args) {
|
|
|
FileWriter stud1 = null;
|
|
|
try {
|
|
|
String dateiBez = "stud003";
|
|
|
stud1 = new FileWriter("C:/Meine Dateien/" + dateiBez + ".txt");
|
|
|
String text = "Sinnspruch Nummer 3\n"
|
|
|
+ "Der Weg ist weit, der Weg ist lang,"
|
|
|
+ " doch uns wird - wie immer - nicht bang.";
|
|
|
stud1.write(text);
|
|
|
stud1.close();
|
|
|
}
|
|
|
catch (IOException fehler) { System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
19.2.2 Anmerkung |
|
Datenstrom |
|
Die Klasse FileWriter gehört zu den sogenannten Datenstromklassen (Streams). Sie stellt einen Ausgabestrom bereit, über den Zeichen in eine Datei geschrieben werden können. Das Programm arbeitet dabei in folgenden Schritten: |
|
- Dateinamen festlegen
- FileWriter-Objekt erzeugen
- Text bereitstellen
- Text in die Datei schreiben
- Datei schließen
|
|
19.2.3 Betrachtete Themen |
|
- Arbeiten mit Textdateien
- Arbeiten mit Verzeichnissen
- Ausgabestrom
- Dateierzeugung durch FileWriter
- Dateipfade
- Datenströme (Streams)
- Escape-Sequenzen
- Exception-Behandlung
- Fehlerausgabe
- Klasse FileWriter
- Klasse IOException
- Konstruktoraufruf
- Methode close()
- Methode write()
- Paket java.io
- Referenzvariablen
- Ressourcenverwaltung
- Schreiben in Dateien
- String-Variablen
- Try/Catch-Konstrukt
- Zeichenkettenverkettung mit +
- Zeilenumbruch mit \n
|
|
19.3 Klasse Schreiben2 |
|
19.3.1 Das Programm |
|
Hier wird die Klasse BufferedWriter verwendet, die einen gepufferten Datenstrom bereitstellt. Das Programm als Ganzes erzeugt eine neue Datei. Entweder in einem festgelegen Verzeichnis, so wie hier im Folgenden, oder im Standardverzeichnis c:/eclipse/hsdaten und trägt in diese gepuffert Daten ein. Vgl. hierzu Abschnitt 6.2. |
|
Gepuffertes Schreiben ist für umfangreiche Datenströme oder Datenströme, die in einer Schleife abgearbeitet werden, notwendig. Hier dient es Demonstrationszwecken. |
|
Klasse Schreiben2 mit Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.*;
|
|
|
|
|
|
public class Schreiben2 {
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
|
Konstruktor der Klasse FileWriter. Das Objekt fiwr stellt das Programmfragment für den Schreibzugriff auf die angebene Datei bereit. |
|
|
FileWriter fiwr = new FileWriter("C:/Meine Dateien/Stud004.txt");
|
|
Konstruktor der Klasse BufferedWriter. Das Objekt buwr stellt einen gepufferten Ausgabestrom bereit, der die Schreibvorgänge zunächst in einem Speicherpuffer sammelt und anschließend gesammelt an die Datei weitergibt. Die beiden Konstruktoraufrufe können auch verschachtelt geschrieben werden. Vgl. zu den E/A-Strömen Abschnitt 6.2. |
|
|
BufferedWriter buwr = new BufferedWriter(fiwr);
|
|
Schreiben in die Datei mit der Methode write(). Anfordern einer Leerzeile. Java-Programme sollen ja auf verschiedenen Betriebssystemen (Windows, Linux, usw.) einsetzbar sein ("Plattformunabhängigkeit"). Deshalb hier die Methode newLine() für das Anfordern einer neuen Zeile. Bleibt man unter Windows mit seinem Programm, wäre dafür auch die Zeichenfolge \n in der vorausgehenden Textausgabe möglich. Beides wird hier in den Beispielen demonstriert. |
|
|
buwr.write("Name=Staudacher");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Vorname=Guiseppe");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Ort=Ravensburg");
|
|
|
buwr.newLine();
|
|
Beim Schließen werden eventuell noch im Puffer befindliche Daten automatisch in die Datei geschrieben: |
|
|
buwr.close();
|
|
|
}
|
|
|
}
|
|
Zu obigem: Die Methode write() schreibt die Daten zunächst in den Puffer des BufferedWriter. Erst wenn der Puffer gefüllt wird oder die Datei geschlossen wird, gelangen die Daten tatsächlich in die Datei. |
|
Klasse Schreiben2 ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.*;
|
|
|
|
|
|
public class Schreiben2 {
|
|
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
FileWriter fiwr = new FileWriter("C:/Meine Dateien/Stud004.txt");
|
|
|
BufferedWriter buwr = new BufferedWriter(fiwr);
|
|
|
|
|
|
buwr.write("Name=Müller");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Vorname=Inge");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Ort=Ravensburg");
|
|
|
buwr.newLine();
|
|
|
buwr.close();
|
|
|
}
|
|
|
}
|
|
19.3.2 Anmerkung |
|
Gepuffertes Schreiben |
|
Beim gepufferten Schreiben werden die Daten zunächst im Arbeitsspeicher gesammelt. Dadurch müssen nicht für jede einzelne Ausgabe Schreibzugriffe auf das Dateisystem erfolgen. |
|
Vorteile: |
|
- höhere Geschwindigkeit
- weniger Zugriffe auf den Datenträger
- besonders geeignet für große Datenmengen
- sinnvoll bei Schleifen mit vielen Ausgaben
|
|
Im vorliegenden Beispiel ist die Datenmenge klein. Das Programm dient nur dazu, die Arbeitsweise eines BufferedWriter kennenzulernen. |
|
19.3.3 Betrachtete Themen |
|
- Arbeiten mit dem Dateisystem
- Arbeiten mit Textdateien
- Ausgabeströme
- Dateipfade
- Datenströme (Streams)
- gepufferte Ein-/Ausgabe
- IOException
- Klasse BufferedWriter
- Klasse FileWriter
- Konstruktoraufrufe
- Methode close()
- Methode newLine()
- Methode write()
- Paket java.io
- plattformunabhängige Zeilenumbrüche
- Pufferkonzept
- Referenzvariablen
- Ressourcenverwaltung
- Schreiben in Dateien
- throws-Klausel
- verschachtelte Konstruktoren
|
|
19.4 Klasse Lesen |
|
19.4.1 Das Programm |
|
Hier spielen die Klassen FileReaderund BufferedReadereine zentrale Rolle. Ein Objekt von FileReader (also eine Art Schnittstelle zur Datei) ist der Parameter von BufferedReader. |
|
Klasse Lesen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
import java.io.FileReader;
|
|
|
import java.io.IOException;
|
|
|
|
|
|
public class Lesen {
|
|
|
public static void main(String[] args) {
|
|
|
String dateiBez = "stud003";
|
|
|
String pfad =
|
|
|
"C:/Meine Dateien/" + dateiBez + ".txt";
|
|
|
System.out.println("\nDateiname: "+ dateiBeyz + "\n");
|
|
|
try {
|
|
|
FileReader fr =new FileReader(pfad);
|
|
|
BufferedReader stud1 = new BufferedReader(fr);
|
|
|
|
|
|
String text;
|
|
|
|
|
|
while ((text = stud1.readLine()) != null) {
|
|
|
System.out.println(text);
|
|
|
}
|
|
|
stud1.close();
|
|
|
} catch (IOException fehler) {
|
|
|
System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
19.4.2 Anmerkung |
|
Für den zeilenweisen Zugriff auf eine Textdatei werden hier zwei Klassen verwendet: |
|
- FileReader
- BufferedReader
|
|
Ein FileReader stellt den grundlegenden Zugriff auf eine Textdatei her. Er erhält im Konstruktor den Dateinamen, gegebenenfalls zusammen mit der Pfadangabe. Ein BufferedReader legt sich gewissermaßen über den FileReader und ermöglicht ein komfortables zeilenweises Lesen mit der Methode readLine(). |
|
Die beiden Objekte können getrennt erzeugt werden: |
|
|
FileReader fr =
|
|
|
new FileReader("C:/Meine Dateien/stud003.txt");
|
|
|
BufferedReader br = new BufferedReader(fr);
|
|
oder verschachtelt: |
|
|
BufferedReader br = new BufferedReader(
|
|
|
new FileReader("C:/Meine Dateien/stud003.txt"));
|
|
Die verschachtelte Schreibweise wird häufig verwendet. |
|
19.4.3 Betrachtete Themen |
|
- Ausnahmebehandlung
- Automatisches Schließen von Ressourcen
- Dateipfade
- Dateiverarbeitung
- FileNotFoundException
- IOException
- Klasse BufferedReader
- Klasse FileReader
- Konsolenausgabe
- Lesen von Textdateien
- Methode readLine()
- Prüfung auf Dateiende mit null
- Schleifen
- try/catch
- try-with-resources
- Verschachtelte Konstruktoraufrufe
- while-Schleife
- Zeichenkettenverkettung für Dateinamen
- Zeilenweises Lesen
|
|
19.5 Klasse Anhaengen |
|
19.5.1 Das Programm |
|
Das Programm dieser Klasse leistet folgendes: |
|
- Es fragt den Namen einer vorhandenen Textdatei ab.
- Es liest eine neue Textzeile von der Konsole ein.
- Es hängt diese Textzeile an die angegebene Datei an.
- Es verwendet dazu Scanner, File, FileWriter und Formatter.
|
|
Die Klasse Formatter dient hier dazu, die Eingaben in eine Textdatei zu formatieren. Der Konstruktor ist: |
|
|
Formatter formatter = new Formatter(writer))
|
|
Er benötigt ein Objekt der Klasse FileWriter als Parameter. Die Methode format erlaubt dann die Spezifizierung: |
|
|
formatter.format("%s%n", newInput);
|
|
Die Kürzel: |
|
- %s bedeutet unformatierte Ausgabe eines Strings.
- %n bedeutet Anforderung einer neuen Zeile, plattformunabhängig
|
|
[Ullenboom 2024, S. 668] empfiehlt wegen der großen Zahl an Formatspezifizierern diesbezüglich den Blick in die API-Dokumentation. |
|
Klasse Anhaengen mit Erläuterungen |
|
|
package hsdaten;
|
|
|
import java.io.File;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
import java.util.Formatter;
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class Anhaengen {
|
|
|
public static void main(String args[]) {
|
|
Ein Objekt der Klasse Scanner wird erzeugt. D.h., es wird die Funktionalität bereitgestellt, mit der Eingaben von der Konsole gelesen werden können. Der Parameter System.in gibt an, dass die Eingabe von der Konsole kommt. |
|
|
Scanner scanner = new Scanner(System.in);
|
|
Zuerst wird auf der Konsole die angegebene Frage formuliert. Dann wird mit der Methode scanner.next() ein Eingabefeld auf der Konsole eingerichtet und für die Aufnahme der Eingabe eine String-Variable fileName angelegt. Anschließend wird mit der Methode scanner.next() die Konsoleneingabe (der Dateiname) gelesen und in die String-Variable fileName gespielt. Mit scanner.nextLine() wird dann die textliche Eingabe gelesen. |
|
|
System.out.println("Welche Datei (ohne .txt)?");
|
|
|
String fileName = scanner.next(); //stud02.txt
|
|
|
scanner.nextLine();
|
|
Konstruktor der Klasse File. Dieses Programmfragment (Objekt) stellt den Zugriff auf die angegebene Datei im jeweiligen Verzeichnis bereit. Es erhält die Bezeichnung myFile. |
|
|
File datei = new File("C:/Meine Dateien/" + fileName + ".txt");
|
|
|
|
|
|
try(
|
|
Konstruktor der (Strom-)Klasse FileWriter. Das Objekt writer stellt eine Schnittstelle zu der als Parameter angegebenen Datei her. |
|
|
FileWriter writer = new FileWriter(datei, true);
|
|
Konstruktor der Klasse Formatter. Dieses Objekt stellt die Formatierungsmöglichkeiten für die Ausgabe von Texten bereit. Vgl. die nachfolgende Methode format() dieser Klasse. |
|
|
Formatter formatter = new Formatter(writer)) {
|
|
Zeilenweises Lesen der Eingabe (das ist der Text, der in der Datei an den vorhandenen Text angefügt wird). Zu den Formatcodes: %s bedeutet "Zeichenkette". %n bedeutet "neue Zeile" |
|
|
System.out.println("Eingabe: ");
|
|
|
String newInput = scanner.nextLine();
|
|
|
|
|
|
formatter.format("%s%n", newInput);
|
|
|
}
|
|
|
catch (IOException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
Schlusssequenz. Schließen der durch die Klasse Scanner angelegten Programmfragmente. Ausgabe der Erfolgsmeldung. |
|
|
scanner.close();
|
|
|
System.out.println("\nEs hat geklappt!");
|
|
|
}
|
|
|
}
|
|
Klasse Anhaengen ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
import java.util.Formatter;
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class Anhaengen {
|
|
|
public static void main(String args[]) {
|
|
|
Scanner scanner = new Scanner(System.in); //Konstruktor
|
|
|
System.out.println("Welche Datei (ohne .txt)?");
|
|
|
String fileName = scanner.next(); //stud02.txt
|
|
|
scanner.nextLine();
|
|
|
File datei = new File("C:/Meine Dateien/" + fileName + ".txt");
|
|
|
try(
|
|
|
FileWriter writer = new FileWriter(datei, true);
|
|
|
Formatter formatter = new Formatter(writer)) {
|
|
|
System.out.println("Eingabe: ");
|
|
|
String newInput = scanner.nextLine();
|
|
|
formatter.format("%s%n", newInput);
|
|
|
}
|
|
|
catch (IOException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
scanner.close();
|
|
|
System.out.println("\nEs hat geklappt!");
|
|
|
}
|
|
|
}
|
|
Ergebnis Programmlauf |
|
|
Welche Datei (ohne .txt)?
|
|
|
stud02
|
|
|
Eingabe:
|
|
|
Angehängter Text
|
|
|
|
|
|
Es hat geklappt!
|
|
Hier noch ein Blick auf die Datei: |
|

|
|
19.5.2 Anmerkung |
|
Der zweite Parameter bei FileWriter ist hier entscheidend: |
|
|
new FileWriter(datei, true)
|
|
Das true bedeutet: Der neue Text wird an die vorhandene Datei angehängt. Ohne true würde der vorhandene Dateiinhalt überschrieben. Also: |
|
|
new FileWriter(datei)
|
|
öffnet die Datei zum Überschreiben. |
|
|
new FileWriter(datei, true)
|
|
öffnet die Datei zum Anhängen. Zur Methode scanner.nextLine(). Nach |
|
|
String fileName = scanner.next();
|
|
steht der Zeilenumbruch noch im Eingabepuffer. Deshalb folgt: |
|
|
scanner.nextLine();
|
|
Diese Anweisung liest den restlichen Zeilenumbruch weg. Erst danach kann die eigentliche Texteingabe korrekt gelesen werden: |
|
|
String newInput = scanner.nextLine();
|
|
Ohne diese Zwischenzeile könnte newInput versehentlich leer bleiben. |
|
19.5.3 Theorieaspekte |
|
Diese Klasse zeigt, wie vorhandene Textdateien erweitert werden können. Besonders wichtig ist der Konstruktoraufruf: |
|
|
new FileWriter(datei, true)
|
|
Er macht aus dem normalen Schreiben ein Anhängen. Dies zeigt den Unterschied zwischen: |
|
- Datei neu schreiben bzw. überschreiben,
- Datei erweitern bzw. anhängen.
|
|
Außerdem zeigt das Beispiel das Zusammenspiel mehrerer Klassen: |
|
- Scanner -> liest Eingaben von der Konsole
- File -> beschreibt die Datei
- FileWriter -> öffnet die Datei zum Schreiben
- Formatter -> formatiert die Ausgabe
|
|
Damit verbindet die Aufgabe Konsoleneingabe, Dateiverarbeitung und formatierte Textausgabe. |
|
19.5.4 Betrachtete Themen |
|
- Anhängen an Textdateien
- Ausnahmebehandlung
- Dateipfade
- Dateiverarbeitung
- Eingabepuffer bei Scanner
- Formatierte Ausgabe
- Formatspezifizierer %s
- IOException
- Klasse File
- Klasse FileWriter
- Klasse Formatter
- Klasse Scanner
- Konsoleneingabe
- Konstruktoren
- Objektverkettung
- Schließen von Ressourcen
- Schreiben in Textdateien
- try-with-resources
- Unterschied zwischen Überschreiben und Anhängen
- Zeichenkettenverkettung
- Zeilenumbruch mit %n
|
|
|
|
19.6 Klasse Loeschen |
|
19.6.1 Das Programm |
|
Dieses Programm löscht eine Textdatei. Die Bezeichnung der zu löschenden Datei wird über die Tastatur eingegeben. Anschließend wird ein Objekt der Klasse File erzeugt, das die angegebene Datei repräsentiert. Mit der Methode |
|
|
delete()
|
|
wird versucht, die Datei zu löschen. Im Beispiel wird im Verzeichnis |
|
|
C:/Meine Dateien/
|
|
gearbeitet. Ohne Pfadangabe würde sich die Datei im aktuellen Arbeitsverzeichnis befinden. Bei einer Standardinstallation von Eclipse ist dies häufig das Projektverzeichnis |
|
|
c:/eclipse/hsdaten.
|
|
Klasse Loeschen mit Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.*;
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class Loeschen {
|
|
|
public static void main(String[] args) {
|
|
|
Scanner scanner = new Scanner(System.in);
|
|
|
|
|
Die Bezeichnung der zu löschenden Datei wird von der Konsole eingelesen. Hier wird die Datei stud02.txt gewählt. |
|
|
System.out.println("Welche Datei soll gelöscht werden (mit .txt)?");
|
|
|
String fileName = scanner.next(); //stud02.txt
|
|
|
scanner.nextLine();
|
|
Ein Objekt der Klasse File wird mit der Dateibezeichnung erzeugt. Dies repräsentiert dann die Datei in ihrem Verzeichnis und stellt Methoden zu deren Bearbeitung bereit. |
|
|
File file = new File("C:/Meine Dateien/" + fileName);
|
|
Die Methode file.delete() wird aufgerufen. Ist sie erfolgreich, kommt es zur Erfolgsmeldung, andernfalls zur Misserfolgsmeldung. |
|
|
if(file.delete())
|
|
|
{
|
|
|
System.out.println("Die Datei wurde gelöscht.");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
System.out.println("Die Datei konnte nicht gelöscht werden.");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
Klasse Loeschen ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.*;
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class Loeschen {
|
|
|
public static void main(String[] args) {
|
|
|
Scanner scanner = new Scanner(System.in);
|
|
|
System.out.println("Welche Datei soll gelöscht werden (mit .txt)?");
|
|
|
String fileName = scanner.next(); //stud02.txt
|
|
|
scanner.nextLine();
|
|
|
File file = new File("C:/Meine Dateien/" + fileName);
|
|
|
if(file.delete())
|
|
|
{
|
|
|
System.out.println("Die Datei wurde gelöscht.");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
System.out.println("Die Datei konnte nicht gelöscht werden.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
19.6.2 Ergebnis Programmlauf |
|
|
Welche Datei soll gelöscht werden (mit .txt)?
|
|
|
|
|
|
stud02.txt
|
|
|
|
|
|
Die Datei wurde gelöscht.
|
|
|
|
|
oder |
|
|
|
|
|
Welche Datei soll gelöscht werden (mit .txt)?
|
|
|
|
|
|
stud02.txt
|
|
|
|
|
|
Die Datei konnte nicht gelöscht werden.
|
|
19.6.3 Erläuterungen |
|
Zunächst wird ein Objekt der Klasse Scanner erzeugt: |
|
|
Scanner scanner = new Scanner(System.in);
|
|
Damit können Eingaben von der Tastatur gelesen werden. Nach der Eingabe des Dateinamens wird ein Objekt der Klasse File erzeugt: |
|
|
File file = new File("C:/Meine Dateien/" + fileName);
|
|
Dieses Objekt stellt die gewünschte Datei innerhalb des angegebenen Verzeichnisses dar. Die Datei wird anschließend mit |
|
|
file.delete();
|
|
gelöscht. Die Methode besitzt den Rückgabewert |
|
|
boolean
|
|
und liefert |
|
- true, wenn das Löschen erfolgreich war,
- false, wenn die Datei nicht gelöscht werden konnte.
|
|
Deshalb kann unmittelbar geschrieben werden: |
|
|
if (file.delete()) {
|
|
|
...
|
|
|
}
|
|
Warum kann delete() fehlschlagen? |
|
Die Methode liefert false, wenn beispielsweise |
|
- die Datei nicht existiert,
- die Datei geöffnet ist,
- keine ausreichenden Zugriffsrechte vorhanden sind,
- der Dateiname falsch eingegeben wurde.
|
|
Das Programm kann dadurch ohne Ausnahmebehandlung erkennen, ob das Löschen erfolgreich war. |
|
Theorieaspekte |
|
Diese Klasse zeigt erstmals eine Änderung am Dateisystem. Während die vorherigen Programme |
|
- Dateien erzeugten,
- in Dateien schrieben,
- Dateien lasen oder
- Dateien erweiterten,
|
|
wird nun eine Datei vollständig entfernt. Es wird gezeigt, dass viele Methoden einen Wahrheitswert (boolean) zurückgeben, der unmittelbar für Entscheidungen verwendet werden kann: |
|
|
if (file.delete()) {
|
|
|
...
|
|
|
}
|
|
Außerdem wird deutlich, dass ein Objekt der Klasse File nicht den Inhalt einer Datei enthält, sondern eine Datei bzw. einen Pfad im Dateisystem repräsentiert. Diese Klasse stellt anschließend Methoden zur Verfügung, mit denen auf die Datei zugegriffen oder sie verändert werden kann. Dies ist ein wichtiges Grundprinzip der objektorientierten Dateiverarbeitung in Java. |
Objektorientierte Daten-
verarbeitung |
19.6.4 Betrachtete Themen |
|
- Bedingte Anweisungen (if)
- Dateipfade
- Dateisystemzugriffe
- Dateiverarbeitung
- Erfolgskontrolle von Methoden
- Klasse File
- Klasse Scanner
- Konsoleneingabe
- Konstruktoren
- Löschen von Dateien
- Methode delete()
- Objekt der Klasse File
- Ressourcen schließen (scanner.close())
- Rückgabewert boolean
- Zeichenketten als Dateinamen
|
|
19.7 Klasse ErzeugLoesch |
|
Das Programm erzeugt zunächst eine Textdatei im Verzeichnis |
|
|
C:/Meine Dateien/
|
|
und schreibt mehrere Zeilen in diese Datei. Anschließend fragt das Programm mit einem JOptionPane-Dialog, ob die Datei wieder gelöscht werden soll. Bei Eingabe von j oder J wird die Datei gelöscht. Bei n oder N bleibt sie erhalten. |
|
Klasse ErzeugLoesch mit Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.BufferedWriter;
|
|
|
import java.io.File;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class ErzeugLoesch {
|
|
|
|
|
Die IOException ist zur Fehlerbehandlung notwendig. |
|
|
public static void main(String[] args) throws IOException {
|
|
Zuerst eine Datei erzeugen |
|
|
String dateibez = "C:/Meine Dateien/stud05.txt";
|
|
Mit dem "Objekt" fiwr der Klasse FileWriter wird die angegebene Datei zum Beschreiben bereitgestellt. Das "Objekt" buwr der Klasse BufferedWriter stellt Methoden für das gepufferte Schreiben bereit. Der Parameter ist hier die Bezeichnung des File Writer-Objekts. Vgl. auch Abschnitt 6.2. |
|
|
FileWriter fiwr = new FileWriter(dateibez);
|
|
|
BufferedWriter buwr = new BufferedWriter(fiwr);
|
|
Mit den Methoden newLine() (Neue Zeile anfordern) und write() (Zeile in die Datei eintragen) wird die Datei beschrieben. |
|
|
buwr.write("Name=Mostkopf");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Vorname=Paul");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Ort=Ravensburg");
|
|
|
buwr.newLine();
|
|
|
buwr.close();
|
|
|
System.out.println("Datei " + dateibez + "
|
|
|
wurde im Standardverzeichnis erzeugt");
|
|
Die Eingabe in die grafische Eingabeaufforderung (siehe unten) führt zu einem String. |
|
|
String eingabe = JOptionPane.showInputDialog
|
|
|
("Datei wieder löschen (j/n)?");
|
|
Da der Umgang mit Strings manchmal schwierig ist und als Beispiel hier das Auslesen des ersten Stringelements in ein Character-Zeichen, mit dem dann die Abfrage, ob j/J oder n/N vorliegt, einfacher ist. |
|
|
char erster = eingabe.charAt(0);
|
|
|
if ((erster == 'j') || (erster == 'J')) {
|
|
|
System.out.println("j wurde erkannt");
|
|
In dateibez steht die Bezeichnung der Datei. Damit wird ein Objekt der Klasse File erzeugt. Dies repräsentiert die Datei in ihrem Verzeichnis. |
|
|
File file = new File(dateibez);
|
|
Dann wird mit dieser Dateibezeichnung die Methode file.delete() zum Löschen der Datei aufgerufen. Ist sie erfolgreich, kommt es zur Erfolgsmeldung, andernfalls zur Misserfolgsmeldung |
|
|
if(file.delete())
|
|
|
{
|
|
|
System.out.println("Die Datei wurde gelöscht.");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
System.out.println("Die Datei konnte nicht gelöscht werden.");
|
|
|
}
|
|
|
}
|
|
|
else if ((erster == 'n' ) || (erster == 'N')) {
|
|
|
System.out.println("Datei wird nicht gelöscht");
|
|
|
}
|
|
|
else System.out.println("Fehlerhafte Eingabe");
|
|
|
}
|
|
|
}
|
|
Klasse ErzeugLoesch ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.BufferedWriter;
|
|
|
import java.io.File;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class ErzeugLoesch {
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
String dateibez = "C:/Meine Dateien/stud05.txt";
|
|
|
FileWriter fiwr = new FileWriter(dateibez);
|
|
|
BufferedWriter buwr = new BufferedWriter(fiwr);
|
|
|
buwr.write("Name=Mostkopf");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Vorname=Paul");
|
|
|
buwr.newLine();
|
|
|
buwr.write("Ort=Ravensburg");
|
|
|
buwr.newLine();
|
|
|
buwr.close();
|
|
|
System.out.println("Datei " + dateibez + " wurde im Standardverzeichnis erzeugt");
|
|
|
String eingabe = JOptionPane.showInputDialog("Datei wieder löschen (j/n)?");
|
|
|
char erster = eingabe.charAt(0);
|
|
|
if ((erster == 'j') || (erster == 'J')) {
|
|
|
System.out.println("j wurde erkannt");
|
|
|
File file = new File(dateibez);
|
|
|
if(file.delete())
|
|
|
{
|
|
|
System.out.println("Die Datei wurde gelöscht.");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
System.out.println("Die Datei konnte nicht gelöscht werden.");
|
|
|
}
|
|
|
}
|
|
|
else if ((erster == 'n' ) || (erster == 'N')) {
|
|
|
System.out.println("Datei wird nicht gelöscht");
|
|
|
}
|
|
|
else System.out.println("Fehlerhafte Eingabe");
|
|
|
}
|
|
|
}
|
|
Eingabefenster: |
|

|
|
19.7.1 Ergebnis Programmlauf |
|
|
Datei C:/Meine Dateien/stud05.txt wurde erzeugt.
|
|
|
j wurde erkannt
|
|
|
Die Datei wurde gelöscht.
|
|
|
|
oder |
|
|
|
|
Datei C:/Meine Dateien/stud05.txt wurde erzeugt.
|
|
|
Datei wird nicht gelöscht.
|
|
19.7.2 Erläuterungen |
|
Zunächst wird der vollständige Dateiname festgelegt: |
|
|
String dateibez = "C:/Meine Dateien/stud05.txt";
|
|
Danach werden ein FileWriter und ein BufferedWriter erzeugt: |
|
|
FileWriter fiwr = new FileWriter(dateibez);
|
|
|
BufferedWriter buwr = new BufferedWriter(fiwr);
|
|
Der FileWriter stellt die Verbindung zur Datei her. Der BufferedWriter ermöglicht komfortables gepuffertes Schreiben. Mit |
|
|
buwr.write("Name=Mostkopf");
|
|
|
buwr.newLine();
|
|
wird eine Zeile geschrieben und anschließend ein Zeilenumbruch eingefügt. Nach dem Schreiben fragt das Programm über ein Eingabefenster: |
|
|
JOptionPane.showInputDialog("Datei wieder löschen (j/n)?");
|
|
Die Eingabe wird als String zurückgegeben. Mit |
|
|
char erster = eingabe.charAt(0);
|
|
wird das erste Zeichen der Eingabe ausgewertet. Dadurch werden auch Eingaben wie |
|
|
ja
|
|
oder |
|
|
Ja
|
|
erkannt, weil nur das erste Zeichen betrachtet wird. |
|
Theorieaspekte |
|
Diese Klasse verbindet mehrere bisher getrennt behandelte Dateioperationen: |
|
- Datei erzeugen
- Datei beschreiben
- Benutzerentscheidung einholen
- Datei optional löschen
|
|
Besonders wichtig ist dabei die Kombination aus Dateiverarbeitung und Benutzereingabe. Es wird gezeigt, dass ein Programm nach dem Schreiben einer Datei eine Entscheidung vom Benutzer einholen und abhängig davon unterschiedliche Aktionen ausführen kann. Außerdem wird der Unterschied zwischen |
|
|
String eingabe
|
|
und |
|
|
char erster
|
|
sichtbar. Der String enthält die gesamte Eingabe, während charAt(0) nur das erste Zeichen auswertet. Dadurch kann das Programm einfache Ja-/Nein-Entscheidungen verarbeiten. |
|
19.7.3 Betrachtete Themen |
|
- Dateiverarbeitung
- Erzeugen von Textdateien
- Schreiben in Textdateien
- Löschen von Dateien
- Klasse File
- Klasse FileWriter
- Klasse BufferedWriter
- Klasse JOptionPane
- Gepuffertes Schreiben
- Methode write()
- Methode newLine()
- Methode delete()
- Grafische Eingabe mit showInputDialog()
- Zeichenketten (String)
- Zeichen (char)
- Methode charAt()
- Bedingte Anweisungen (if, else if, else)
- Logische Operatoren (||)
- Ausnahmebehandlung
- IOException
- try-with-resources
- Automatisches Schließen von Ressourcen
- Prüfung auf null
- Prüfung auf leere Eingabe
- Dateipfade
- Konsolenausgabe
|
|
19.8 Klasse EinlesenCSV |
|
19.8.1 Das Programm |
|
CSV steht für Comma Separated Values. Es handelt sich um ein einfaches Dateiformat zum Austausch tabellarischer Daten. Die einzelnen Werte einer Zeile werden durch ein Trennzeichen voneinander getrennt. |
|
Im deutschsprachigen Raum wird häufig nicht das Komma, sondern das Semikolon (;) als Trennzeichen verwendet. Deshalb verwendet dieses Programm: |
|
|
lesen.useDelimiter(";");
|
|
Für dieses Beispiel wurde eine Excel-Datei mitarbeiter.csv erzeugt und anschließend als CSV UTF-8 (durch Trennzeichen getrennt) gespeichert. Im Editor (z. B. Notepad) besitzt die Datei folgenden Aufbau: |
|
|
nachname;vorname;mitarbeiternummer;abteilung
|
|
|
Tanzer;Toni;1234;KA
|
|
|
Leoprecht;Max;3712;IT
|
|
|
...
|
|
Hinweis |
|
Zum Nachvollziehen sollte sich eine Datei |
|
|
mitarbeiter.csv
|
|
im angegebenen Verzeichnis befinden. Beim Speichern aus Excel sollte das Dateiformat |
|
|
CSV UTF-8 (durch Trennzeichen getrennt)
|
|
gewählt werden. |
|
Klasse EinlesenCSV mit Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.util.Scanner;
|
|
|
import java.io.BufferedReader;
|
|
|
import java.io.FileNotFoundException;
|
|
|
import java.io.FileReader;
|
|
|
import java.io.IOException;
|
|
|
|
|
|
public class EinlesenCSV {
|
|
|
|
|
|
public static void main(String[] args) throws FileNotFoundException {
|
|
|
|
|
Konstruktor der Klasse File. Vgl. Abschnitt 6.3. |
|
|
File CSVDatei = new File("mitarbeiter.csv");
|
|
Konstruktor der Klasse Scanner. Richtet ein "Scanner-Objekt" ein, mit dem von der Konsole gelesen werden kann. Klappt nur, falls Excel-Datei als CSV/UTF-8 gespeichert ist. Er erhält als Parameter die Dateibezeichnung und die Angabe des Zeichencodes (8-Bit UCS Transformation Code). |
|
|
Scanner lesen = new Scanner(CSVDatei, "UTF-8");
|
|
Die Instanzenmethode useDelimiter() wird auf die zum Scannen bereitgestellte Datei angewandt. Hier wird das Trennzeichen zwischen den Einzeleinträgen geklärt. Vgl. die Ausgabe unten. |
|
|
lesen.useDelimiter(";");
|
|
|
|
|
|
System.out.println("\nZum Testen, Ausgabe als CSV-Datei:\n");
|
|
|
while (lesen.hasNext())
|
|
|
{
|
|
|
System.out.print(lesen.next() + " / ");
|
|
|
}
|
|
|
lesen.close();
|
|
|
|
|
|
System.out.println("\n\nEinfache Ausgabe als Testdatei:");
|
|
|
BufferedReader stud1 = null;
|
|
|
String text;
|
|
|
try {
|
|
|
String fileName = "C:/Meine dateien/mitarbeiter.csv";
|
|
|
|
|
Hier liegen wiederum verkapselte "Konstruktor-Objekte" vor. Als Parameter von BufferedReader dient ein FileReader-Objekt.: stud1 = new BufferedReader (new FileReader(fileName )); |
|
|
System.out.println("Dateiname:" + fileName + "\n");
|
|
|
stud1 = new BufferedReader (new FileReader(fileName ));
|
|
|
|
|
|
} catch (FileNotFoundException fehler) {
|
|
|
System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
Noch ein Try/Catch-Konstrukt. Diesmal mit einer Schleife zum Lesen und Ausgeben der Zeilen der Datei und für die evtl. Fehlermeldung. |
|
|
try {
|
|
|
while ((text = stud1.readLine()) != null) {
|
|
|
System.out.println(text);
|
|
|
}
|
|
|
} catch (IOException fehler) {
|
|
|
System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse EinlesenCSV ohne Erläuterungen |
|
|
package hsdaten;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.BufferedReader;
|
|
|
import java.io.FileNotFoundException;
|
|
|
import java.io.FileReader;
|
|
|
import java.io.IOException;
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class EinlesenCSV {
|
|
|
|
|
|
public static void main(String[] args) throws FileNotFoundException {
|
|
|
File CSVDatei = new File("mitarbeiter.csv");
|
|
|
Scanner lesen = new Scanner(CSVDatei, "UTF-8");
|
|
|
lesen.useDelimiter(";");
|
|
|
System.out.println("\nAusgabe als CSV-Datei:\n");
|
|
|
while (lesen.hasNext())
|
|
|
{
|
|
|
System.out.print(lesen.next() + " / ");
|
|
|
}
|
|
|
lesen.close();
|
|
|
|
|
|
System.out.println("\n\nZum Testen, Ausgabe als Textdatei:\n");
|
|
|
BufferedReader stud1 = null;
|
|
|
String text;
|
|
|
try {
|
|
|
String fileName = "C:/Meine dateien/mitarbeiter.csv";
|
|
|
System.out.println("Dateiname: " + fileName + "\n");
|
|
|
stud1 = new BufferedReader(new FileReader(fileName ));
|
|
|
|
|
|
} catch (FileNotFoundException fehler) {
|
|
|
System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
|
try {
|
|
|
while ((text = stud1.readLine()) != null) {
|
|
|
System.out.println(text);
|
|
|
}
|
|
|
} catch (IOException fehler) {
|
|
|
System.out.println("Fehler: " + fehler);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Ausgabe |
|
|
Ausgabe als CSV-Datei:
|
|
|
|
|
|
nachname / vorname / mitarbeiternummer / abteilung
|
|
|
Tanzer / Toni / 1234 / KA
|
|
|
Leoprecht / Max / 3712 / IT
|
|
|
Honig / Fritz / 3713 / ORG
|
|
|
Mälker / Kai / 9876 / PW
|
|
|
Staud / Josef / 1097 / IT /
|
|
|
|
|
|
Zum Testen, einfache Ausgabe als Textdatei:
|
|
|
|
|
|
Dateiname: C:/meine dateien/mitarbeiter.csv
|
|
|
|
|
|
nachname;vorname;mitarbeiternummer;abteilung
|
|
|
Tanzer;Toni;1234;KA
|
|
|
Leoprecht;Max;3712;IT
|
|
|
Honig;Fritz;3713;ORG
|
|
|
Mälker;Kai;9876;PW
|
|
|
Staud;Josef;1097;IT
|
|
19.8.2 Erläuterungen |
|
Zunächst wird ein Objekt der Klasse File erzeugt: |
|
|
File csvDatei = new File("C:/Meine Dateien/mitarbeiter.csv");
|
|
Dieses Objekt repräsentiert die CSV-Datei im Dateisystem. Anschließend wird ein Scanner erzeugt: |
|
|
Scanner lesen = new Scanner(csvDatei, "UTF-8");
|
|
Der Scanner liest nicht von der Tastatur, sondern direkt aus der angegebenen Datei. Mit |
|
|
lesen.useDelimiter(";");
|
|
wird festgelegt, dass das Semikolon als Trennzeichen zwischen zwei Datenfeldern verwendet wird. Dadurch liefert |
|
|
lesen.next();
|
|
jeweils genau einen Eintrag der CSV-Datei. Im zweiten Programmteil wird dieselbe Datei mit einem BufferedReader gelesen: |
|
|
BufferedReader stud1 = new BufferedReader(new FileReader(...));
|
|
Hier erfolgt keine Interpretation der CSV-Struktur. Jede Zeile wird vollständig gelesen und unverändert ausgegeben. Dadurch wird der Unterschied zwischen |
|
- strukturierter Verarbeitung
- und normalem Textlesen
|
|
deutlich. |
|
Theorieaspekte |
|
Diese Klasse zeigt zwei unterschiedliche Sichtweisen auf dieselbe Datei. Im ersten Teil wird die CSV-Datei als strukturierte Datensammlung interpretiert. Das Trennzeichen (;) zerlegt jede Zeile in einzelne Datenfelder. |
|
Im zweiten Teil wird dieselbe Datei als gewöhnliche Textdatei betrachtet. Es werden lediglich die einzelnen Zeilen gelesen und unverändert ausgegeben. Dies verdeutlicht den Unterschied zwischen |
|
- dem Lesen strukturierter Daten und
- dem Lesen beliebiger Textdateien.
|
|
Gleichzeitig wird gezeigt, dass viele Programme (z. B. Excel) Daten im CSV-Format speichern können und dass Java verschiedene Klassen bereitstellt, um solche Dateien je nach Anwendungsfall unterschiedlich zu verarbeiten. |
|
Eine kleine didaktische Empfehlung |
|
Ich würde den Dateinamen in beiden Programmteilen vereinheitlichen: |
|
|
String dateiname = "C:/Meine Dateien/mitarbeiter.csv";
|
|
Dann verwenden beide Leseverfahren dieselbe Variable. Das erleichtert Einsteigern das Verständnis und vermeidet doppelte Pfadangaben. Außerdem würde ich die Verzeichnisbezeichnung konsequent als C:/Meine Dateien/ schreiben (nicht einmal C:/meine dateien/ und einmal C:/Meine Dateien/), um Verwirrung zu vermeiden. |
|
19.8.3 Betrachtete Themen |
|
- Ausnahmebehandlung
- CSV-Dateien
- Dateipfade
- Datenaustauschformate
- IOException
- Klasse BufferedReader
- Klasse File
- Klasse FileReader
- Klasse Scanner
- Konsolenausgabe
- Lesen aus Dateien
- Methode hasNext()
- Methode next()
- Methode readLine()
- Methode useDelimiter()
- Strukturierte Daten
- Textdateien
- Tokenweises Lesen
- Trennzeichen (Delimiter)
- try-with-resources
- Zeichencodierung UTF-8
- Zeilenweises Lesen
|
|
|
|
20 Übungsaufgaben Teil 1 |
|
Die Unterteilung der Übungsaufgaben in "Teile" ist nur darstellungstechnisch bedingt. Es wäre sonst nur schwer möglich, in der Frame-basierten Version die Aufgaben vernünftig anzuordnen. |
|
Hier nun einfache Aufgaben zum Üben der Programmierkompetenz. Durch oftmaliges Lösen solcher Aufgabenstellungen wird die Basiskompetenz erworben. Übrigens können hier auch die modernen KI-Programme hilfreich sein. Nicht nur zum Überprüfen der Lösung, sondern auch zum Stellen von Aufgaben: |
|
Nutzen Sie die KI als Trainer, indem sie sich Aufgaben stellen lassen, zuerst einfacher, dann schwieriger. |
|
|
|
20.1 Aufgabe 1 - Klasse und Objekt |
|
Klasse, Objekt und Attribute |
|
20.1.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Aufgabe01 (Hauptprogramm) und eine Klasse Stud. Letztere erfasst Studierende und erhält folgende Attribute: |
|
- Matrikelnummer (int)
- Name (String)
- Vorname (String)
|
|
Erzeugen Sie im Hauptprogramm ein Objekt der Klasse Stud. Beschreiben Sie die Attribute dieses Objekts mit Beispielwerten und geben Sie die Daten anschließend auf der Konsole aus. |
|
20.1.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine eigene Klasse zu erstellen und daraus ein Objekt zu erzeugen. Sie verstehen, wie Attribute mit Werten belegt und über das Objekt angesprochen werden. Dadurch erwerben Sie die grundlegenden Kenntnisse zum Aufbau und zur Verwendung von Klassen und Objekten in der objektorientierten Programmierung. |
|
|
|
20.1.3 Lösung |
|
Klasse Stud |
|
|
package Studierende;
|
|
|
|
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
void ausgeben() {
|
|
|
System.out.println(mNr + " " + vName + " " + name);
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe01 |
|
|
package Studierende;
|
|
|
|
|
|
public class Aufgabe01 {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s = new Stud();
|
|
|
s.mNr = 123;
|
|
|
s.name = "Maier";
|
|
|
s.vName = "Klara";
|
|
|
s.ausgeben();
|
|
|
}
|
|
|
}
|
|
20.1.4 Ergebnis Programmlauf |
|
|
123 Klara Maier
|
|
20.1.5 Betrachtete Themen |
|
- Attribute
- Instanzattribute
- Instanziierung mit new
- Klassen
- Konsolenausgabe
- Methoden
- Objekte (Instanzen)
- Objektzugriff mit Punktnotation
- Standardkonstruktor
|
|
20.1.6 Erläuterung |
|
Mit |
|
|
Stud s = new Stud();
|
|
wird ein neues Objekt der Klasse Stud erzeugt. Die Variable s enthält eine Referenz auf dieses Objekt. Über die Punktnotation werden anschließend die Attribute beschrieben: |
|
|
s.mNr = 123;
|
|
|
s.name = "Maier";
|
|
|
s.vName = "Klara";
|
|
Der Methodenaufruf |
|
|
s.ausgeben();
|
|
führt die Methode ausgeben() für dieses Objekt aus. |
|
|
|
20.2 Aufgabe 2 - Referenzen |
|
20.2.1 Aufgabenstellung |
|
Wenn obiges Programm um folgende Zeilen ergänzt wird, wie sieht dann das Ergebnis aus? |
|
|
Stud s1 = new Stud();
|
|
|
Stud s2 = s1;
|
|
|
|
|
|
s1.name = "Meier";
|
|
|
System.out.println(s2.name);
|
|
Wie erklärt sich das Ergebnis? |
|
20.2.2 Lernziele |
|
In dieser Aufgabe lernen Sie das Konzept der Objektreferenzen in Java kennen. Sie verstehen, dass Referenzvariablen auf Objekte verweisen und dass mehrere Referenzvariablen auf dasselbe Objekt zeigen können. Dadurch vertiefen Sie Ihr Verständnis für den Umgang mit Objekten und Referenzen in der objektorientierten Programmierung. |
|
|
|
20.2.3 Lösung |
|
Klasse Aufgabe02 |
|
|
package studierende;
|
|
|
|
|
|
public class Aufgabe02 {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s = new Stud();
|
|
|
s.mNr = 123;
|
|
|
s.name = "Maier";
|
|
|
s.vName = "Klara";
|
|
|
|
|
|
s.ausgeben();
|
|
|
|
|
|
Stud s1 = new Stud();
|
|
|
Stud s2 = s1;
|
|
|
s1.name = "Meier";
|
|
|
System.out.println(s2.name);
|
|
|
}
|
|
|
}
|
|
Klasse Stud |
|
|
package studierende;
|
|
|
|
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
void ausgeben() {
|
|
|
System.out.println(mNr + " " + vName + " " + name);
|
|
|
}
|
|
|
}
|
|
Begründung |
|
Die Variablen s1 und s2 enthalten keine Objekte, sondern Referenzen auf Objekte. Durch die Anweisung |
|
|
Stud s2 = s1;
|
|
wird keine Kopie des Objekts erzeugt. Stattdessen zeigen beide Variablen auf dasselbe Objekt im Speicher. Wird das Objekt über s1 verändert, |
|
|
s1.name = "Meier";
|
|
so ist die Änderung auch über s2 sichtbar: |
|
|
System.out.println(s2.name);
|
|
Deshalb wird |
|
|
Meier
|
|
ausgegeben. |
|
20.2.4 Ergebnis Programmlauf |
|
|
123 Klara Maier
|
|
|
Meier
|
|
20.2.5 Betrachtete Themen |
|
- Gemeinsamer Zugriff auf Objekte
- Instanziierung mit new
- Mehrere Referenzen auf dasselbe Objekt
- Objekte
- Objektvariablen
- Punktnotation
- Referenzen
- Referenzvariablen
- Speichermodell von Objekten
- Zuweisung von Referenzen
|
|
20.2.6 Erläuterung |
|
Bei primitiven Datentypen wird bei einer Zuweisung der Wert kopiert: |
|
|
int a = 5;
|
|
|
int b = a;
|
|
Danach besitzen a und b jeweils ihren eigenen Wert. Bei Objekten ist dies anders: |
|
|
Stud s1 = new Stud();
|
|
|
Stud s2 = s1;
|
|
Hier wird nicht das Objekt kopiert, sondern nur die Referenz. Dadurch zeigen beide Variablen auf dasselbe Objekt. |
|
|
|
20.3 Aufgabe 3a - Arrays Einführung |
|
20.3.1 Aufgabenstellung |
|
In einer Arztpraxis sollen die Gewichte mehrerer Patienten verwaltet werden. Erstellen Sie eine Klasse Aufgabe03a mit einer main()-Methode und realisieren Sie folgende Aufgaben: |
|
- Legen Sie ein Array an, das die Gewichte von fünf Patienten speichern kann.
- Tragen Sie folgende Gewichte in das Array ein:
|
|
|
|
| Patient |
Gewicht |
| 1 |
72 |
| 2 |
85 |
| 3 |
64 |
| 4 |
91 |
| 5 |
78 |
| |
|
|
- Ändern Sie anschließend das Gewicht des dritten Patienten auf 66 kg.
- Geben Sie danach alle Gewichte auf dem Bildschirm aus.
- Berechnen Sie zusätzlich das Durchschnittsgewicht aller Patienten und geben Sie dieses aus.
|
|
Die Bildschirmausgabe soll so aussehen: |
|
|
Gewichte der Patienten:
|
|
|
Patient 1: 72 kg
|
|
|
Patient 2: 85 kg
|
|
|
Patient 3: 66 kg
|
|
|
Patient 4: 91 kg
|
|
|
Patient 5: 78 kg
|
|
|
Durchschnittsgewicht: 78.4 kg
|
|
20.3.2 Lernziele |
|
In dieser Aufgabe lernen Sie, Arrays in Java anzulegen und zu verwenden. Sie verstehen, wie Werte in einem Array gespeichert, über ihren Index angesprochen und mit einer Schleife ausgegeben werden. Dadurch erwerben Sie die Grundlagen für die spätere Verwaltung von Objekten in Arrays. |
|
20.3.3 Lösung |
|
|
public class Aufgabe03a {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
Array für fünf Gewichte anlegen |
|
|
int[] gewichte = new int[5];
|
|
|
|
|
Werte eintragen |
|
|
gewichte[0] = 72;
|
|
|
gewichte[1] = 85;
|
|
|
gewichte[2] = 64;
|
|
|
gewichte[3] = 91;
|
|
|
gewichte[4] = 78;
|
|
|
|
|
Gewicht des dritten Patienten ändern |
|
|
gewichte[2] = 66;
|
|
|
|
|
Ausgabe aller Gewichte |
|
|
System.out.println("Gewichte der Patienten:");
|
|
|
|
|
|
for (int i = 0; i < gewichte.length; i++) {
|
|
|
System.out.println(
|
|
|
"Patient " + (i + 1) + ": "
|
|
|
+ gewichte[i] + " kg");
|
|
|
}
|
|
|
|
|
Durchschnitt berechnen |
|
|
int summe = 0;
|
|
|
|
|
|
for (int gewicht : gewichte) {
|
|
|
summe += gewicht;
|
|
|
}
|
|
|
|
|
|
double durchschnitt =
|
|
|
(double) summe / gewichte.length;
|
|
|
|
|
|
System.out.println(
|
|
|
"\nDurchschnittsgewicht: "
|
|
|
+ durchschnitt + " kg");
|
|
|
}
|
|
|
}
|
|
20.3.4 Betrachtete Themen |
|
- Array-Deklaration
- Array-Elemente ändern
- Array-Elemente lesen
- Array-Erzeugung mit new
- Array-Indizes
- Arrays
- Attribut length
- Datentyp int
- Durchschnittsberechnung
- For-Schleife
- Iteration über Datenstrukturen
- Konsolenausgabe
- Primitive Datentypen
- Schleifen
- Summenbildung
- Zählschleife (for)
|
|
20.3.5 Erläuterung |
|
Betrachten wir folgende Anweisung: |
|
|
int[] gewichte = new int[5];
|
|
Sie besteht aus mehreren Teilen. |
|
|
|
|
int ist ein primitiver Datentyp für ganze Zahlen. |
|
|
|
|
|
int[]
|
|
Die eckigen Klammern zeigen an, dass mehrere Werte gleichen Typs gespeichert werden sollen. |
|
Vergleich: |
|
int gewicht; stellt eine einzelne Zahl dar. |
|
int[] gewichte; entspricht mehreren Zahlen. Man spricht von einem Array von Integer-Werten. |
|
|
|
|
|
gewichte
|
|
Dies ist der Name der Variablen. Die Variable enthält später einen Verweis auf das Array. |
|
|
|
|
|
new
|
|
fordert Java auf, ein neues Objekt anzulegen. Auch Arrays sind in Java Objekte. Deshalb muss Speicher reserviert werden. Alle Elemente werden zunächst automatisch mit 0 gefüllt. |
|
|
|
|
|
new int[5]
|
|
Hier wird festgelegt: |
|
- Typ der Elemente: int
- Anzahl der Elemente: 5
|
|
Java reserviert Speicher für fünf Integer-Werte. |
|
|
|
|
|
[5]
|
|
bedeutet: 5 Elemente und nicht "letzter Index = 5". Die Indizes beginnen bei 0. Deshalb sind die gültigen Indizes: 0, 1, 2, 3, 4. |
|
Ein Array besitzt nach seiner Einrichtung immer eine feste Länge, im Unterschied zu Listen, die später betrachtet werden. |
|
Zugriff auf einzelne Elemente |
|
|
gewichte[0] = 72;
|
|
|
gewichte[1] = 85;
|
|
|
gewichte[2] = 64;
|
|
|
gewichte[3] = 91;
|
|
|
gewichte[4] = 78;
|
|
Lesen eines Wertes |
|
|
System.out.println(gewichte[2]);
|
|
führt zur Ausgabe: |
|
|
64
|
|
Der Index 2 bezeichnet das dritte Element. |
|
|
|
Ändern eines Wertes |
|
Mit |
|
|
gewichte[2] = 66;
|
|
wird der bisherige Wert überschrieben. |
|
20.3.6 Hinweis - Arrays von Objekten |
|
Oben wurden Zahlen gespeichert: |
|
|
int[] gewichte = new int[5];
|
|
In objektorientierten Programmen werden häufig Objekte gespeichert: |
|
|
Stud[] studierende = new Stud[5];
|
|
oder |
|
|
Note[] noten = new Note[10];
|
|
Man spricht dann von Objektarrays oder Referenzarrays. Die nächste Aufgabe zeigt, wie Objekte in einem Array gespeichert und verarbeitet werden. |
|
|
|
20.4 Aufgabe 3b - Arrays mit Objekten |
|
20.4.1 Aufgabenstellung |
|
Wir benötigen die Klassen Stud und Aufgabe03b (als HP). |
|
Erzeugen Sie ein Array für drei Objekte der Klasse Stud. Erzeugen Sie anschließend in einer Schleife für jedes Arrayelement ein neues Objekt der Klasse Stud und speichernSie es im Array. |
|
Weisen Sie jedem Objekt einen Namen zu. Der Name soll aus dem Text "Studierende" und einem Zähler bestehen, also beispielsweise: Studierende1, Studierende2, Studierende3. |
|
Geben Sie danach mit einer forEach-Schleife die Namen aller gespeicherten Objekte auf der Konsole aus. Das sollte zu folgendem Ergebnis führen: |
|
|
Studierende1
|
|
|
Studierende2
|
|
|
Studierende3
|
|
20.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie, Objekte in einem Array zu verwalten. Sie verstehen, wie Objektreferenzen in einem Array gespeichert, die einzelnen Objekte in einer Schleife erzeugt und anschließend mit einer forEach-Schleife ausgegeben werden. |
|
|
|
20.4.3 Lösung |
|
Klasse Aufgabe03b |
|
|
package studierende;
|
|
|
public class Aufgabe03 {
|
|
|
public static void main(String[] args) {
|
|
Erzeugung eines Arrays für drei Objekte (Studierende), noch ohne Daten: null |
|
|
Stud[] arr = new Stud[3];
|
|
Schleife von 0 bis 2 |
|
|
for (int i = 0; i < arr.length; i++) {
|
|
Neues Objekt erzeugen und im Array speichern |
|
|
arr[i] = new Stud();
|
|
Zugriff auf das Objekt, Name eintragen |
|
|
arr[i].name = "Name" + (i+1);
|
|
|
}
|
|
ForEach-Schleife über alle Elemente des Arrays. s ist jeweils ein Stud-Objekt |
|
|
for (Stud s : arr) {
|
|
|
System.out.println(s.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Stud |
|
|
package studierende;
|
|
|
|
|
|
class Stud {
|
|
|
String name;
|
|
|
}
|
|
20.4.4 Ergebnis Programmlauf |
|
|
Name1
|
|
|
Name2
|
|
|
Name3
|
|
20.4.5 Betrachtete Themen |
|
- Array-Indizes
- Arrays
- ForEach-Schleife
- For-Schleife
- Instanziierung mit new
- Iteration über Datenstrukturen
- Objektarrays
- Objekte in Arrays
- Objektverwaltung mit Arrays
- Punktnotation
- Referenzen in Arrays
- Schleifen
- Zugriff auf Objekte über Arrayelemente
|
|
20.4.6 Erläuterung |
|
In Aufgabe 3a wurden Zahlen in einem Array gespeichert: |
|
|
int[] gewichte = new int[5];
|
|
Die Arrayelemente enthielten direkt die Werte. In dieser Aufgabe werden dagegen Objekte gespeichert: |
|
|
Stud[] arr = new Stud[3];
|
|
Dabei entsteht zunächst nur das Array. Die Elemente enthalten anfangs: |
|
|
null
|
|
|
null
|
|
|
null
|
|
Es existieren also noch keine Studierendenobjekte. Erst durch |
|
|
arr[i] = new Stud();
|
|
wird für jedes Arrayelement ein eigenes Objekt erzeugt. Danach zeigt jedes Arrayelement auf ein Objekt der Klasse Stud. Vereinfacht dargestellt: |
|
|
arr[0] --> Stud
|
|
|
arr[1] --> Stud
|
|
|
arr[2] --> Stud
|
|
|
|
21 Übungsaufgaben Teil 2 |
|
|
|
21.1 Aufgabe 4a - Klassen ohne Beziehung |
|
Mehrere Klassen ohne Beziehung |
|
Die folgenden Aufgaben behandeln das Zusammenspiel verschiedener Klassen. In dieser ersten Version existieren die Klassen Stud und Note nebeneinander. Es gibt noch keine Beziehung zwischen ihnen. Die Noten werden über die Matrikelnummern den Studierenden zugeordnet. |
|
21.1.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Aufgabe04a (Hauptprogramm) sowie die Klassen Stud und Note. |
|
Die Klasse Stud soll folgende Attribute besitzen: |
|
- Matrikelnummer (int)
- Name (String)
- Vorname (String)
|
|
Die Klasse Note soll folgende Attribute besitzen: |
|
- Fach (String)
- Note (int)
- Matrikelnummer des Studierenden (int)
|
|
Legen Sie im Hauptprogramm mindestens zwei Studierende und mehrere Noten an. Speichern Sie bei jeder Note die Matrikelnummer des zugehörigen Studierenden. |
|
Geben Sie anschließend für jeden Studierenden alle zugehörigen Noten aus. Die Zuordnung soll dabei ausschließlich über die Matrikelnummer erfolgen. |
|
Hinweise |
|
- Die Matrikelnummer wird in der Klasse Note als normales Attribut gespeichert.
- Zwischen den Klassen Stud und Note besteht noch keine Objektverknüpfung.
- Die Zuordnung erfolgt ausschließlich durch den Vergleich der Matrikelnummern.
|
|
21.1.2 Lernziele |
|
In dieser Aufgabe lernen Sie, mehrere Klassen in einem Java-Programm gemeinsam zu verwenden. Sie verstehen, wie Objekte verschiedener Klassen erzeugt und im Hauptprogramm zusammen eingesetzt werden. Dadurch erwerben Sie die Grundlagen für die spätere Modellierung von Objektbeziehungen. |
|
Zusammen mit den folgenden Aufgaben sollte sich ihnen der Unterschied zwischen einer datenbankbasierten Verknüpfung (so wie hier) und einer objektorientierten (wie in den folgenden Aufgaben) erschließen. |
|
21.1.3 Ergebnis Programmlauf |
|
|
Paula Maier hat folgende Noten:
|
|
|
Mathe: 2
|
|
|
Informatik: 1
|
|
|
|
|
|
Anna Schulz hat folgende Noten:
|
|
|
Mathe: 3
|
|
|
|
21.1.4 Lösung |
|
|
package studierende;
|
|
|
|
|
|
public class Aufgabe04a {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
Stud s1 = new Stud(1001, "Maier", "Paula");
|
|
|
Stud s2 = new Stud(1002, "Schulz", "Anna");
|
|
|
|
|
|
Note n1 = new Note("Mathe", 2, 1001);
|
|
|
Note n2 = new Note("Informatik", 1, 1001);
|
|
|
Note n3 = new Note("Mathe", 3, 1002);
|
|
|
|
|
|
Note[] alleNoten = { n1, n2, n3 };
|
|
|
|
|
|
notenAusgeben(s1, alleNoten);
|
|
|
System.out.println();
|
|
|
|
|
|
notenAusgeben(s2, alleNoten);
|
|
|
}
|
|
|
|
|
|
static void notenAusgeben(Stud s, Note[] alleNoten) {
|
|
|
System.out.println(s.vName + " " + s.name
|
|
|
+ " hat folgende Noten:");
|
|
|
|
|
|
for (Note n : alleNoten) {
|
|
|
if (n.mNr == s.mNr) {
|
|
|
System.out.println(n.fach + ": " + n.note);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
Stud(int mNr, String name, String vName) {
|
|
|
this.mNr = mNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Note {
|
|
|
String fach;
|
|
|
int note;
|
|
|
int mNr;
|
|
|
|
|
|
Note(String fach, int note, int mNr) {
|
|
|
this.fach = fach;
|
|
|
this.note = note;
|
|
|
this.mNr = mNr;
|
|
|
}
|
|
|
}
|
|
21.1.5 Betrachtete Themen |
|
- Attribute
- forEach-Schleife
- Instanziierung mit new
- Konstruktoren
- Matrikelnummer als Zuordnungskriterium
- Mehrere Klassen
- Objektarrays
- Objekte
- Objektorientierte Modellierung ohne Objektverknüpfung
- Parameterübergabe an Konstruktoren
- Suche in einem Array
- Vergleich von Attributwerten
- Zuordnung über Identifikator
- Zusammenarbeit mehrerer Klassen im selben Projekt
|
|
21.1.6 Erläuterung |
|
Mit dieser Aufgabe wird gelernt, |
|
- mehrere Klassen in einem Programm zu verwenden,
- Objekte anzulegen und mit Attributwerten zu versehen,
- Daten über einen gemeinsamen Identifikator (Matrikelnummer) miteinander zu verknüpfen,
- Objekte mit Hilfe einer Schleife zu durchsuchen und passende Datensätze auszuwählen.
|
|
Diese Lösung entspricht dem Vorgehen in Datenbanksystemen, bei denen Datensätze häufig über Schlüsselwerte miteinander verbunden werden. Eine direkte Objektverknüpfung zwischen Studierenden und Noten wird in den folgenden Aufgaben eingeführt. |
|
21.2 Aufgabe 4b -Einseitig |
|
Einseitige objektorientierte 1:n-Beziehung zwischen Studierenden und Noten |
|
21.2.1 Aufgabenstellung |
|
In Aufgabe 4a wurden Studierende und Noten lediglich über die Matrikelnummer miteinander verbunden. Nun soll erstmals eine direkte Beziehung zwischen Objekten eingerichtet werden. Erweitern Sie die Lösung aus Aufgabe 4a. Ein Studierender soll mehrere Noten besitzen können. |
|
Ergänzen Sie deshalb die Klasse Stud um eine geeignete Datenstruktur zur Speicherung mehrerer Noten. Legen Sie mindestens drei Studierende und mehrere Noten an und ordnen Sie die Noten den jeweiligen Studierenden zu. Geben Sie anschließend für jeden Studierenden alle gespeicherten Noten aus. |
|
Hinweise |
|
- Die Noten werden direkt beim Studierenden gespeichert.
- Zwischen den Klassen Stud und Note besteht eine einseitige Beziehung.
- Von einem Studierenden kann auf seine Noten zugegriffen werden.
- Von einer Note kann noch nicht auf den zugehörigen Studierenden geschlossen werden.
|
|
21.2.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine einseitige 1:n-Beziehung zwischen zwei Klassen in Java zu realisieren. Sie verstehen, wie ein Objekt mehrere zugehörige Objekte verwalten kann und wie diese Beziehung über Objektreferenzen hergestellt wird. Dadurch vertiefen Sie Ihr Verständnis für die Modellierung einfacher Objektbeziehungen in der objektorientierten Programmierung. |
|
21.2.3 Ergebnis Programmlauf |
|
|
Paul Maier
|
|
|
Mathe: 2
|
|
|
Informatik: 1
|
|
|
|
|
|
Anna Schulz
|
|
|
Mathe: 3
|
|
|
|
|
|
Lisa Huber
|
|
|
Programmierung: 1
|
|
|
Datenbanken: 2
|
|
|
|
21.2.4 Lösung |
|
Klasse Stud |
|
|
package studierende;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Stud {
|
|
|
|
|
|
int matrNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
===== VERKNÜPFUNG ===== Zu einem Studierenden gehören mehrere Noten. |
|
|
List<Note> noten = new ArrayList<>();
|
|
|
|
|
|
Stud(int matrNr, String name, String vName) {
|
|
|
this.matrNr = matrNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
|
|
===== VERKNÜPFUNG ===== Fügt eine Note zur Liste hinzu. |
|
|
void addNote(Note n) {
|
|
|
noten.add(n);
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println(vName + " " + name);
|
|
|
|
|
|
for (Note n : noten) {
|
|
|
System.out.println(n.fach + ": " + n.note);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Note |
|
|
package studierende;
|
|
|
|
|
|
class Note {
|
|
|
String fach;
|
|
|
int note;
|
|
|
|
|
|
Note(String fach, int note) {
|
|
|
this.fach = fach;
|
|
|
this.note = note;
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe04b - Hauptprogramm |
|
|
package studierende;
|
|
|
|
|
|
public class Aufgabe04b {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Stud s1 = new Stud(1001, "Maier", "Paul");
|
|
|
Stud s2 = new Stud(1002, "Schulz", "Anna");
|
|
|
Stud s3 = new Stud(1003, "Huber", "Lisa");
|
|
|
|
|
|
s1.addNote(new Note("Mathe", 2));
|
|
|
s1.addNote(new Note("Informatik", 1));
|
|
|
|
|
|
s2.addNote(new Note("Mathe", 3));
|
|
|
|
|
|
s3.addNote(new Note("Programmierung", 1));
|
|
|
s3.addNote(new Note("Datenbanken", 2));
|
|
|
|
|
|
s1.ausgeben();
|
|
|
System.out.println();
|
|
|
|
|
|
s2.ausgeben();
|
|
|
System.out.println();
|
|
|
|
|
|
s3.ausgeben();
|
|
|
}
|
|
|
}
|
|
21.2.5 Ergebnis Programmlauf |
|
Siehe Aufgabenstellung. |
|
21.2.6 Betrachtete Themen |
|
- 1:n-Beziehungen
- ArrayList
- Assoziationen
- ForEach-Schleife
- Generics (List<Note>)
- Hinzufügen von Objekten zu Listen
- List
- Mehrere Klassen
- Navigation zwischen Objekten
- Objekte
- Objekte als Attribute
- Objektorientierte Modellierung
- Objektreferenzen
- Sammlungen von Objekten
- Unidirektionale Beziehungen
|
|
In dieser Aufgabe wird erstmals eine einseitige Assoziation realisiert. Den Studierenden sind Noten zugeordnet. Von den Noten kann aber (noch) nicht auf die Studierenden geschlossen werden. |
|
21.2.7 Erläuterung |
|
Erstmals wird eine Beziehung eingerichtet. Die Klasse Stud enthält eine Liste von Noten: |
|
|
class Stud {
|
|
|
List<Note> noten = new ArrayList<>();
|
|
|
}
|
|
Dadurch kann ein Studierender beliebig viele Noten verwalten. Die Methode |
|
|
void addNote(Note n)
|
|
fügt eine weitere Note hinzu. Beispielsweise: |
|
|
s1.addNote(new Note("Mathe", 2));
|
|
Dadurch entsteht eine direkte Objektverknüpfung. |
|
21.2.8 Exkurs - Von Arrays zu Listen |
|
Oftmals macht die Unterscheidung von Arrays und Listen Probleme. Deshalb dieser Exkurs. |
|
Bei List<Note> noten = new ArrayList<>(); kommen gegenüber int[] gewichte = new int[5]; mehrere neue Konzepte hinzu. |
|
1. Feste Größe oder dynamische Größe |
|
Beim Array: |
|
|
int[] gewichte = new int[5];
|
|
ist die Größe fest vorgegeben: 5 Elemente. Später können keine weiteren Elemente hinzugefügt werden. Bei |
|
|
List<Note> noten = new ArrayList<>();
|
|
wird eine dynamische Liste angelegt. Diese wächst automatisch: |
|
|
noten.add(n1);
|
|
|
noten.add(n2);
|
|
|
noten.add(n3);
|
|
Man muss die Größe nicht vorher kennen. |
|
2.Gespeicherte Elemente |
|
Beim Array: |
|
|
int[] gewichte
|
|
werden Integer-Werte gespeichert. Bei |
|
|
List<Note> noten
|
|
werden Objekte der Klasse Note gespeichert. Die Liste enthält also Verweise auf Notenobjekte. |
|
3. Das Interface List |
|
|
List<Note>
|
|
bedeutet: |
|
- Variable heißt noten
- Sie verwaltet mehrere Objekte vom Typ Note
- Die Programmierung erfolgt über das Interface List
|
|
Vereinfacht kann man sagen: List ist ein Behälter für beliebig viele Objekte. |
|
4. Generische Typen |
|
|
<Note>
|
|
legten fest, welche Objekte gespeichert werden dürfen. Beispiele: |
|
|
List<String> namen;
|
|
... speichert Zeichenketten |
|
|
List<Integer> zahlen;
|
|
... speichert ganze Zahlen |
|
|
List<Stud> studierende;
|
|
... speichert Studierende |
|
|
List<Note> noten;
|
|
... speichert Noten |
|
5. Das Objekt ArrayList ... |
|
|
new ArrayList<>()
|
|
... erzeugt die eigentliche Liste. Man könnte auch schreiben: |
|
|
new ArrayList<Note>()
|
|
Seit Java 7 genügt meist: |
|
|
new ArrayList<>()
|
|
da Java den Typ automatisch erkennt. |
|
Vergleich der beiden Varianten |
|
| Array |
Liste |
| feste Größe |
wächst automatisch |
| Anzahl vorher festlegen |
beliebig viele Elemente |
| Zugriff mit [ ] |
Zugriff mit get() |
| primitive Datentypen und Objekte |
meist Objekte |
| keine Komfortmethoden |
viele Komfortmethoden |
| |
|
|
Beispiele: gewichte[2] und noten.get(2). |
|
|
|
21.3 Aufgabe 4c - Bidirektional |
|
Bidirektionale 1: n-Beziehung zwischen Studierenden und Noten |
|
21.3.1 Aufgabenstellung |
|
Nun wird, im Vergleich zur vorigen Aufgabe, die Gegenrichtung ergänzt: Von einer Note soll auch auf den zugehörigen Studierenden geschlossen werden. Erweitern Sie dazu die Lösung aus Aufgabe 4b. Bisher "kennt" ein Studierender seine Noten. Nun soll zusätzlich jede Note "wissen", zu welchem Studierenden sie gehört. Ergänzen Sie dazu die Klasse Note um ein geeignetes Attribut, das auf ein Objekt der Klasse Stud verweist. Richten Sie die Beziehungen beim Erzeugen der Objekte entsprechend ein. Realisieren Sie anschließend folgende Ausgaben: |
|
- Geben Sie für alle Studierenden ihre Noten aus.
- Geben Sie alle Studierenden aus, die im Fach Informatik die Note 1 erhalten haben.
|
|
21.3.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine bidirektionale 1:n-Beziehung zwischen zwei Klassen in Java zu realisieren. Sie verstehen, wie sich verknüpfte Objekte gegenseitig referenzieren und wie dadurch der Zugriff auf die Beziehung von beiden Seiten aus möglich wird. Dadurch vertiefen Sie Ihr Verständnis für bidirektionale Objektbeziehungen in der objektorientierten Programmierung. |
|
|
|
21.3.3 Lösung |
|
Klasse Stud |
|
|
package studierende;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Stud {
|
|
|
int matrNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
===== VERKNÜPFUNG ===== Stud -> Note Ein Studierender "kennt" seine Noten. |
|
|
List<Note> noten = new ArrayList<>();
|
|
|
Stud(int matrNr, String name, String vName) {
|
|
|
this.matrNr = matrNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
|
|
===== VERKNÜPFUNG ===== Fügt eine Note zur Notenliste hinzu. |
|
|
void addNote(Note n) {
|
|
|
noten.add(n);
|
|
|
}
|
|
|
void ausgeben() {
|
|
|
System.out.println(vName + " " + name);
|
|
|
|
|
|
for (Note n : noten) {
|
|
|
System.out.println(n.fach + ": " + n.note);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Note |
|
|
package studierende;
|
|
|
|
|
|
class Note {
|
|
|
|
|
|
String fach;
|
|
|
int note;
|
|
|
|
|
===== VERKNÜPFUNG ===== Note -> Stud |
|
|
Stud student;
|
|
|
Note(String fach, int note, Stud student) {
|
|
|
this.fach = fach;
|
|
|
this.note = note;
|
|
===== VERKNÜPFUNG ===== |
|
|
this.student = student;
|
|
|
}
|
|
|
}
|
|
Hauptprogramm |
|
|
package studierende;
|
|
|
|
|
|
public class Aufgabe04c {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Stud s1 = new Stud(1001, "Maier", "Paul");
|
|
|
Stud s2 = new Stud(1002, "Schmidt", "Anna");
|
|
|
Stud s3 = new Stud(1003, "Huber", "Lisa");
|
|
|
|
|
===== VERKNÜPFUNG ===== Beim Erzeugen wird der oder die Studierende "mit der Note gespeichert". |
|
|
Note n1 = new Note("Mathe", 2, s1);
|
|
|
Note n2 = new Note("Informatik", 1, s1);
|
|
|
|
|
|
Note n3 = new Note("Mathe", 3, s2);
|
|
|
Note n4 = new Note("Informatik", 2, s2);
|
|
|
|
|
|
Note n5 = new Note("Informatik", 1, s3);
|
|
|
Note n6 = new Note("Datenbanken", 2, s3);
|
|
|
|
|
===== VERKNÜPFUNG ===== Zusätzlich werden die Noten beim Studierenden gespeichert. |
|
|
s1.addNote(n1);
|
|
|
s1.addNote(n2);
|
|
|
|
|
|
s2.addNote(n3);
|
|
|
s2.addNote(n4);
|
|
|
|
|
|
s3.addNote(n5);
|
|
|
s3.addNote(n6);
|
|
|
|
|
|
Stud[] alleStudierenden = { s1, s2, s3 };
|
|
|
Note[] alleNoten = { n1, n2, n3, n4, n5, n6 };
|
|
|
|
|
|
System.out.println("Alle Studierenden mit ihren Noten:\n");
|
|
|
|
|
|
for (Stud s : alleStudierenden) {
|
|
|
s.ausgeben();
|
|
|
System.out.println();
|
|
|
}
|
|
|
|
|
|
System.out.println("Studierende mit Note 1 in Informatik:\n");
|
|
|
|
|
|
for (Note n : alleNoten) {
|
|
|
|
|
|
if (n.fach.equals("Informatik") amp;amp; n.note == 1) {
|
|
|
System.out.println(
|
|
|
n.student.vName + " " + n.student.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
21.3.4 Ergebnis Programmlauf |
|
|
Alle Studierenden mit ihren Noten:
|
|
|
|
|
|
Paul Maier
|
|
|
Mathe: 2
|
|
|
Informatik: 1
|
|
|
|
|
|
Anna Schmidt
|
|
|
Mathe: 3
|
|
|
Informatik: 2
|
|
|
|
|
|
Lisa Huber
|
|
|
Informatik: 1
|
|
|
Datenbanken: 2
|
|
|
|
|
|
Studierende mit Note 1 in Informatik:
|
|
|
|
|
|
Paul Maier
|
|
|
Lisa Huber
|
|
21.3.5 Betrachtete Themen |
|
- 1:n-Beziehungen
- Assoziationen
- Bidirektionale Beziehungen
- ForEach-Schleifen
- Generics (List<Note>)
- Kombinierte Bedingungen mit amp;amp;
- Konsistenz von Beziehungen
- Listen (ArrayList)
- Mehrere Klassen
- Navigation in beide Richtungen
- Objektarrays
- Objekte
- Objekte als Attribute
- Objektorientierte Modellierung
- Objektreferenzen
- Suche in Objektbeständen
- Vergleich von Zeichenketten mit equals()
|
|
21.3.6 Theorieaspekt |
|
Eine Beziehung kann in Java in beiden Klassen hinterlegt werden. In der Klasse Stud wird gespeichert, welche Noten ein Studierender besitzt: |
|
|
class Stud {
|
|
|
List<Note> noten;
|
|
|
}
|
|
In der Klasse Note wird gespeichert, zu welchem Studierenden die Note gehört: |
|
|
class Note {
|
|
|
Stud student;
|
|
|
}
|
|
Damit kann man in beide Richtungen navigieren: |
|
|
stud.noten
|
|
und |
|
|
note.student
|
|
Die Beziehung ist damit bidirektional. |
|
Diese Aufgabe zeigt den Unterschied zwischen einer einseitigen und einer zweiseitigen Objektbeziehung. In Aufgabe 4b war nur diese Navigation möglich: |
|
|
Stud -> Note
|
|
Nun ist zusätzlich möglich: |
|
|
Note -> Stud
|
|
Dadurch kann man nicht nur alle Noten eines Studierenden ausgeben, sondern auch von einer bestimmten Note zurück zum zugehörigen Studierenden navigieren. |
|
Besonders wichtig ist dabei die Konsistenz der Beziehung: Die Note muss beim Studierenden eingetragen sein, und zugleich muss die Note den Studierenden "kennen". |
|
|
|
21.4 Aufgabe 4d - n:m-Beziehung |
|
n:m-Beziehung zwischen Angestellten und Projekten |
|
21.4.1 Aufgabe |
|
Erstellen Sie die Klassen Angestellter, Projekt und Aufgabe04d (Hauptprogramm). Die Klasse Angestellter erhält folgende Attribute: |
|
- Personalnummer (persNr, int)
- Name (name, String)
- Abteilung (abteilung, String)
|
|
Festgehalten wird auch, in welchen Projekten die oder der Angestellte mitarbeitet. |
|
Die Klasse Projekt erhält folgende Attribute: |
|
- Projektnummer (projNr, int)
- Projektbezeichnung (projBez, String)
|
|
Hier wird festgehalten, wer im jeweiligen Projekt mitarbeitet. Damit ist dann die m:n-Beziehung erfasst. |
|
Legen Sie im Hauptprogramm mehrere Angestellte und mehrere Projekte an. Stellen Sie anschließend Beziehungen zwischen den Objekten her. Realisieren Sie die Erfassung der Projekte bei den Angestellten und der Angestellten bei den Projekten durch geeignete Methoden. |
|
Geben Sie danach |
|
- alle Projekte eines ausgewählten Angestellten und
- alle Angestellten eines ausgewählten Projekts
|
|
aus. |
|
21.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine bidirektionale n:m-Beziehung zwischen zwei Klassen in Java zu realisieren. Sie verstehen, wie Objekte beider Klassen mehrere Verknüpfungen zu Objekten der jeweils anderen Klasse verwalten und wie diese Beziehungen von beiden Seiten aus genutzt werden können. Dadurch vertiefen Sie Ihr Verständnis für die Modellierung komplexerer Objektbeziehungen in der objektorientierten Programmierung. |
|
21.4.3 Lösung |
|
Klasse Angestellter |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String abteilung;
|
|
Liste der Projekte des Angestellten |
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
Angestellter(int persNr, String name, String abteilung) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.abteilung = abteilung;
|
|
|
}
|
|
|
void addProjekt(Projekt p) {
|
|
|
projekte.add(p);
|
|
|
}
|
|
|
}
|
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Projekt {
|
|
|
int projNr;
|
|
|
String projBez;
|
|
Liste der beteiligten Angestellten |
|
|
List<Angestellter> angestellte = new ArrayList<>();
|
|
|
Projekt(int projNr, String projBez) {
|
|
|
this.projNr = projNr;
|
|
|
this.projBez = projBez;
|
|
|
}
|
|
|
void addAngestellter(Angestellter a) {
|
|
|
angestellte.add(a);
|
|
|
}
|
|
|
}
|
|
Hauptprogramm Aufgabe04d |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe04d {
|
|
|
public static void main(String[] args) {
|
|
|
Angestellter a1 =
|
|
|
new Angestellter(1001, "Müller", "Entwicklung");
|
|
|
Angestellter a2 =
|
|
|
new Angestellter(1002, "Schneider", "Vertrieb");
|
|
|
Projekt p1 =
|
|
|
new Projekt(2001, "BPMN");
|
|
|
Projekt p2 =
|
|
|
new Projekt(2002, "Prozessoptimierung");
|
|
Verknüpfungen herstellen |
|
|
a1.addProjekt(p1);
|
|
|
p1.addAngestellter(a1);
|
|
|
a1.addProjekt(p2);
|
|
|
p2.addAngestellter(a1);
|
|
|
a2.addProjekt(p1);
|
|
|
p1.addAngestellter(a2);
|
|
Projekte von a1 ausgeben |
|
|
System.out.println("Projekte von "
|
|
|
+ a1.name + ":");
|
|
|
for (Projekt p : a1.projekte) {
|
|
|
System.out.println(p.projBez);
|
|
|
}
|
|
|
System.out.println();
|
|
Angestellte von p1 ausgeben |
|
|
System.out.println("Mitarbeiter im Projekt "
|
|
|
+ p1.projBez + ":");
|
|
|
for (Angestellter a : p1.angestellte) {
|
|
|
System.out.println(a.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
21.4.4 Ergebnis Programmlauf |
|
|
Projekte von Müller:
|
|
|
BPMN
|
|
|
Prozessoptimierung
|
|
|
|
|
|
Mitarbeiter im Projekt BPMN:
|
|
|
Müller
|
|
|
Schneider
|
|
21.4.5 Betrachtete Themen |
|
- ArrayList
- Ausgabe verknüpfter Objekte
- Bidirektionale Beziehung
- foreach-Schleife
- List
- Mehrere Klassen
- Mehrwertige Attribute
- Methoden zum Herstellen von Beziehungen
- n:m-Beziehung
- Navigation in beide Richtungen
- Objekte als Listenelemente
- Objekte und Objektreferenzen
|
|
21.4.6 Anmerkung |
|
Besonders wichtig ist hier: |
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
und |
|
|
List<Angestellter> angestellte = new ArrayList<>();
|
|
Damit wird die n:m-Beziehung in beiden Klassen gespeichert: |
|
- Ein Angestellter kann in mehreren Projekten mitarbeiten.
- Ein Projekt kann mehrere Angestellte haben.
|
|
Die Methoden |
|
|
void addProjekt(Projekt p)
|
|
und |
|
|
void addAngestellter(Angestellter a)
|
|
stellen die Beziehung zwischen den Objekten her. |
|
21.5 Aufgabe 4e - Assoziationsklasse |
|
n:m-Beziehung mit Assoziationsklasse und Beziehungsatttribut |
|
In dieser Aufgabe 4e wird dieselbe inhaltliche Situation wie in der vorigen Aufgabe mit einer Assoziationsklasse modelliert. Dann gibt es keine direkten Listen List<Projekt> bzw. List<Angestellter> mehr, sondern Objekte der Assoziationsklasse (z. B. Mitarbeit), die die Beziehung repräsentieren. Dadurch können auch Beziehungsattribute wie Rolle, Eintrittsdatum oder Arbeitsstunden gespeichert werden. |
Assoziationsklasse |
21.5.1 Aufgabe |
|
Erfasst werden soll die Mitarbeit von Angestellten in Projekten. Ein Angestellter kann an mehreren Projekten beteiligt sein. Gleichzeitig arbeiten in jedem Projekt mehrere Angestellte mit. Es liegt also eine n:m-Bezuiehung vor. |
|
Zusätzlich soll durch ein Attribut Mitarbeit gespeichert werden, wie viele Stunden ein Angestellter bereits für ein bestimmtes Projekt geleistet hat. |
|
Erstellen Sie die folgenden Klassen: |
|
Angestellter |
|
- persNr (int)
- name (String)
- abteilung (String)
|
|
Projekt |
|
- projNr (int)
- projBez (String)
|
|
Mitarbeit |
|
- angestellter (Angestellter)
- projekt (Projekt)
- stunden (int)
|
|
Legen Sie im Hauptprogramm mindestens zwei Angestellte und zwei Projekte an. Nutzen Sie dafür Konstruktoren mit Parameterliste. Erzeugen Sie anschließend mehrere Objekte für die Klasse Mitarbeit, um die Beteiligung der Angestellten an den Projekten abzubilden, etwa so wie im Beispielsergebnis. |
|
Geben Sie alle Einträge in Mitarbeit aus, z.B. so: |
|
|
Müller arbeitet im Projekt BPMN mit.
|
|
|
Geleistete Stunden: 120
|
|
|
|
|
|
Müller arbeitet im Projekt Prozessoptimierung mit.
|
|
|
Geleistete Stunden: 40
|
|
|
|
|
|
Meier arbeitet im Projekt BPMN mit.
|
|
|
Geleistete Stunden: 60
|
|
|
|
|
|
Meier arbeitet im Projekt Prozessoptimierung mit.
|
|
|
Geleistete Stunden: 75
|
|
21.5.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine n:m-Beziehung mit einer Assoziationsklasse zu realisieren. Sie verstehen, wie zusätzliche Informationen zur Beziehung - beispielsweise die Anzahl der geleisteten Stunden eines Mitarbeiters in einem Projekt - in einer eigenen Klasse gespeichert werden. Dadurch vertiefen Sie Ihr Verständnis für die Modellierung komplexer Objektbeziehungen in Java und UML. |
|
Dies ist wiederum eine datenbankorientierte Lösung des Problems, Daten miteinander Zu verknüpfen, die in einer n:m-Beziehung stehen und deren Beziehung auch Attribute aufweist. Vgl. meine Texte zu Relationalen Datenbanken auf diesen Web-Seiten und in [Staud 2021] |
|
21.5.3 Lösung |
|
Klasse Angestellter |
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String abteilung;
|
|
|
|
|
|
Angestellter(int persNr, String name, String abteilung) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.abteilung = abteilung;
|
|
|
}
|
|
|
}
|
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
class Projekt {
|
|
|
int projNr;
|
|
|
String projBez;
|
|
|
Projekt(int projNr, String projBez) {
|
|
|
this.projNr = projNr;
|
|
|
this.projBez = projBez;
|
|
|
}
|
|
|
}
|
|
Klasse Mitarbeit |
|
|
package firma;
|
|
|
|
|
|
class Mitarbeit {
|
|
|
Angestellter angestellter;
|
|
|
Projekt projekt;
|
|
|
int stunden;
|
|
|
|
|
|
Mitarbeit(Angestellter angestellter, Projekt projekt,
|
|
|
int stunden) {
|
|
|
this.angestellter = angestellter;
|
|
|
this.projekt = projekt;
|
|
|
this.stunden = stunden;
|
|
|
}
|
|
|
}
|
|
Hauptprogramm Aufgabe04d |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe04d {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
Angestellte erzeugen |
|
|
Angestellter a1 = new Angestellter(1001, "Müller", "IT");
|
|
|
Angestellter a2 = new Angestellter(1002, "Meier", "Controlling");
|
|
Projekte erzeugen |
|
|
Projekt p1 = new Projekt(2001, "BPMN");
|
|
|
Projekt p2 = new Projekt(2002, "Prozessoptimierung");
|
|
Mitarbeiten erzeugen |
|
|
Mitarbeit m1 = new Mitarbeit(a1, p1, 120);
|
|
|
Mitarbeit m2 = new Mitarbeit(a1, p2, 40);
|
|
|
Mitarbeit m3 = new Mitarbeit(a2, p1, 60);
|
|
|
Mitarbeit m4 = new Mitarbeit(a2, p2, 75);
|
|
Ausgabe |
|
|
Mitarbeit[] liste = { m1, m2, m3, m4 };
|
|
|
for (Mitarbeit m : liste) {
|
|
|
System.out.println(m.angestellter.name + " arbeitet im Projekt " + m.projekt.projBez + " mit.");
|
|
|
System.out.println("Geleistete Stunden: " + m.stunden);
|
|
|
System.out.println();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
21.5.4 Betrachtete Themen |
|
- Array zur Verwaltung mehrerer Beziehungsobjekte
- Assoziationsklasse
- Attribute
- Ausgabe verknüpfter Objekte
- Beziehung als eigenes Objekt
- Beziehungsattribute
- foreach-Schleife
- Konstruktoren mit Parameterliste
- mehrere Klassen
- n:m-Beziehung
- Navigation über die Assoziationsklasse
- Objekte als Attribute
- Objekte und Objektreferenzen
- objektorientierte Umsetzung einer n:m-Beziehung
- Referenz von Mitarbeit auf Angestellter
- Referenz von Mitarbeit auf Projekt
- Trennung von Objektklassen und Beziehungsklasse
- Vergleich mit direkter Listenlösung aus Aufgabe 4d
- Vergleich mit einer junction table
- Zugriff auf Attribute verknüpfter Objekte
- Zusammenhang zum relationalen Datenbankmodell
- Zusammenhang zur UML-Assoziationsklasse
|
|
21.5.5 Anmerkung |
|
Der zentrale Unterschied zu Aufgabe 4d ist: In 4d wird die n:m-Beziehung durch direkte Listen in beiden Klassen gespeichert: List<Projekt> in Angestellter bzw. List<Angestellter> in Projekt. In 4e wird die Beziehung selbst zu einem eigenen Objekt: |
|
|
class Mitarbeit {
|
|
|
Angestellter angestellter;
|
|
|
Projekt projekt;
|
|
|
int stunden;
|
|
|
}
|
|
Damit kann die Beziehung eigene Attribute erhalten, hier: int stunden; |
|
Das ist der eigentliche Schwerpunkt dieser Aufgabe: Die Mitarbeit ist nicht nur eine Verknüpfung zwischen Angestelltem und Projekt, sondern ein eigenständiges Objekt mit zusätzlichen Attributen. |
|
Damit unterscheidet sich diese Aufgabe von den bisherigen in 4a bis 4d: |
|
- Bei 1:n-Beziehungen genügt meist eine Referenz oder eine Liste.
- Bei einer n:m-Beziehung wird häufig eine zusätzliche Klasse benötigt.
- Die Klasse Mitarbeit beschreibt die Beziehung zwischen Angestellten und Projekten.
- Sie enthält zudem das Beziehungsattribut stunden.
- Im relationalen Datenbankmodell würde die Klasse Mitarbeit einer Verbindungsrelation (junction table) entsprechen.
|
|
Kein Link-Array |
|
Dies ist zugleich ein einfaches Beispiel für eine Assoziationsklasse der UML. Bei einer solchen wird die Verknüpfung selbst als eigenes Objekt modelliert. Deshalb benötigt man normalerweise kein zusätzliches Link-Array oder eine separate Liste von Zuordnungen. |
|
22 Übungsaufgaben Teil 3 |
|
|
|
22.1 Aufgabe 5 - Eingaben |
|
Benutzereingabe mit Scanner |
|
22.1.1 Aufgabenstellung |
|
Ausgangspunkt ist die Klasse Stud wie oben, also z.B. so: |
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
}
|
|
Mit dem Programm sollen Namen und Matrikelnummer eines Studierenden über die Konsole eingelesen, in einem Objekt gespeichert und auf der Konsole ausgegeben werden. Etwa so: |
|
22.1.2 Gewünschte Ausgabe |
|
|
Matrikelnummer eingeben: 1007
|
|
|
Vorname eingeben: Pierre
|
|
|
Name eingeben: Picard
|
|
|
|
|
|
--- Daten des Studierenden ---
|
|
|
Matrikelnummer: 1007
|
|
|
Vorname: Pierre
|
|
|
Name: Picard
|
|
22.1.3 Lernziele |
|
In dieser Aufgabe lernen Sie, Benutzereingaben mit der Klasse Scanner einzulesen und zur Erzeugung eines Objekts zu verwenden. Sie verstehen, wie Eingabedaten verarbeitet, Attributen zugewiesen und anschließend ausgegeben werden. |
|
|
|
22.1.4 Lösung |
|
Klasse Aufgabe05 |
|
|
package studierende;
|
|
|
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class Aufgabe05 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
Scanner-Objekt für Eingaben erzeugen |
|
|
Scanner sc = new Scanner(System.in);
|
|
|
|
|
Studierenden-Objekt erzeugen |
|
|
Stud s = new Stud();
|
|
|
|
|
Eingaben. Die Eingabe über die Tastatur liefert zunächst einen String. Mit Integer.parseInt() wird dieser String in einen Integer-Wert umgewandelt. |
|
|
System.out.print("Matrikelnummer eingeben: ");
|
|
|
s.mNr = Integer.parseInt(sc.nextLine());
|
|
|
System.out.print("Vornamen eingeben: ");
|
|
|
s.vName = sc.nextLine();
|
|
|
System.out.print("Namen eingeben: ");
|
|
|
s.name = sc.nextLine();
|
|
|
|
|
Ausgabe |
|
|
s.ausgeben();
|
|
|
|
|
Scanner schließen |
|
|
sc.close();
|
|
|
}
|
|
|
}
|
|
Klasse Stud |
|
|
package studierende;
|
|
|
|
|
|
class Stud {
|
|
|
int mNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
void ausgeben() {
|
|
|
System.out.println("\n--- Daten des Studierenden ---");
|
|
|
System.out.println("Matrikelnummer: " + mNr);
|
|
|
System.out.println("Vorname: " + vName);
|
|
|
System.out.println("Name: " + name);
|
|
|
}
|
|
} |
|
22.1.5 Betrachtete Themen |
|
- Attribute
- Benutzereingaben über die Konsole
- Datentypumwandlung mit Integer.parseInt()
- Einlesen von Zeichenketten (nextLine())
- Interaktive Programme
- Klasse Scanner
- Konsolenausgaben mit System.out.print()
- Konsolenausgaben mit System.out.println()
- Methoden
- Methodenaufruf
- Objekte
- Objekterzeugung mit new
- Objektorientierte Datenhaltung
- Referenzvariablen
- Ressourcen freigeben mit close()
- Speicherung von Eingaben in Objektattributen
- Trennung von Hauptprogramm und Fachklasse
- Verwendung externer Klassen (import java.util.Scanner)
- Zugriff auf Attribute eines Objekts
|
|
Theorieaspekte |
|
Der Schwerpunkt dieser Aufgabe liegt nicht auf Klassenbeziehungen, sondern auf dem Einlesen von Daten und deren Speicherung in Objekten. Gezeigt wird: |
|
1. Ein Objekt erzeugen |
|
|
Stud s = new Stud();
|
|
2. Daten vom Benutzer einlesen |
|
|
s.name = sc.nextLine();
|
|
3. Die Daten im Objekt speichern |
|
|
s.mNr = ...
|
|
|
s.vName = ...
|
|
|
s.name = ...
|
|
4. Die gespeicherten Daten über eine Methode ausgeben |
|
|
s.ausgeben();
|
|
Damit entsteht ein vollständiger Ablauf aus: |
|
Eingabe -> Speicherung im Objekt -> Verarbeitung -> Ausgabe |
|
Dieser Ablauf bildet die Grundlage vieler Anwendungen, beispielsweise für Datenbanken, grafische Oberflächen oder Dateiverarbeitung. |
|
22.2 Aufgabe 6 - Record |
|
"Datensätze" |
|
22.2.1 Aufgabenstellung |
|
Erstellen Sie ein Java-Programm zur Verwaltung einfacher Studierendendaten mit einem record. Der record soll folgende Attribute besitzen: |
|
|
name vom Typ String,
|
|
|
vName vom Typ String,
|
|
|
plz vom Typ int,
|
|
|
ort vom Typ String,
|
|
|
anzSem vom Typ int,
|
|
|
gebTag vom Typ String.
|
|
Führen Sie folgende Aufgaben aus: |
|
- Erzeugen Sie drei Objekte des Typs Stud in der main()-Methode.
- Weisen Sie zwei Objekten identische Werte zu.
- Geben Sie einzelne Komponenten über die automatisch erzeugten Zugriffsmethoden aus.
- Geben Sie anschließend die gesamten Objekte mit toString() aus.
- Vergleichen Sie die Objekte mit equals() und geben Sie das Ergebnis aus.
- Ergänzen Sie im record Stud eine eigene Methode ausgeben(), die die Werte klassisch zeilenweise ausgibt.
|
|
22.2.2 Lernziele |
|
In dieser Aufgabe lernen Sie Record-Klassen in Java kennen. Sie verstehen, wie sich einfache Datenobjekte mit einem Record kompakt definieren lassen und wie Java automatisch Zugriffsmethoden sowie weitere Standardmethoden bereitstellt. Dadurch erwerben Sie eine moderne und übersichtliche Möglichkeit zur Beschreibung unveränderlicher Datenobjekte. |
|
Vgl. zu Records auch Projekt HS6 und Aufgabe 41. |
|
|
|
22.2.3 Lösung |
|
Klasse HP |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
Drei Record-Objekte werden erzeugt. Auch hier wird mit new der Konstruktor augerufen. Vgl. Record Stud unten. Die records werden per Parameterübergabe beschrieben. |
|
|
Stud s1 = new Stud("Müller", "Franz", 88888, "Überall", 5, "20.1.2000");
|
|
|
Stud s2 = new Stud("Müller", "Franz", 99999, "Nirgendwo", 13, "1.1.2001");
|
|
|
Stud s3 = new Stud("Müller", "Franz", 99999, "Nirgendwo", 13, "1.1.2001");
|
|
|
|
|
Für jedes Attribut wird eine gleichnamige Abfragemethode bereitgestellt. Für name also name(), wie hier gezeigt. |
|
|
System.out.println("\nAusgabe einzelner Attributsausprägungen:\n");
|
|
|
System.out.println("Name: " + s1.name());
|
|
|
System.out.println("Name: " + s2.name());
|
|
|
|
|
Die Methode toString() liefert Ausgaben eines ganzen Record-Objekts mit Attributsbezeichnung und Attributsausprägung. Vgl. unten. |
|
|
System.out.println("\nAusgabe records s1 ... s3:\n");
|
|
|
System.out.println(s1.toString());
|
|
|
System.out.println(s2.toString());
|
|
|
System.out.println(s3.toString());
|
|
|
System.out.println("\nVergleich der Objekte:\n");
|
|
|
|
|
Der Vergleich von Record-Objekten erfolgt mit der Methode equals(). Eine Abfrage mittels einfacher Gleichsetzung klappt nicht. Vgl. die in Abschnitt 4.3 angegebene Literatur. |
|
|
if (s1.equals(s2))
|
|
|
System.out.println("s1 und s2: Wertgleiche Studierende.");
|
|
|
else
|
|
|
System.out.println("s1 und s2: Nicht wertgleiche Studierende.");
|
|
|
if (s3.equals(s2))
|
|
|
System.out.println("s3 und s2: Wertgleiche Studierende.");
|
|
|
else
|
|
|
System.out.println("s3 und s2: Nicht wertgleiche Studierende.");
|
|
|
if (s3.equals(s1))
|
|
|
System.out.println("s3 und s1: Wertgleiche Studierende.");
|
|
|
else
|
|
|
System.out.println("s3 und s1: Nicht wertgleiche Studierende.");
|
|
|
|
|
Zur Veranschaulichung hier noch die "klassische" Ausgabe auf der Konsole. |
|
|
System.out.println("\nStudierende/r s1:");
|
|
|
s1.ausgeben();
|
|
|
System.out.println("\nStudierende/r s2:");
|
|
|
s2.ausgeben();
|
|
|
System.out.println("\nStudierende/r s3:");
|
|
|
s3.ausgeben();
|
|
|
}
|
|
|
}
|
|
Klasse Stud |
|
|
package hochschule;
|
|
|
|
|
|
public record Stud(String name, String vName, int plz, String ort, int anzSem, String gebTag) {
|
|
|
|
|
|
void ausgeben() {
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname: " + vName);
|
|
|
System.out.println("PLZ: " + plz);
|
|
|
System.out.println("Ort: " + ort);
|
|
|
System.out.println("Anzahl Semester: " + anzSem);
|
|
|
System.out.println("Geburtstag: " + gebTag);
|
|
|
}
|
|
|
}
|
|
22.2.4 Ergebnis Programmlauf |
|
|
Ausgabe einzelner Attributsausprägungen:
|
|
|
|
|
|
Name: Müller
|
|
|
Name: Müller
|
|
|
|
|
|
Ausgabe records s1 ... s3:
|
|
|
|
|
|
Stud[name=Müller, vName=Franz, plz=88888, ort=Überall, anzSem=5, gebTag=20.1.2000]
|
|
|
Stud[name=Müller, vName=Franz, plz=99999, ort=Nirgendwo, anzSem=13, gebTag=1.1.2001]
|
|
|
Stud[name=Müller, vName=Franz, plz=99999, ort=Nirgendwo, anzSem=13, gebTag=1.1.2001]
|
|
|
|
|
|
Vergleich der Objekte:
|
|
|
|
|
|
s1 und s2: Nicht wertgleiche Studierende.
|
|
|
s3 und s2: Wertgleiche Studierende.
|
|
|
s3 und s1: Nicht wertgleiche Studierende.
|
|
|
|
|
|
Studierende/r s1:
|
|
|
Name: Müller
|
|
|
Vorname: Franz
|
|
|
PLZ: 88888
|
|
|
Ort: Überall
|
|
|
Anzahl Semester: 5
|
|
|
Geburtstag: 20.1.2000
|
|
|
|
|
|
Studierende/r s2:
|
|
|
Name: Müller
|
|
|
Vorname: Franz
|
|
|
PLZ: 99999
|
|
|
Ort: Nirgendwo
|
|
|
Anzahl Semester: 13
|
|
|
Geburtstag: 1.1.2001
|
|
|
|
|
|
Studierende/r s3:
|
|
|
Name: Müller
|
|
|
Vorname: Franz
|
|
|
PLZ: 99999
|
|
|
Ort: Nirgendwo
|
|
|
Anzahl Semester: 13
|
|
|
Geburtstag: 1.1.2001
|
|
22.2.5 Betrachtete Themen |
|
- automatisch erzeugte equals()-Methode
- automatisch erzeugte hashCode()-Methode
- automatisch erzeugte toString()-Methode
- automatisch erzeugte Zugriffsmethoden
- automatisch erzeugter Konstruktor
- automatische Implementierung von equals(), hashCode() und toString()
- Datenträgerklassen
- eigene Methoden in Records
- Konsolenausgaben
- Konstruktoren
- Methodenaufrufe
- Objektdarstellung mit toString()
- Objekterzeugung mit new
- Objektvergleich mit equals()
- Record-Komponenten
- Record-Komponenten als Parameter des Record-Headers
- Records
- Referenzvariablen
- Unterschied zwischen Referenzgleichheit und Wertgleichheit
- Unterschiede zwischen Record und Klasse
- unveränderliche Objekte (immutable objects)
- Vergleich von == und equals()
- Wertgleichheit von Objekten
- Zugriffsmethoden ohne get
|
|
22.2.6 Exkurs: Wiederholung zu records |
|
Oben wird mit folgendem Befehl ein Record eingerichtet: |
|
|
record Stud(String name, int sem) {}
|
|
Er besitzt somit zwei Attribute: |
|
|
|
|
Daraus erzeugt Java automatisch: |
|
- private final-Attribute
- einen Konstruktor
- Getter-Methoden (name() und sem())
- eine toString()-Methode
- equals() und hashCode() (Methoden der Klasse Object, die jede Java-Klasse automatisch erbt.)
|
|
Beispielhafte Verwendung in einem Hauptprogramm: |
|
|
public class Test
|
|
|
public static void main(String[] args) {
|
|
|
Stud s = new Stud("Maier", 3);{
|
|
Erklärung new Stud("Maier", 3) ruft den automatisch erzeugten Konstruktor auf. Das Objekt wird in der Variablen s gespeichert. |
|
Die Ausgabe mit toString() wird wie folgt realisiert. Der Ausdruck println(s) in der Anweisung ... |
|
|
System.out.println(s);
|
|
... ruft automatisch s.toString() auf. Dies liefert dann hier z.B. Stud[name=Maier, sem=3]. |
|
|
|
22.3 Aufgabe 7 - Vererbung |
|
Effizienter programmieren und modellieren mit Vererbung |
|
22.3.1 Aufgabenstellung |
|
Erstellen Sie ein Java-Programm zur Verwaltung von Fahrzeugen. |
|
Superklasse Fahrzeug |
|
Legen Sie eine Klasse Fahrzeug an. Die Klasse soll folgende Attribute besitzen: |
|
- fzNr (Fahrzeugnummer)
- hersteller
- baujahr
|
|
Erstellen Sie außerdem: |
|
- einen Konstruktor zur Übergabe aller Attribute
- eine Methode anzeigen(), die alle Fahrzeugdaten ausgibt
|
|
Subklasse PKW |
|
Legen Sie eine Klasse PKW an, die von Fahrzeug erbt und folgende zusätzlichen Attribute hat: |
|
- sitze (Anzahl der ...)
- typ (Fahrzeugtyp)
|
|
Erstellen Sie: |
|
- einen Konstruktor
- einen Aufruf des Superklassen-Konstruktors mit super(...)
- eine überschreibende Methode anzeigen()
|
|
Die Methode soll zunächst die Ausgabe der Superklasse nutzen und anschließend die zusätzlichen PKW-Daten ausgeben. |
|
Klasse Aufgabe07 |
|
Erstellen Sie eine Klasse Aufgabe07 mit einem Hauptprogramm (main()). Darin werden ... |
|
- ein Objekt der Klasse Fahrzeug und
- ein Objekt der Klasse PKW
|
|
erzeugt. Geben Sie anschließend die Daten beider Objekte mit der Methode anzeigen() aus. Die Ausgabe soll so aussehen: |
|
|
--- Fahrzeug ---
|
|
|
Fahrzeugnummer: 1
|
|
|
Hersteller: MAN
|
|
|
Baujahr: 2015
|
|
|
|
|
|
--- PKW ---
|
|
|
Fahrzeugnummer: 2
|
|
|
Hersteller: VW
|
|
|
Baujahr: 2022
|
|
|
Sitze: 5
|
|
|
Typ: Kombi
|
|
22.3.2 Lernziele |
|
In dieser Aufgabe lernen Sie das Grundprinzip der Vererbung in Java kennen. Sie verstehen, wie eine Subklasse Attribute und Methoden einer Oberklasse übernimmt und um eigene Attribute erweitert. Dadurch erwerben Sie eine wichtige Grundlage der objektorientierten Programmierung und bereiten sich auf weiterführende Konzepte wie Überschreiben und Polymorphie vor. |
|
Vgl. auch Aufgabe 14 für eine Vertiefung der Vererbung in einem umfangreicheren Anwendungsbeispiel. |
|
|
|
22.3.3 Lösung |
|
Klasse Aufgabe07 |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class Aufgabe07 {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
Objekt der Superklasse |
|
|
Fahrzeug f = new Fahrzeug(1, "MAN", 2015);
|
|
|
System.out.println("--- Fahrzeug ---");
|
|
|
f.anzeigen();
|
|
Objekt der Subklasse |
|
|
PKW p = new PKW(2, "VW", 2022, 5, "Kombi");
|
|
|
System.out.println("\n--- PKW ---");
|
|
|
p.anzeigen();
|
|
|
}
|
|
|
}
|
|
Klasse Fahrzeug |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class Fahrzeug {
|
|
|
int fzNr;
|
|
|
String hersteller;
|
|
|
int baujahr;
|
|
Konstruktor mit Parameterübergabe. |
|
|
public Fahrzeug(int fzNr, String hersteller, int baujahr) {
|
|
|
this.fzNr = fzNr;
|
|
|
this.hersteller = hersteller;
|
|
|
this.baujahr = baujahr;
|
|
|
}
|
|
Methode zur Ausgabe |
|
|
void anzeigen() {
|
|
|
System.out.println("Fahrzeugnummer: " + fzNr);
|
|
|
System.out.println("Hersteller: " + hersteller);
|
|
|
System.out.println("Baujahr: " + baujahr);
|
|
|
}
|
|
|
}
|
|
Klasse PKW |
|
|
package fahrzeuge;
|
|
|
|
|
|
public class PKW extends Fahrzeug {
|
|
|
int sitze;
|
|
|
String typ;
|
|
Konstruktor in der Subklasse. Mit Hilfe des Schlüsselworts super kann der Konstruktor der Superklasse integriert werden |
|
|
public PKW(int fzNr, String hersteller, int baujahr, int sitze, String typ) {
|
|
|
super(fzNr, hersteller, baujahr);
|
|
|
this.sitze = sitze;
|
|
|
this.typ = typ;
|
|
|
}
|
|
Methode überschreiben (Override). Die Attribute der Superklasse werden wieder mit super hinzugenommen. |
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
super.anzeigen();
|
|
|
System.out.println("Sitze: " + sitze);
|
|
|
System.out.println("Typ: " + typ);
|
|
|
}
|
|
|
}
|
|
22.3.4 Ergebnis Programmlauf |
|
|
--- Fahrzeug ---
|
|
|
Fahrzeugnummer: 1
|
|
|
Hersteller: MAN
|
|
|
Baujahr: 2015
|
|
|
|
|
|
--- PKW ---
|
|
|
Fahrzeugnummer: 2
|
|
|
Hersteller: VW
|
|
|
Baujahr: 2022
|
|
|
Sitze: 5
|
|
|
Typ: Kombi
|
|
22.3.5 Betrachtete Themen |
|
- Annotation @Override
- Attribute
- Aufruf des Superklassen-Konstruktors mit super(...)
- Aufruf einer überschriebenen Superklassenmethode mit super.anzeigen()
- geerbte Attribute
- geerbte Methoden
- Generalisierung
- Klassen und Objekte
- Konsolenausgabe mit System.out.println()
- Konstruktor der Superklasse
- Konstruktoren mit Parameterliste
- Methoden
- Methodenaufruf
- Superklasse
- Objekterzeugung mit new
- Schlüsselwort extends
- Spezialisierung
- Überschreiben von Methoden
- Subklasse
- Vererbung
- Wiederverwendung von Programmcode
- zusätzliche Attribute in Subklassen
|
|
22.3.6 Erläuterung |
|
Diese Aufgabe zeigt ein einfaches Beispiel für das Konzept Vererbung der objektorientierten Theorie. Die Idee hinter dem Vererbungskonzept ist: Gemeinsame Attribute und Methoden werden in einer Superklasse gespeichert. Spezielle Subklassen erweitern diese Superklasse um zusätzliche Eigenschaften und Methoden. |
|
Im Beispiel bedeutet das: |
|
- Ein PKW ist ebenfalls ein Fahrzeug.
- Deshalb übernimmt die Klasse PKW die Eigenschaften der Klasse Fahrzeug.
|
|
Die Methode void anzeigen() in Fahrzeug gibt die Fahrzeugdaten aus. Aufruf in Aufgabe07: f.anzeigen(); Das Objekt führt dann seine eigene Methode aus. |
|
Die Subklasse PKW entsteht durch diese Anweisung: public class PKW extends Fahrzeug. Das Schlüsselwort extends bedeutet, dass die Klasse PKW von der Klasse Fahrzeug Attribute und Methoden erbt. Die Klasse PKW hat zusätzlich die Attrribute int sitze und String typ. |
|
Im Konstruktor der Subklasse ... |
|
|
public PKW(int fzNr, String hersteller,
|
|
|
int baujahr, int sitze, String typ)
|
|
... werden sowohl die geerbten Attribute als auch die neuen Attribute übergeben. |
|
Mit super(...) wird der Konstruktor der Superklasse aufgerufen. Dies bedeutet, die Superklasse übernimmt selbst die Initialisierung ihrer Attribute. Danach werden die zusätzlichen PKW-Attribute gesetzt. |
|
Methoden überschreiben (Override) |
|
Die Methode anzeigen() existiert bereits in der Superklasse. In PKW wird sie erneut definiert. Das ist entlang einer Vererbungshierachie möglich und wird Überschreiben bzw. Override genannt. Die Subklasse ersetzt damit die geerbte Methode durch eine eigene Version. Mit super.anzeigen() in der Klasse PKW wird zuerst die Methode der Superklasse ausgeführt. |
|
Zusammenfassung |
|
Die Klasse PKW erweitert die Klasse Fahrzeug. Dadurch können gemeinsame Eigenschaften zentral gespeichert werden. Die Vererbung vermeidet doppelte Programmierung und macht Programme übersichtlicher und leichter erweiterbar. |
|
22.4 Aufgabe 8 - Kapselung |
|
Kapselung durch Zugriffsmodifizierer |
|
22.4.1 Aufgabenstellung |
|
Richte ein Klasse Stud mit den privaten Attributen name, matrNr, semester und studiengang ein und demonstriere Getter- und Setter-Zugriffe. Stelle sicher, dass bei einer Semesterzahl > 15 die Fehlermeldung "Ungültiges Semester" folgt. |
|
Erstelle für die Attribute passende Getter- und Setter-Methoden. Der Setter für semester soll überprüfen, ob das Semester gültig ist. Es soll gelten: |
|
- Semester muss größer als 0 sein
- Semester darf maximal 15 sein
|
|
Falls ein ungültiger Wert eingegeben wird, soll eine Fehlermeldung erscheinen. |
|
Erstelle eine Klasse Aufgabe08 mit einer main()-Methode. Darin soll: |
|
- ein Objekt der Klasse Stud erzeugt werden
- die Attribute über Setter beschrieben werden
- die Werte über Getter ausgegeben werden
|
|
So soll die Ausgabe aussehen: |
|
|
Name: Müller
|
|
|
Matrikelnummer: 12345
|
|
|
Semester: 3
|
|
|
Studiengang: Informatik
|
|
22.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie, Attribute und Methoden mithilfe von Zugriffsmodifizierern zu schützen. Sie verstehen, wie die Sichtbarkeit von Klassenbestandteilen gesteuert wird und warum Kapselung ein wichtiges Prinzip der objektorientierten Programmierung ist. Dadurch vertiefen Sie Ihr Verständnis für den sicheren und kontrollierten Zugriff auf Objektdaten. |
|
Vgl. zur Vertiefung Aufgabe 13. |
|
|
|
22.4.3 Lösung |
|
Klasse Stud |
|
|
class Stud {
|
|
Private Attribute, die damit geschützt sind (->Sichtbarkeitsmodifizierer) |
|
|
private String name;
|
|
|
private int matrNr;
|
|
|
private int semester;
|
|
|
private String studiengang;
|
|
Getter und Setter für das Attribut name. |
|
|
public String getName() {
|
|
|
return name;
|
|
|
}
|
|
|
public void setName(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
Getter und Setter für das Attribut matrNr (Matrikelnummer). |
|
|
public int getMatrNr() {
|
|
|
return matrNr;
|
|
|
}
|
|
|
public void setMatrNr(int matrNr) {
|
|
|
this.matrNr = matrNr;
|
|
|
}
|
|
Getter und Setter für das Attribut semester. Mit Prüfung, ob Semesteranzahl korrekt. |
|
|
public int getSemester() {
|
|
|
return semester;
|
|
|
}
|
|
|
public void setSemester(int semester) {
|
|
|
if (semester > 0 amp;amp; semester <= 15) {
|
|
|
this.semester = semester;
|
|
|
} else {
|
|
|
System.out.println("Ungültiges Semester!");
|
|
|
}
|
|
|
}
|
|
Getter und Setter für das Attribut studiengang. |
|
|
public String getStudiengang() {
|
|
|
return studiengang;
|
|
|
}
|
|
|
public void setStudiengang(String studiengang) {
|
|
|
this.studiengang = studiengang;
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe08 (HP) |
|
|
public class Aufgabe08 {
|
|
|
public static void main(String[] args) {
|
|
|
Stud s = new Stud();
|
|
|
|
|
|
s.setName("Müller");
|
|
|
s.setMatrNr(12345);
|
|
|
s.setSemester(3);
|
|
|
s.setStudiengang("Informatik");
|
|
|
|
|
|
System.out.println("Name: " + s.getName());
|
|
|
System.out.println("Matrikelnummer: " + s.getMatrNr());
|
|
|
System.out.println("Semester: " + s.getSemester());
|
|
|
System.out.println("Studiengang: " + s.getStudiengang());
|
|
|
}
|
|
|
}
|
|
22.4.4 Betrachtete Themen |
|
- Attribute
- Datenzugriff über Methoden
- Getter-Methoden
- if-Anweisung
- Informationsverbergung
- Kapselung
- Klassen
- Konsolenausgaben
- logische Operatoren (amp;amp;)
- Methoden mit Rückgabewert
- Methoden ohne Rückgabewert (void)
- Methodenaufrufe
- Objekte
- Objekterzeugung mit new
- Objektorientierte Datenverwaltung
- Plausibilitätsprüfung
- private
- public
- Schutz von Attributen
- Setter-Methoden
- Sichtbarkeitsmodifizierer
- Validierung von Eingabewerten
|
|
22.4.5 Erläuterung |
|
In dieser Aufgabe wird gezeigt, wie in Java mit privaten Attributen, Gettern und Settern gearbeitet wird. Alle Attribute der Klasse Stud sind mit dem Modifizierer private geschützt. Dadurch kann von außen nicht direkt auf sie zugegriffen werden. Der Zugriff erfolgt ausschließlich über die sogenannten Getter- und Setter-Methoden. |
|
Im Hauptprogramm wird ein Objekt der Klasse Stud erzeugt. Anschließend werden die Attribute mit Setter-Methoden beschrieben und mit Getter-Methoden wieder ausgegeben. |
|
Dabei können auch Kontrollen der Eingaben einbebaut werden. Dies wird bei der Methode setSemester() gezeigt. Dort wird geprüft, ob das angegebene Semester zwischen 1 und 15 liegt. Wird ein ungültiger Wert eingegeben, erscheint die Meldung Ungültiges Semester. |
|
Insgesamt zeigt damit das Projekt an einem einfachen Beispiel: |
|
- Datenkapselung
- Zugriffsschutz mit private
- Verwendung von Getter- und Setter-Methoden
- einfache Plausibilitätsprüfungen in Methoden
- Objekterzeugung und Methodennutzung in Java
|
|
22.5 Aufgabe 9 - Overload |
|
Methoden überladen |
|
22.5.1 Aufgabenstellung |
|
Erstellen Sie ein Java-Programm zur Verwaltung von Studierendendaten. Legen Sie eine Klasse Stud mit folgenden Attributen des Typs private an: |
|
- name
- matrNr
- semester
- studiengang
|
|
Erstellen Sie für alle Attribute passende Getter- und Setter-Methoden. Zum Beispiel: |
|
|
public String getName()
|
|
|
public void setName(String name)
|
|
Erstellen Sie mehrere Methoden mit der Bezeichnung anzeigen(), die unterschiedliche Parameterlisten besitzen, womit eine Methodenüberladung entsteht: |
|
- Variante 1 - Keine Parameter. Die Methode soll alle Daten des Studierenden ausgeben.
- Variante 2 - Boolean-Parameter, z.B. anzeigen(boolean nurName). Ist der Parameter true, soll nur der Name ausgegeben werden. Ist der Parameter false, sollen alle Daten ausgegeben werden. Hinweis: Die Methode darf die parameterlose Methode anzeigen() erneut aufrufen.
- Variante 3 - Textparameter, z.B. anzeigen(String text). Die Methode soll einen frei wählbaren Text zusammen mit dem Namen ausgeben. Beispiel: "Student: Müller".
- Variante 4 - Zwei Parameter, z.B. anzeigen(String text, int semester). Die Methode soll einen Text, den Namen und das Semester ausgeben. Beispiel: "Info: Müller (Semester 3)"
|
|
Erstellen Sie zusätzlich eine Klasse Aufgabe09 mit einer main()-Methode. Im Hauptprogramm erzeugen Sie ein Objekt der Klasse Stud, beschreiben das Objekt mit Hilfe der Setter-Methoden und rufen anschließend alle Varianten der Methode anzeigen() auf. Zum Beispiel mit folgendem Ergebnis: |
|
22.5.2 Ergebnis Programmlauf: |
|
|
Strolch, 54321, 3, Informatik
|
|
|
Name: Strolch
|
|
|
Student: Strolch
|
|
|
Info: Strolch (Semester 3)
|
|
22.5.3 Lernziele |
|
In dieser Aufgabe lernen Sie, Methoden zu überladen (Overload), indem Sie mehrere Methoden mit demselben Namen, aber unterschiedlichen Parameterlisten definieren. Sie verstehen, wie dadurch verschiedene Varianten einer Funktion bereitgestellt werden können. |
|
22.5.4 Lösung |
|
Klasse Stud |
|
|
package studierende;
|
|
|
|
|
|
class Stud {
|
|
|
private String name;
|
|
|
private int matrNr;
|
|
|
private int semester;
|
|
|
private String studiengang;
|
|
Getter und Setter |
|
|
public String getName() { return name; }
|
|
|
public void setName(String name) { this.name = name; }
|
|
|
|
|
|
public int getMatrNr() { return matrNr; }
|
|
|
public void setMatrNr(int matrNr) { this.matrNr = matrNr; }
|
|
|
|
|
|
public int getSemester() { return semester; }
|
|
|
public void setSemester(int semester) { this.semester = semester; }
|
|
|
|
|
|
public String getStudiengang() { return studiengang; }
|
|
|
public void setStudiengang(String studiengang) { this.studiengang = studiengang; }
|
|
Überladene Methoden anzeigen() 1. keine Parameter -> alle Daten anzeigen |
|
|
public void anzeigen() {
|
|
|
System.out.println(name + ", " + matrNr + ", " + semester + ", " + studiengang);
|
|
|
}
|
|
2. nur Name anzeigen |
|
|
public void anzeigen(boolean nurName) {
|
|
|
if (nurName) {
|
|
|
System.out.println("Name: " + name);
|
|
|
} else {
|
|
|
anzeigen(); // ruft Methode 1 auf
|
|
|
}
|
|
|
}
|
|
3. frei wählbarer Text + Name |
|
|
public void anzeigen(String text) {
|
|
|
System.out.println(text + ": " + name);
|
|
|
}
|
|
4. zwei Parameter -> Name und Semester |
|
|
public void anzeigen(String text, int semester) {
|
|
|
System.out.println(text + ": " + name + " (Semester " + semester + ")");
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe09 |
|
|
Package studierende;
|
|
|
|
|
|
public class Aufgabe09 {
|
|
|
public static void main(String[] args) {
|
|
Werte eintragen |
|
|
Stud s = new Stud();
|
|
|
s.setName("Strolch");
|
|
|
s.setMatrNr(54321);
|
|
|
s.setSemester(3);
|
|
|
s.setStudiengang("Informatik");
|
|
|
|
|
Aufrufe der überladenen Methoden |
|
|
s.anzeigen(); // alle Daten
|
|
|
s.anzeigen(true); // nur Name
|
|
|
s.anzeigen("Student"); // Text + Name
|
|
|
s.anzeigen("Info", s.getSemester()); // Text + Name + Semester
|
|
|
}
|
|
|
}
|
|
22.5.5 Betrachtete Themen |
|
- boolean-Parameter
- Getter-Methoden
- gleiche Methodennamen
- if-Anweisung
- int-Parameter
- Kapselung
- Klassen
- Konsolenausgabe mit System.out.println()
- Methoden
- Methodenaufrufe
- Methodensignatur
- Methodenüberladung
- Objekte
- Overload
- Parameter
- private Attribute
- Setter-Methoden
- String-Parameter
- unterschiedliche Parameterlisten
- Wiederverwendung einer Methode innerhalb derselben Klasse
- Zugriff auf Objektattribute innerhalb von Methoden
|
|
22.5.6 Erläuterung |
|
Mehrere Methoden dürfen denselben Namen besitzen, wenn sich ihre Parameterlisten unterscheiden. Beispiele: |
|
|
anzeigen()
|
|
|
anzeigen(boolean nurName)
|
|
|
anzeigen(String text)
|
|
|
anzeigen(String text, int semester)
|
|
Java erkennt beim Aufruf automatisch, welche Methode gemeint ist. |
|
23 Übungsaufgaben Teil 4 |
|
Jetzt nochmals einführende Aufgaben, wieder inhaltlich von vorne beginnend. |
|
|
|
23.1 Aufgabe 10 - Einstieg |
|
Erste Klasse und erstes Objekt. |
|
23.1.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Student mit den Attributen: |
|
- name vom Typ String
- alter vom Typ int
|
|
Implementieren Sie außerdem eine Methode vorstellen(), die den Namen und das Alter auf der Konsole ausgibt. Schreiben Sie danach ein Hauptprogramm mit der Bezeichnung Test, in dem: |
|
- ein Objekt der Klasse Student erzeugt wird
- die Attribute gesetzt werden
- die Methode vorstellen() aufgerufen wird
|
|
23.1.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine eigene Klasse mit Attributen und Methoden zu erstellen und Objekte dieser Klasse zu erzeugen. Sie verstehen, wie Objekte Daten speichern und über Methoden auf diese Daten zugreifen können. Dadurch erwerben Sie die Grundlagen für die objektorientierte Programmierung in Java. |
|
|
|
23.1.3 Lösung |
|
|
package studierende;
|
|
|
|
|
|
class Student {
|
|
|
String name;
|
|
|
int alter;
|
|
|
|
|
|
void vorstellen() {
|
|
|
System.out.println("Ich heiße " + name + " und bin " + alter + " Jahre alt.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Test {
|
|
|
public static void main(String[] args) {
|
|
|
Student s1 = new Student();
|
|
|
s1.name = "Anna";
|
|
|
s1.alter = 20;
|
|
|
|
|
|
s1.vorstellen();
|
|
|
}
|
|
|
}
|
|
Anmerkung: In Java dürfen mehrere Klassen in einer Datei stehen. Dabei darf jedoch nur eine Klasse als public deklariert werden. Testen Sie deshalb hin und wieder die Unterbringung aller Klassen in einer einzigen Datei. |
|
23.1.4 Betrachtete Themen |
|
- Attributbelegung
- Attribute
- Datentypen (String, int)
- Hauptprogramm (main())
- Instanziierung
- Klassen
- Klassen als Baupläne
- Konsolenausgabe mit System.out.println()
- Methoden
- Methodenaufrufe
- Objekte
- Objekte als Instanzen einer Klasse
- Objekterzeugung
- Objektzugriff mit dem Punktoperator
- Referenzvariablen
- Verwendung von new
|
|
23.1.5 Ergebnis Programmlauf |
|
|
Ich heiße Anna und bin 20 Jahre alt.
|
|
|
|
23.2 Aufgabe 11 - Konstruktoren |
|
Konstruktoren mit Parametern |
|
23.2.1 Aufgabenstellung |
|
Erweitern Sie die Klasse Student |
|
|
class Student {
|
|
|
String name;
|
|
|
int alter;
|
|
|
...
|
|
so, dass Name und Alter bereits beim Erzeugen des Objekts übergeben werden. Dazu soll ein Konstruktor implementiert werden. |
|
Erzeugen Sie im Hauptprogramm ein Objekt der Klasse Student mit Hilfe des Konstruktors und geben Sie die Daten mit einer Methode vorstellen() aus. |
|
23.2.2 Lernziele |
|
In dieser Aufgabe lernen Sie, Konstruktoren mit Parametern zu implementieren und Objekte bereits beim Erzeugen mit Anfangswerten zu initialisieren. Sie verstehen, wie Werte an einen Konstruktor übergeben und den Attributen eines Objekts zugewiesen werden. Dadurch vertiefen Sie Ihr Verständnis für die strukturierte Initialisierung von Objekten. |
|
|
|
23.2.3 Lösung |
|
|
package studierende;
|
|
|
class Student {
|
|
|
String name;
|
|
|
int alter;
|
|
|
|
|
|
Student(String name, int alter) {
|
|
|
this.name = name;
|
|
|
this.alter = alter;
|
|
|
}
|
|
|
|
|
|
void vorstellen() {
|
|
|
System.out.println("Ich heiße " + name + " und bin " + alter + " Jahre alt.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Test {
|
|
|
public static void main(String[] args) {
|
|
|
Student s1 = new Student("Max", 22);
|
|
|
s1.vorstellen();
|
|
|
}
|
|
|
}
|
|
23.2.4 Ergebnis Programmlauf |
|
|
Ich heiße Max und bin 22 Jahre alt.
|
|
23.2.5 Betrachtete Themen |
|
- Attribute
- Hauptprogramm (main())
- Initialisierung von Objekten
- Instanziierung
- Klassen
- Konsolenausgabe
- Konstruktoraufruf
- Konstruktoren
- Konstruktorparameter
- Methoden
- Methodenaufruf
- Objekte
- Objekterzeugung mit new
- Parameterübergabe
- Referenzvariablen
- Unterschied zwischen Attributen und Parametern
- Verwendung von this
|
|
|
|
23.3 Aufgabe 12 - Array |
|
Array von Objekten |
|
23.3.1 Aufgabenstellung |
|
Erstellen Sie mehrere Objekte der Klasse Student und speichern Sie diese in einem Array. Legen Sie ein Array für drei Studierende an. Erzeugen Sie anschließend drei Objekte der Klasse Student, speichern Sie diese im Array und vergeben Sie die Namen: |
|
|
|
|
Geben Sie danach alle Studierenden mit einer Schleife aus. |
|
23.3.2 Lernziele |
|
In dieser Aufgabe lernen Sie, mehrere Objekte in einem Array zu verwalten. Sie verstehen, wie Objektreferenzen in einem Array gespeichert, auf die einzelnen Elemente zugegriffen und deren Methoden aufgerufen werden können. |
|
23.3.3 Ergebnis Programmlauf |
|
|
Student: Anna
|
|
|
Student: Ben
|
|
|
Student: Clara
|
|
|
|
23.3.4 Lösung |
|
|
package studierende;
|
|
|
|
|
|
class Student {
|
|
|
String name;
|
|
|
|
|
|
Student(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("Student: " + name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Test {
|
|
|
public static void main(String[] args) {
|
|
|
Student[] gruppe = new Student[3];
|
|
|
|
|
|
gruppe[0] = new Student("Anna");
|
|
|
gruppe[1] = new Student("Ben");
|
|
|
gruppe[2] = new Student("Clara");
|
|
|
|
|
|
for (Student s : gruppe) {
|
|
|
s.anzeigen();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
23.3.5 Betrachtete Themen |
|
- Array-Indizes
- Arrays
- Attribute
- ForEach-Schleife
- Instanziierung mit new
- Iteration über Datenstrukturen
- Klassen
- Konstruktoren
- Methoden
- Objektarrays
- Objekte
- Objektverwaltung mit Arrays
- Punktnotation
- Referenzen
- Referenzen in Arrays
- Speicherung von Objekten in Datenstrukturen
|
|
23.3.6 Erläuterung |
|
Die Anweisung |
|
|
Student[] gruppe = new Student[3];
|
|
erzeugt ein Array für drei Objekte der Klasse Student. Wichtig ist: Zu diesem Zeitpunkt existieren die drei Studierenden noch nicht. Das Array enthält zunächst: |
|
|
null
|
|
|
null
|
|
|
null
|
|
Erst durch die Anweisungen |
|
|
gruppe[0] = new Student("Anna");
|
|
|
gruppe[1] = new Student("Ben");
|
|
|
gruppe[2] = new Student("Clara");
|
|
werden die Objekte erzeugt und im Array gespeichert. Vereinfacht dargestellt: |
|
|
gruppe[0] --> Student("Anna")
|
|
|
gruppe[1] --> Student("Ben")
|
|
|
gruppe[2] --> Student("Clara")
|
|
Das Array enthält also nicht die Objekte selbst, sondern Referenzen auf diese Objekte. |
|
Theorieaspekte |
|
Diese Aufgabe verbindet zwei wichtige Konzepte: |
|
|
|
|
Sie zeigt, wie man mehrere Objekte gemeinsam in einer Datenstruktur verwaltet und mit einer Schleife verarbeitet. Das ist eine wichtige Grundlage für spätere Themen wie: |
|
- Objektverknüpfungen
- Listen (ArrayList)
- Sammlungen (Collections)
- 1:n-Beziehungen
- n:m-Beziehungen
|
|
Und stellt damit den Übergang von einzelnen Objekten zur Verwaltung größerer Objektmengen dar. |
|
|
|
23.4 Aufgabe 13 - Kapselung |
|
Encapsulation |
|
23.4.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Konto mit einem privaten Attribut kontostand vom Typ double. Implementieren Sie dazu: |
|
- eine Methode einzahlen(double betrag), die den Kontostand erhöht
- eine Methode getKontostand(), die den aktuellen Kontostand zurückgibt
|
|
Testen Sie die Klasse in einer main-Methode. Führen Sie mehrere Einzahlungen durch und geben Sie anschließend den aktuellen Kontostand aus. |
|
23.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie das Konzept der Kapselung in Java kennen. Sie verstehen, wie Attribute durch geeignete Zugriffsrechte geschützt und über Methoden kontrolliert zugänglich gemacht werden. Dadurch vertiefen Sie Ihr Verständnis für den sicheren und übersichtlichen Aufbau von Klassen. |
|
|
|
23.4.3 Lösung |
|
|
package banken;
|
|
|
|
|
|
class Konto {
|
|
|
private double kontostand;
|
|
|
public void einzahlen(double betrag) {
|
|
|
kontostand = kontostand + betrag;
|
|
|
}
|
|
|
public double getKontostand() {
|
|
|
return kontostand;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe13 {
|
|
|
public static void main(String[] args) {
|
|
|
Konto k = new Konto();
|
|
|
k.einzahlen(100.0);
|
|
|
k.einzahlen(50.0);
|
|
|
System.out.println("Kontostand: " + k.getKontostand());
|
|
|
}
|
|
|
}
|
|
23.4.4 Ergebnis Programmlauf |
|
|
Kontostand: 150.0
|
|
23.4.5 Betrachtete Themen |
|
- Attribute
- Datenverbergung (Information Hiding)
- Getter-Methode
- Kapselung
- Klassen
- Methoden
- Methoden mit Parametern
- Methoden mit Rückgabewert
- Objekte
- Objektorientierte Modellierung
- private
- public
- Sichtbarkeitsmodifizierer
- Zugriffsschutz
- Zustandsänderung von Objekten
|
|
23.4.6 Erläuterung |
|
Das Attribut private double kontostand; ist private. Es kann deshalb nicht direkt von außen angesprochen werden. Nicht möglich wäre: |
|
|
k.kontostand = 1000.0; // nicht erlaubt!
|
|
Der Zugriff erfolgt ausschließlich über die öffentlichen Methoden: |
|
|
k.einzahlen(100.0);
|
|
und |
|
|
k.getKontostand();
|
|
Dadurch kontrolliert die Klasse selbst, wie ihr Zustand verändert werden darf. |
|
Theorieaspekte |
|
Diese Aufgabe führt ein wichtiges Prinzip der objektorientierten Programmierung ein: Kapselung (Encapsulation). Mit ihm werden Daten eines Objekts vor direktem Zugriff geschützt und können nur über definierte Methoden gelesen oder verändert werden. Dadurch |
|
- bleiben Objekte konsistent,
- werden Fehlbedienungen verhindert,
- kann die interne Implementierung später geändert werden, ohne andere Programmteile anzupassen.
|
|
23.5 Aufgabe 14 - Vererbung |
|
Attribute und Methoden weitergebe |
|
23.5.1 Aufgabenstellung |
|
Erstellen Sie eine Superklasse Person mit dem Attribut String name; sowie der Methode void vorstellen(). Die Methode soll den Namen der Person ausgeben. |
|
Leiten Sie davon eine Klasse Student ab. Diese soll zusätzlich das Attribut String studiengang; besitzen. Implementieren Sie außerdem eine Methode |
|
|
void anzeigen()
|
|
zur Ausgabe des Studiengangs. |
|
Schreiben Sie ein Hauptprogramm Aufgabe14, in dem ein Objekt der Klasse Student erzeugt, mit Daten versehen und getestet wird. |
|
23.5.2 Lernziele |
|
In dieser Aufgabe lernen Sie das Konzept der Vererbung in Java kennen. Sie verstehen, wie eine Unterklasse Eigenschaften und Methoden einer Oberklasse übernimmt und diese um eigene Merkmale erweitern kann. |
|
|
|
23.5.3 Lösung |
|
|
package personen;
|
|
|
|
|
|
class Person {
|
|
|
String name;
|
|
|
void vorstellen() {
|
|
|
System.out.println("Ich heiße " + name + ".");
|
|
|
}
|
|
|
}
|
|
|
class Student extends Person {
|
|
|
String studiengang;
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(name + " studiert " + studiengang + ".");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe14 {
|
|
|
public static void main(String[] args) {
|
|
|
Student s = new Student();
|
|
|
s.name = "Paula";
|
|
|
s.studiengang = "Informatik";
|
|
|
|
|
|
s.vorstellen();
|
|
|
s.anzeigen();
|
|
|
}
|
|
|
}
|
|
23.5.4 Ergebnis Programmlauf |
|
|
Ich heiße Paula.
|
|
|
Paula studiert Informatik.
|
|
23.5.5 Betrachtete Themen |
|
- Basisklasse
- Geerbte Attribute
- Geerbte Methoden
- Generalisierung
- Instanziierung mit new
- Klassenhierarchien
- Methodenaufrufe
- Superklasse
- Objekte
- Objektorientierte Modellierung
- Schlüsselwort extends
- Spezialisierung
- Subklasse
- Vererbung
- Wiederverwendung von Programmcode
|
|
23.5.6 Erläuterung |
|
Die Klasse Student wird von der Klasse Person abgeleitet: |
|
|
class Student extends Person
|
|
Dadurch übernimmt Student automatisch alle Attribute und Methoden der Superklasse. Die Klasse Person definiert: |
|
String name; und void vorstellen() |
|
Diese Elemente stehen deshalb auch einem Objekt der Klasse Student zur Verfügung. Deshalb ist folgende Anweisung möglich: |
|
|
s.name = "Paula";
|
|
obwohl das Attribut name nicht in der Klasse Student definiert wurde. Ebenso kann die Methode s.vorstellen(); aufgerufen werden, obwohl sie nur in der Klasse Person implementiert ist. |
|
Theorieaspekte |
|
Diese Aufgabe demonstriert das Konzept der Vererbung. Es wird gezeigt, dass gemeinsame Eigenschaften in einer Superklasse zusammengefasst werden können. Spezielle Eigenschaften werden dann in Subklassen ergänzt. Dadurch wird: |
|
- Programmcode wiederverwendet,
- Redundanz vermieden,
- eine Klassenhierarchie aufgebaut.
|
|
|
|
23.6 Aufgabe 15 - Override |
|
Methoden überschreiben |
|
23.6.1 Aufgabenstellung |
|
Verwenden Sie wieder die Klassen Person und Student. Die Methode vorstellen() soll in der Klasse Student überschrieben werden, sodass zusätzlich der Studiengang ausgegeben wird. |
|
Verwenden Sie dabei die Annotation @Override. Testen Sie das Verhalten im Hauptprogramm Aufgabe15. |
|
23.6.2 Lernziele |
|
In dieser Aufgabe lernen Sie, Methoden einer Oberklasse in einer Unterklasse zu überschreiben (Override). Sie verstehen, wie das Verhalten geerbter Methoden an die Anforderungen einer Unterklasse angepasst werden kann und wie dadurch die Wiederverwendung und Erweiterung von Klassen unterstützt wird. |
|
|
|
23.6.3 Lösung |
|
|
package personen;
|
|
|
|
|
|
class Person {
|
|
|
String name;
|
|
|
void vorstellen() {
|
|
|
System.out.println("Ich heiße " + name + ".");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Student extends Person {
|
|
|
String studiengang;
|
|
|
|
|
|
@Override
|
|
|
void vorstellen() {
|
|
|
System.out.println("Ich heiße " + name + " und studiere " + studiengang + ".");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe15 {
|
|
|
public static void main(String[] args) {
|
|
|
Student s = new Student();
|
|
|
s.name = "Tom";
|
|
|
s.studiengang = "Wirtschaftsinformatik";
|
|
|
s.vorstellen();
|
|
|
}
|
|
|
}
|
|
23.6.4 Ergebnis Programmlauf |
|
|
Ich heiße Tom und studiere Wirtschaftsinformatik.
|
|
23.6.5 Betrachtete Themen |
|
- Annotation @Override
- Dynamische Bindung
- Methodenaufrufe
- Methodenüberschreibung (Override)
- Superklasse
- Objektorientierte Modellierung
- Polymorphes Verhalten
- Spezialisierung von Verhalten
- Überschreiben geerbter Methoden
- Subklasse
- Vererbung
- Wiederverwendung von Programmcode
|
|
23.6.6 Erläuterung |
|
Die Klasse Student erbt die Methode void vorstellen() zunächst von der Klasse Person. Durch die eigene Implementierung |
|
|
@Override
|
|
|
void vorstellen() {
|
|
|
...
|
|
|
}
|
|
wird die geerbte Methode ersetzt. Man spricht vom Überschreiben einer Methode oder von Override. Die neue Implementierung wird immer dann ausgeführt, wenn die Methode für ein Objekt der Klasse Student aufgerufen wird. |
|
Die Annotation @Override |
|
Die Annotation @Override ist nicht zwingend erforderlich, wird aber empfohlen. Sie informiert den Compiler darüber, dass eine geerbte Methode überschrieben werden soll. Wird dabei versehentlich eine falsche Methodensignatur verwendet, erkennt der Compiler den Fehler sofort. |
|
Beispiel: |
|
|
@Override
|
|
|
void vorstelllen() {
|
|
|
}
|
|
Der Schreibfehler würde vom Compiler erkannt werden. |
|
Theorieaspekte |
|
Diese Aufgabe führt erstmals das Überschreiben von Methoden ein. Es wird gezeigt, dass eine Subklasse nicht nur neue Attribute und Methoden hinzufügen kann, sondern auch das Verhalten geerbter Methoden verändern darf. Dadurch können allgemeine Eigenschaften in einer Superklasse definiert und in den Subklassen spezialisiert werden. |
|
|
|
23.7 Aufgabe 16 - Polymorphie |
|
Zur Laufzeit die passende Methode |
|
23.7.1 Aufgabenstellung |
|
Erstellen Sie eine Superklasse Tier mit der Methode lautGeben(). Leiten Sie davon zwei Klassen ab: Hund und Katze. Überschreiben Sie die Methode jeweils passend. Katzen sagen Miau, Hunde sagen Wuff. |
|
Speichern Sie mehrere Tier-Objekte in einem Array vom Typ Tier und lassen Sie alle Tiere ihre Laute ausgeben. |
|
23.7.2 Ergebnis Programmlauf |
|
|
Wuff
|
|
|
Miau
|
|
|
Wuff
|
|
23.7.3 Lernziele |
|
In dieser Aufgabe lernen Sie das Konzept der Polymorphie in Java kennen. Sie verstehen, wie eine Referenzvariable der Oberklasse auf Objekte verschiedener Unterklassen verweisen kann und wie dabei zur Laufzeit automatisch die jeweils passende Methode aufgerufen wird. |
|
|
|
23.7.4 Lösung |
|
|
package tiere;
|
|
|
|
|
|
class Tier {
|
|
|
void lautGeben() {
|
|
|
System.out.println("Unbekanntes Tiergeräusch");
|
|
|
}
|
|
|
}
|
|
|
class Hund extends Tier {
|
|
|
@Override
|
|
|
void lautGeben() {
|
|
|
System.out.println("Wuff");
|
|
|
}
|
|
|
}
|
|
|
class Katze extends Tier {
|
|
|
@Override
|
|
|
void lautGeben() {
|
|
|
System.out.println("Miau");
|
|
|
}
|
|
|
}
|
|
|
public class Aufgabe16 {
|
|
|
public static void main(String[] args) {
|
|
|
Tier[] tiere = new Tier[3];
|
|
|
tiere[0] = new Hund();
|
|
|
tiere[1] = new Katze();
|
|
|
tiere[2] = new Hund();
|
|
|
|
|
|
for (Tier t : tiere) {
|
|
|
t.lautGeben();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
23.7.5 Betrachtete Themen |
|
- Austauschbarkeit von Objekten
- Dynamische Bindung
- ForEach-Schleife
- Laufzeitbindung (Late Binding)
- Auswahl der passenden Methode zur Laufzeit
- Methodenüberschreibung (Override)
- Superklasse
- Superklassenreferenzen
- Objektarrays
- Objektorientierte Modellierung
- Polymorphie
- Subklassen
- Vererbung
|
|
23.7.6 Erläuterung |
|
Die zentrale Anweisung lautet: |
|
|
Tier[] tiere = new Tier[3];
|
|
Das Array besitzt den Typ Tier. Trotzdem werden darin unterschiedliche Objekte gespeichert: |
|
|
tiere[0] = new Hund();
|
|
|
tiere[1] = new Katze();
|
|
|
tiere[2] = new Hund();
|
|
Dies ist möglich, weil sowohl Hund als auch Katze von Tier erben. Beim Durchlaufen des Arrays wird immer dieselbe Anweisung verwendet: |
|
|
t.lautGeben();
|
|
Trotzdem entstehen unterschiedliche Ausgaben: |
|
|
Wuff
|
|
|
Miau
|
|
|
Wuff
|
|
Java entscheidet erst zur Laufzeit, welche Methode tatsächlich ausgeführt werden muss. |
|
Theorieaspekte |
|
Diese Aufgabe zeigt erstmals die eigentliche Stärke der Vererbung. Bei Aufgabe 15 wurde zwar bereits eine Methode überschrieben, die Methode wurde jedoch direkt über ein Objekt der Klasse Student aufgerufen: |
|
|
Student s = new Student();
|
|
|
s.vorstellen();
|
|
In der vorliegenden Aufgabe erfolgt der Aufruf dagegen über eine Referenz der Superklasse: |
|
|
Tier t;
|
|
beziehungsweise |
|
|
Tier[] tiere;
|
|
Dadurch wird sichtbar, dass dieselbe Referenzvariableunterschiedliche Objekttypen verwalten kann. Genau dies bezeichnet man als Polymorphie. |
|
23.7.7 Exkurs Polymorphie |
|
Polymorphie bedeutet in der objektorientierten Programmierung: |
|
Eine Referenzvariable vom Typ der Superklasse kann auf Objekte verschiedener Subklassen zeigen. |
|
Beim Methodenaufruf entscheidet Java nicht anhand des Typs der Referenzvariablen, sondern anhand des tatsächlichen Objekts, welche überschriebene Methode ausgeführt wird. Diese Entscheidung erfolgt erst zur Laufzeit und wird als dynamische Bindung bezeichnet. |
|
Beispielsweise: |
|
|
Fahrzeug f;
|
|
|
f = new PKW();
|
|
|
f.fahren();
|
|
|
|
|
|
f = new LKW();
|
|
|
f.fahren();
|
|
Obwohl immer dieselbe Referenzvariable verwendet wird, entstehen unterschiedliche Ergebnisse. Dies ist nur möglich, weil die Methode fahren() in den Subklassen überschrieben wurde. |
|
Ein weiteres Beispiel: |
|
|
class Fahrzeug {
|
|
|
void fahren() {
|
|
|
System.out.println("Ein Fahrzeug fährt.");
|
|
|
}
|
|
|
}
|
|
|
class PKW extends Fahrzeug {
|
|
|
@Override
|
|
|
void fahren() {
|
|
|
System.out.println("Der PKW fährt.");
|
|
|
}
|
|
|
}
|
|
|
class LKW extends Fahrzeug {
|
|
|
@Override
|
|
|
void fahren() {
|
|
|
System.out.println("Der LKW fährt.");
|
|
|
}
|
|
|
}
|
|
Dies erfordert im Programm: |
|
|
Fahrzeug f;
|
|
|
|
|
|
f = new PKW();
|
|
|
f.fahren();
|
|
|
|
|
|
f = new LKW();
|
|
|
f.fahren();
|
|
Ausgabe: |
|
|
Der PKW fährt.
|
|
|
Der LKW fährt.
|
|
Die Polymorphie steckt in dieser Zeile: |
|
|
Fahrzeug f;
|
|
Die Variable f hat den Typ Fahrzeug. Später verweist sie aber einmal auf ein PKW-Objekt und einmal auf ein LKW-Objekt: |
|
|
f = new PKW();
|
|
|
f = new LKW();
|
|
Dieselbe Variable kann also Objekte unterschiedlicher Klassen verwalten. |
|
Was passiert beim Methodenaufruf? |
|
|
f.fahren();
|
|
Der Compiler sieht nur: |
|
|
Fahrzeug f
|
|
Zur Laufzeit schaut Java aber nach: Auf welches Objekt zeigt f tatsächlich? Zeigt f auf einen PKW? |
|
|
f = new PKW();
|
|
Dann wird ausgeführt: |
|
|
PKW.fahren()
|
|
Zeigt f auf einen LKW? |
|
|
f = new LKW();
|
|
Dann wird ausgeführt: |
|
|
LKW.fahren()
|
|
Das nennt man dynamische Bindung oder spätes Binden (late binding). |
|
Beispiel mit dem Interface-Thema |
|
In einer der folgenden Aufgaben wird dieses Beispiel verwendet: |
|
|
interface Beweglich {
|
|
|
void bewegen();
|
|
|
}
|
|
|
|
|
|
class Mensch implements Beweglich {
|
|
|
public void bewegen() {
|
|
|
System.out.println("Der Mensch läuft.");
|
|
|
}
|
|
|
}
|
|
Wird dann programmiert ... |
|
|
Beweglich b = new Mensch();
|
|
|
b.bewegen();
|
|
... liegt ebenfalls Polymorphie vor. Die Variable besitzt den Typ Beweglich, verweist aber auf ein Objekt der Klasse Mensch. |
|
Zusammenhang mit Override |
|
Polymorphie wird besonders nützlich, wenn Methoden überschrieben werden: |
|
|
@Override
|
|
|
void fahren() {
|
|
|
...
|
|
|
}
|
|
Denn dann kann derselbe Aufruf f.fahren(); je nach tatsächlichem Objekt unterschiedliche Ergebnisse liefern. |
|
Zusammenfassung |
|
Bei einer Vererbung, z.B. wenn PKW und LKW von Fahrzeug erben, kann man schreiben: |
|
|
Fahrzeug f;
|
|
und später |
|
|
f = new PKW();
|
|
oder |
|
|
f = new LKW();
|
|
Wenn dieselbe Referenzvariable Objekte verschiedener Subklassen aufnehmen kann und der passende Methodenrumpf erst zur Laufzeit ausgewählt wird, spricht man von Polymorphie. |
|
24 Übungsaufgaben Teil 5 |
|
|
|
24.1 Aufgabe 17 - Abstrakte Klasse |
|
Gemeinsame Grundlage mehrerer Klassen |
|
24.1.1 Aufgabenstellung |
|
Erstellen Sie eine abstrakte Klasse Fahrzeug mit der abstrakten Methode fahren(). Leiten Sie davon eine Klasse Auto ab und implementieren Sie die Methode. |
|
Testen Sie die Klassen in einem Hauptprogramm Aufgabe17. Verwenden Sie dabei eine Referenz vom Typ Fahrzeug. |
|
24.1.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine abstrakte Klasse in Java zu erstellen und von ihr konkrete Klassen abzuleiten. Sie verstehen den Zweck abstrakter Klassen als gemeinsame Grundlage für mehrere Klassen und lernen, wie abstrakte Methoden in den Unterklassen implementiert werden. |
|
|
|
24.1.3 Lösung |
|
Klasse Fahrzeug |
|
|
package fahrzeuge;
|
|
|
abstract class Fahrzeug {
|
|
|
abstract void fahren();
|
|
|
}
|
|
|
|
|
Klasse Auto |
|
|
package fahrzeuge;
|
|
|
class Auto extends Fahrzeug {
|
|
|
@Override
|
|
|
void fahren() {
|
|
|
System.out.println("Das Auto fährt.");
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe17 |
|
|
package fahrzeuge;
|
|
|
public class Aufgabe17 {
|
|
|
public static void main(String[] args) {
|
|
|
Fahrzeug f = new Auto();
|
|
|
f.fahren();
|
|
|
}
|
|
|
}
|
|
24.1.4 Ergebnis Programmlauf |
|
|
Das Auto fährt.
|
|
24.1.5 Betrachtete Themen |
|
- Abstrakte Klassen
- Abstrakte Methoden
- Vererbung
- Superklasse
- Subklasse
- Spezialisierung
- Generalisierung
- Gemeinsame Superklasse
- Methodenüberschreibung (Override)
- Polymorphie
- Superklassenreferenzen
- Dynamische Bindung
- Instanziierung von Subklassen
- Objektorientierte Modellierung
|
|
24.1.6 Exkurs - Abstrakte Klasse |
|
Eine abstrakte Klasse ist eine Klasse, von der normalerweise keine direkten Objekte erzeugt werden. Sie dient als gemeinsame Grundlage für andere Klassen. |
|
Beispiel: |
|
|
abstract class Fahrzeug {
|
|
|
String marke;
|
|
|
}
|
|
Von Fahrzeug soll nur geerbt werden: |
|
|
class PKW extends Fahrzeug {
|
|
|
}
|
|
Der folgende Aufruf wäre nicht erlaubt: |
|
|
Fahrzeug f = new Fahrzeug(); // Fehler!
|
|
Eine abstrakte Methode ist eine Methode ohne Programmcode. Sie legt nur fest, dass eine Methode vorhanden sein muss. |
|
Beispiel: |
|
|
abstract class Fahrzeug {
|
|
|
abstract void fahren();
|
|
|
}
|
|
Die erbende Klasse muss die Methode dann konkret ausprogrammieren: |
|
|
class PKW extends Fahrzeug {
|
|
|
@Override
|
|
|
void fahren() {
|
|
|
System.out.println("Der PKW fährt.");
|
|
|
}
|
|
|
}
|
|
Es gilt: |
|
- Eine abstrakte Klasse kann normale und abstrakte Methoden enthalten.
- Enthält eine Klasse mindestens eine abstrakte Methode, muss auch die Klasse selbst als abstract gekennzeichnet werden.
|
|
|
|
24.2 Aufgabe 18 - Interface |
|
Beschreibung gemeinsamer Fähigkeiten |
|
24.2.1 Aufgabenstellung |
|
Erstellen Sie ein Interface Beweglich mit der Methode bewegen(). Implementieren Sie dieses Interface in einer Klasse Mensch. Die Methode soll ausgeben: |
|
|
Der Mensch läuft.
|
|
Testen Sie die Implementierung im Hauptprogramm Aufgabe18. |
|
24.2.2 Lernziele |
|
In dieser Aufgabe lernen Sie, ein Interface in Java zu definieren und von einer Klasse implementieren zu lassen. Sie verstehen den Zweck von Interfaces als Beschreibung gemeinsamer Fähigkeiten unabhängig von der Klassenhierarchie und lernen, wie dadurch einheitliche Schnittstellen für unterschiedliche Klassen geschaffen werden. |
|
Vgl. auch die Aufgaben zu mehreren Interfaces (Aufgabe 38) sowie zur Polymorphie (Aufgabe 39). |
|
|
|
24.2.3 Lösung |
|
|
package menschen;
|
|
|
|
|
|
interface Beweglich {
|
|
|
void bewegen();
|
|
|
}
|
|
|
|
|
|
class Mensch implements Beweglich {
|
|
|
@Override
|
|
|
public void bewegen() {
|
|
|
System.out.println("Der Mensch läuft.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe18 {
|
|
|
public static void main(String[] args) {
|
|
|
Beweglich b = new Mensch();
|
|
|
b.bewegen();
|
|
|
}
|
|
|
}
|
|
24.2.4 Betrachtete Themen |
|
- Abstraktion
- Definition von Interfaces
- Dynamische Bindung
- Implementierung von Interfaces
- Interface-Referenzen
- Interfaces
- Mehrfachimplementierung von Interfaces
- Methodenaufrufe über Interface-Referenzen
- Methodensignaturen
- Objektorientierte Modellierung
- Polymorphie
- Schlüsselwort implements
- Trennung von Schnittstelle und Implementierung
- Vertrag (Contract) zwischen Interface und Klasse
- Wiederverwendbare Schnittstellen
|
|
24.2.5 Erläuterung |
|
Das Programm zeigt, wie ein Interface verwendet wird. Mit ... |
|
|
interface Beweglich {
|
|
|
void bewegen();
|
|
|
}
|
|
... wird das Interface Beweglich definiert. Es enthält die Methode void bewegen(); Die Methode besitzt noch keinen Programmcode. Das Interface legt also nur fest: "Jede Klasse, die Beweglich sein will, muss eine Methode bewegen() besitzen." |
|
Die Klasse Mensch |
|
|
class Mensch implements Beweglich {
|
|
Die Klasse Mensch übernimmt das Interface mit: |
|
|
implements Beweglich
|
|
Dadurch verpflichtet sich die Klasse, die Methode bewegen() bereitzustellen. |
|
Umsetzung der Methode |
|
|
@Override
|
|
|
public void bewegen() {
|
|
|
System.out.println("Der Mensch läuft.");
|
|
|
}
|
|
Hier wird die im Interface verlangte Methode konkret programmiert. Die Annotation @Override bedeutet: Diese Methode überschreibt bzw. erfüllt eine Vorgabe aus dem Interface. |
|
Das Hauptprogramm |
|
|
Beweglich b = new Mensch();
|
|
Hier passiert folgendes: |
|
- rechts wird ein Objekt der Klasse Mensch erzeugt
- links wird es in einer Variablen vom Typ Beweglich gespeichert
|
|
Die Variable kennt also nur das Verhalten des Interfaces. Der Methodenaufruf b.bewegen() funktioniert, weil das Interface die Methode bewegen() definiert. |
|
Zur Laufzeit wird die Methode der Klasse Mensch ausgeführt: |
|
|
Der Mensch läuft.
|
|
Bedeutung des Beispiels |
|
Das Interface beschreibt eine Fähigkeit: "Kann sich bewegen". Andere Klassen könnten ebenfalls Beweglich implementieren: |
|
|
class Auto implements Beweglich
|
|
|
class Hund implements Beweglich
|
|
|
class Roboter implements Beweglich
|
|
Alle müssten eine Methode bewegen() besitzen, aber jeweils mit unterschiedlichem Verhalten. Das ist ein wichtiger Gedanke der objektorientierten Programmierung: |
|
- gemeinsames Verhalten definieren
- konkrete Umsetzung den Klassen überlassen
|
|
24.2.6 Exkurs - Interface |
|
Ein Interface legt fest, welche Methoden eine Klasse haben muss, aber nicht wie diese Methoden genau funktionieren. Einfach erklärt |
|
- Ein Interface enthält Methoden ohne Implementierung (nur die Signatur, d.h. Bezeichnung und Parameterliste).
- Eine Klasse, die dieses Interface benutzt ("implementiert"), muss diese Methoden definieren.
- So kann man sicherstellen, dass verschiedene Klassen sich gleich "verhalten", auch wenn sie intern unterschiedlich arbeiten.
|
|
Beispiel |
|
|
interface Fahrzeug {
|
|
|
void starten();
|
|
|
void fahren();
|
|
|
}
|
|
Das Interface sagt nur: Jedes Fahrzeug muss starten() und fahren() können. |
|
|
class Auto implements Fahrzeug {
|
|
|
public void starten() {
|
|
|
System.out.println("Auto startet");
|
|
|
}
|
|
|
public void fahren() {
|
|
|
System.out.println("Auto fährt");
|
|
|
}
|
|
|
}
|
|
Wofür braucht man Interfaces? |
|
- Einheitliche Struktur: Verschiedene Klassen können gleich angesprochen werden
- Flexibilität: Man kann später leicht neue Klassen hinzufügen
- Mehrfachvererbung (von Verhalten): Eine Klasse kann mehrere Interfaces implementieren
|
|
Kurz gesagt: |
|
- Ein Interface beschreibt was gemacht werden soll,
- die Klasse beschreibt wie es gemacht wird.
|
|
24.2.7 Interface vs. abstrakte Klasse |
|
Interfaces und abstrakte Klassen verfolgen ein ähnliches Ziel: Sie dienen als Vorlage für andere Klassen. Es gibt aber wichtige Unterschiede. |
|
|
|
| Interface |
Abstrakte Klasse |
| Beschreibt vor allem ein Verhalten ("kann etwas") |
Beschreibt eine gemeinsame Superklasse ("ist etwas") |
| Eine Klasse kann mehrere Interfaces implementieren |
Eine Klasse kann nur von einer abstrakten Klasse erben |
| Enthält hauptsächlich Methodensignaturen |
Kann Attribute, Konstruktoren und vollständige Methoden enthalten |
| Schlüsselwort interface |
Schlüsselwort abstract class |
| Keine Objekte direkt erzeugbar |
Keine Objekte direkt erzeugbar |
| |
Beispiel mit Interface
|
|
Hier wird nur festgelegt, dass sich etwas bewegen kann: |
|
|
interface Beweglich {
|
|
|
void bewegen();
|
|
|
}
|
|
Verschiedene Klassen können dieses Verhalten unterschiedlich umsetzen: |
|
|
class Mensch implements Beweglich {
|
|
|
public void bewegen() {
|
|
|
System.out.println("Der Mensch läuft.");
|
|
|
}
|
|
|
}
|
|
|
class Auto implements Beweglich {
|
|
|
public void bewegen() {
|
|
|
System.out.println("Das Auto fährt.");
|
|
|
}
|
|
|
}
|
|
Das Interface beschreibt also nur die Fähigkeit, dass Menschen und Autos sich bewegen können. |
|
|
|
Beispiel mit abstrakter Klasse |
|
Hier haben alle Fahrzeuge gemeinsame Eigenschaften: |
|
|
abstract class Fahrzeug {
|
|
|
String kennzeichen;
|
|
|
|
|
|
public void tanken() {
|
|
|
System.out.println("Fahrzeug wird betankt.");
|
|
|
}
|
|
|
|
|
|
public abstract void fahren();
|
|
|
}
|
|
Abgeleitete Klassen erben die gemeinsamen Bestandteile: |
|
|
class Pkw extends Fahrzeug {
|
|
|
public void fahren() {
|
|
|
System.out.println("PKW fährt.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Lkw extends Fahrzeug {
|
|
|
public void fahren() {
|
|
|
System.out.println("LKW fährt.");
|
|
|
}
|
|
|
}
|
|
Hier gilt: |
|
- Ein PKW ist ein Fahrzeug.
- Ein LKW ist ein Fahrzeug.
|
|
Wann verwendet man was? |
|
Interface |
|
Wenn verschiedene Klassen eine gemeinsame Fähigkeit besitzen: |
|
|
interface Druckbar
|
|
|
interface Beweglich
|
|
|
interface Speicherbar
|
|
Beispiele: |
|
- Dokumente sind druckbar.
- Rechnungen sind druckbar.
- Fotos sind druckbar.
|
|
Diese Klassen haben sonst möglicherweise gar nichts miteinander zu tun. |
|
Abstrakte Klasse |
|
Wenn mehrere Klassen viele gemeinsame Attribute und Methoden besitzen: |
|
|
abstract class Person
|
|
|
abstract class Fahrzeug
|
|
|
abstract class Tier
|
|
Beispiele: |
|
- Studierende und Dozierende sind Personen.
- PKW und LKW sind Fahrzeuge.
|
|
Hier gibt es gemeinsame Attribute und Methoden, die vererbt werden können. |
|
Zusammenfassung |
|
Abstrakte Klasse: Beschreibt, was Objekte gemeinsam haben. Beispiel: PKW und LKW sind Fahrzeuge. |
|
Interface: Beschreibt, was Objekte gemeinsam können. Beispiel: Mensch, Auto und Fahrrad können sich bewegen. |
|
Deshalb lautet eine häufige Faustregel: |
|
- "ist ein" -> abstrakte Klasse
- "kann" -> Interface
|
|
Beispiele: |
|
|
class Pkw extends Fahrzeug
|
|
Ein PKW ist ein Fahrzeug. |
|
|
class Pkw implements Beweglich
|
|
Ein PKW kann sich bewegen. |
|
|
|
24.3 Aufgabe 19 - 1:1 |
|
Einführung der einseitigen 1:1-Beziehung |
|
24.3.1 Aufgabenstellung |
|
Erstellen Sie die beiden Klassen Stud und Adresse. Eine Adresse soll folgende Attribute besitzen: |
|
|
int adrNr;
|
|
|
String strasse;
|
|
|
String ort;
|
|
Ein Studierender soll folgende Attribute besitzen: |
|
|
int matrNr;
|
|
|
String name;
|
|
Zwischen den Klassen soll eine 1:1-Beziehung eingerichtet werden. D.h., jedem Objekt der Klasse Stud soll genau ein Objekt der Klasse Adresse zugeordnet werden. Implementieren Sie geeignete Konstruktoren und eine Methode anzeigen(), die die Daten des Studierenden zusammen mit seiner Adresse ausgibt. Testen Sie das Zusammenspiel der Klassen im Hauptprogramm. |
|
Es genügt diese eine Richtung. |
|
Exkurs: Lesen Sie [Staud 2019] bzw. [OO2025]. Dort wird die Unterscheidung zwischen Kardinalitäten und Min-/Max-Angaben dargestellt. Eine Beziehung 1:1 (eigentlich: Kardinalität) kann, ausgedrückt in Min-/Max-Angaben folgendes bedeuten: 0,1 : 0,1, 1,1 : 0,1, 1,1 : 1,1. Welche Lösung ist hier realisiert? |
|
24.3.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine 1:1-Beziehung zwischen zwei Klassen in Java zu realisieren. Sie verstehen, wie ein Objekt über eine Referenz mit genau einem anderen Objekt verknüpft wird und wie auf die Daten des verknüpften Objekts zugegriffen werden kann. |
|
|
|
24.3.3 Lösung |
|
Klasse Adresse |
|
|
package hochschule;
|
|
|
|
|
|
class Adresse {int adrNr; String strasse; String ort;
|
|
|
|
|
|
Adresse(int adrNr, String strasse, String ort) {
|
|
|
this.adrNr = adrNr;
|
|
|
this.strasse = strasse;
|
|
|
this.ort = ort;
|
|
|
}
|
|
|
}
|
|
Klasse Stud |
|
|
package hochschule;
|
|
|
|
|
|
class Stud {
|
|
|
int matrNr;
|
|
|
String name;
|
|
|
|
|
Verknüpfung zur Adresse (1:1) |
|
|
Adresse adresse;
|
|
|
|
|
|
Stud(int matrNr, String name, Adresse adresse) {
|
|
|
this.matrNr = matrNr;
|
|
|
this.name = name;
|
|
|
this.adresse = adresse;
|
|
|
}
|
|
|
void anzeigen() {
|
|
|
System.out.println("Matrikelnummer: " + matrNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
|
|
|
System.out.println("Adresse:");
|
|
|
System.out.println("AdrNr: " + adresse.adrNr);
|
|
|
System.out.println(adresse.strasse);
|
|
|
System.out.println(adresse.ort);
|
|
|
}
|
|
|
}
|
|
Hauptprogramm |
|
|
package hochschule;
|
|
|
|
|
|
public class HP {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
Adresse adr1 =
|
|
|
new Adresse(501, "Musterstraße 12", "Passau");
|
|
|
Stud s1 =
|
|
|
new Stud(1001, "Eva Müller", adr1);
|
|
|
s1.anzeigen();
|
|
|
}
|
|
|
}
|
|
Lösung zur Frage im obigen Exkurs Durch die Hinterlegung des Adressenobjekts beim Studierenden muss jeder Studierende genau eine Adresse besitzen. Auf der Seite der Studierenden liegt daher eine Min-/Max-Angabe von 1,1 vor. In der Klasse Adresse ist kein Verweis auf einen Studierenden vorhanden. Die Beziehung ist daher nur in einer Richtung modelliert (unidirektional). Aus dem Programm allein lässt sich deshalb keine eindeutige Min-/Max-Angabe für die Adressseite ableiten. Inhaltlich ist jedoch beabsichtigt, eine 1:1-Beziehung abzubilden. Eine vollständige Umsetzung der 1:1-Beziehung erfolgt erst in der nächsten Aufgabe durch die Gegenreferenz in der Klasse Adresse. |
|
24.3.4 Ergebnis Programmlauf |
|
|
Matrikelnummer: 1001
|
|
|
Name: Eva Müller
|
|
|
Adresse:
|
|
|
AdrNr: 501
|
|
|
Musterstraße 12
|
|
|
Passau
|
|
24.3.5 Betrachtete Themen |
|
- Attribute
- Bildschirmausgabe mit System.out.println()
- Einfache 1:1-Beziehung
- Klassen
- Klassenverknüpfungen
- Konstruktoren
- Methoden
- Navigation von Stud zu Adresse
- Objekt als Attribut
- Objektattribute
- Objekte
- Objekterzeugung mit new
- Objektreferenzen
- Übergabe von Objekten als Parameter
- Unidirektionale Beziehung
|
|
24.3.6 Erläuterung |
|
Die eigentliche 1:1-Verknüpfung befindet sich in der Klasse Stud: |
|
|
Adresse adresse;
|
|
Hier wird keine Straße und kein Ort gespeichert, sondern eine Referenz auf ein Objekt der Klasse Adresse. Beim Erzeugen des Studierenden wird die Adresse übergeben: |
|
|
Stud s1 = new Stud(1001,
|
|
|
"Eva Müller",
|
|
|
adr1);
|
|
Der Studierende "kennt" dadurch seine Adresse und kann über die Referenz auf deren Attribute zugreifen: |
|
|
adresse.strasse
|
|
|
adresse.ort
|
|
|
adresse.adrNr
|
|
Theorieaspekte |
|
Diese Aufgabe zeigt die direkte Objektverknüpfung zwischen zwei Klassen. Im Unterschied zu einer Zuordnung über Schlüsselwerte wird hier nicht nur eine Nummer gespeichert, sondern ein Objekt verweist direkt auf ein anderes Objekt. Damit wird deutlich: |
|
Beziehungen zwischen Objekten werden in Java durch Referenzen realisiert. |
|
|
|
24.4 Aufgabe 19b - Bidirektional |
|
Erweiterung von Aufgabe 19 zur bidirektionalen 1:1-Beziehung |
|
24.4.1 Aufgabenstellung |
|
Erweitern Sie die Lösung aus Aufgabe 19 so, dass die Beziehung zwischen den Klassen Stud und Adresse bidirektional wird. Bisher "kennt" jeder Studierende seine Adresse. Nun soll zusätzlich jede Adresse den zugehörigen Studierenden "kennen". |
|
Ergänzen Sie dazu in der Klasse Adresse ein Attribut vom Typ Stud. Setzen Sie im Hauptprogramm beide Verweise so, dass von einem Studierenden auf seine Adresse und von einer Adresse auf ihren Studierenden zugegriffen werden kann. |
|
Erstellen Sie außerdem eine Methode |
|
|
void anzeigenStud()
|
|
in der Klasse Adresse, welche die Daten des zugehörigen Studierenden ausgibt. Testen Sie die Navigation in beide Richtungen im Hauptprogramm. |
|
Frage: Welche Lösung ist hier bzgl. Studierenden und Adressen tatsächlich realisiert? |
|
24.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie, eine bidirektionale 1:1-Beziehung zwischen zwei Klassen zu realisieren. Sie verstehen, wie sich zwei Objekte gegenseitig referenzieren und wie dadurch der Zugriff von beiden Seiten der Beziehung möglich wird. Dabei vertiefen Sie Ihr Verständnis von Objektverknüpfungen und Referenzen in der objektorientierten Programmierung. |
|
24.4.3 Lösung |
|
Klasse Adresse |
|
|
package hochschule;
|
|
|
|
|
|
class Adresse {
|
|
|
int adrNr;
|
|
|
String strasse;
|
|
|
String ort;
|
|
|
|
|
Rückverweis zum Studierenden (1:1) |
|
|
Stud stud;
|
|
|
|
|
|
Adresse(int adrNr, String strasse, String ort) {
|
|
|
this.adrNr = adrNr;
|
|
|
this.strasse = strasse;
|
|
|
this.ort = ort;
|
|
|
}
|
|
|
|
|
|
void anzeigenStud() {
|
|
|
System.out.println("Zugehöriger Studierender:");
|
|
|
System.out.println("Matrikelnummer: " + stud.matrNr);
|
|
|
System.out.println("Name: " + stud.name);
|
|
|
}
|
|
|
}
|
|
Klasse Stud |
|
|
package hochschule;
|
|
|
|
|
|
class Stud {
|
|
|
int matrNr;
|
|
|
String name;
|
|
|
|
|
Verknüpfung zur Adresse (1:1) |
|
|
Adresse adresse;
|
|
|
|
|
|
Stud(int matrNr, String name, Adresse adresse) {
|
|
|
this.matrNr = matrNr;
|
|
|
this.name = name;
|
|
|
this.adresse = adresse;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("Matrikelnummer: " + matrNr);
|
|
|
System.out.println("Name: " + name);
|
|
|
|
|
|
System.out.println("Adresse:");
|
|
|
System.out.println("AdrNr: " + adresse.adrNr);
|
|
|
System.out.println(adresse.strasse);
|
|
|
System.out.println(adresse.ort);
|
|
|
}
|
|
|
}
|
|
Hauptprogramm |
|
|
package hochschule;
|
|
|
|
|
Natürlich kann man das jeweilige Hauptprogramm auch HP nennen. |
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Adresse adr1 =
|
|
|
new Adresse(501, "Musterstraße 12", "Passau");
|
|
|
|
|
|
Stud s1 =
|
|
|
new Stud(1001, "Eva Müller", adr1);
|
|
|
|
|
Zweite Richtung der Beziehung setzen |
|
|
adr1.stud = s1;
|
|
|
|
|
|
System.out.println("Ausgabe vom Studierenden aus:");
|
|
|
s1.anzeigen();
|
|
|
System.out.println("\n---------------------\n");
|
|
|
|
|
|
System.out.println("Ausgabe von der Adresse aus:");
|
|
|
adr1.anzeigenStud();
|
|
|
}
|
|
|
}
|
|
Lösung zur Frage oben Im Gegensatz zur vorherigen Aufgabe existieren nun Referenzen in beide Richtungen. Damit wird die Min-/Max-Kombination 1,1 : 1,1 modelliert. Das Programm überprüft diese Bedingung allerdings nicht automatisch, sondern setzt voraus, dass die Objekte korrekt miteinander verknüpft werden. |
|
24.4.4 Ergebnis Programmlauf |
|
|
Ausgabe vom Studierenden aus:
|
|
|
Matrikelnummer: 1001
|
|
|
Name: Eva Müller
|
|
|
Adresse:
|
|
|
AdrNr: 501
|
|
|
Musterstraße 12
|
|
|
Passau
|
|
|
|
|
|
---------------------
|
|
|
|
|
|
Ausgabe von der Adresse aus:
|
|
|
Zugehöriger Studierender:
|
|
|
Matrikelnummer: 1001
|
|
|
Name: Eva Müller
|
|
24.4.5 Betrachtete Themen |
|
- bidirektionale Beziehung
- einfache 1:1-Beziehung
- Konsistenz von Objektverknüpfungen
- Konstruktoren
- Mehrere Klassen
- Methodenaufrufe
- nachträgliches Setzen einer Beziehung
- Navigation in beide Richtungen
- Objekte als Attribute
- Objekte und Objektreferenzen
- objektorientierte Modellierung
- Referenzvariablen
- Rückverweis
|
|
24.4.6 Erläuterungen |
|
Die eigentlichen Programmelemente für die bidirektionale Beziehung sind: |
|
- In Stud: Adresse adresse;
- In Adresse: Stud stud;
|
|
und im Hauptprogramm: |
|
|
Stud s1 = new Stud(1001, "Eva Müller", adr1);
|
|
|
adr1.stud = s1;
|
|
Damit gilt: Von beiden Objekten kann nun auf das andere geschlossen werden, womit die bidirektionale 1:1-Beziehung realisiert ist. |
|
Das ist aber nur der Anfang. Beim Einrichten einer solchen Beziehung müsste überprüft werden, ob wirklich alle Objekte an der Beziehung teilhaben (dies bedeutet 1,1 : 1,1), ob also nicht |
|
- 0,1 : 1,1
- 0,1 : 0,1 oder
- 1,1 : 0,1
|
|
vorliegen. Das müsste abgefangen werden. |
|
|
|
24.5 Aufgabe 20 - n:m |
|
N:m-Beziehung mit den Klassen Stud und Kurs. |
|
24.5.1 Aufgabenstellung |
|
Erstelle ein Programm, das die n:m-Beziehung zwischen Studierenden und Kursen vollumfänglich erfasst: |
|
- Ein Studierender besucht mehrer Kurse
- Ein Kurs wird von mehreren Studierenden besucht.
|
|
Lege die beiden Klassen Stud und Kurs so an, dass die Daten des Programmlaufs sich wie folgt ergeben: |
|
|
Eva besucht folgende Kurse:
|
|
|
Programmierung 1
|
|
|
Datenbanken
|
|
|
|
|
|
Paul besucht folgende Kurse:
|
|
|
Programmierung 1
|
|
|
|
|
|
Kurs: Programmierung 1
|
|
|
Eva
|
|
|
Paul
|
|
|
|
|
|
Kurs: Datenbanken
|
|
|
Eva
|
|
|
Guiseppe
|
|
Nutzen Sie für die Verknüpfung jeweils eine ArrayList. |
|
24.5.2 Lernziele |
|
Hier wird gezeigt, wie eine n:m-Beziehung zwischen zwei Klassen in Java umgesetzt wird. Sie verstehen, wie mehrere Objekte einer Klasse mit mehreren Objekten einer anderen Klasse verknüpft werden können und wie diese Beziehungen mithilfe von Listen verwaltet werden. |
|
|
|
24.5.3 Lösung |
|
Klasse Student |
|
|
package studierende;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Student {
|
|
|
String name;
|
|
|
|
|
Verknüpfung zu mehreren Kursen |
|
|
List<Kurs> kurse = new ArrayList<>();
|
|
|
|
|
|
Student(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
|
void addKurs(Kurs kurs) {
|
|
|
kurse.add(kurs);
|
|
|
}
|
|
|
void anzeigen() {
|
|
|
System.out.println(name + " besucht folgende Kurse:");
|
|
|
|
|
|
for (Kurs k : kurse) {
|
|
|
System.out.println(" " + k.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Kurs |
|
|
package studierende;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Kurs {
|
|
|
String name;
|
|
|
|
|
Verknüpfung zu mehreren Studierenden |
|
|
List<Student> studenten = new ArrayList<>();
|
|
|
|
|
|
Kurs(String name) {
|
|
|
this.name = name;
|
|
|
}
|
|
|
void addStudent(Student student) {
|
|
|
studenten.add(student);
|
|
|
}
|
|
|
void anzeigen() {
|
|
|
System.out.println("Kurs: " + name);
|
|
|
|
|
|
for (Student s : studenten) {
|
|
|
System.out.println(" " + s.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
HP (Hauptprogramm) |
|
|
package studierende;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Kurs k1 = new Kurs("Programmierung 1");
|
|
|
Kurs k2 = new Kurs("Datenbanken");
|
|
|
|
|
|
Student s1 = new Student("Eva");
|
|
|
Student s2 = new Student("Paul");
|
|
|
Student s3 = new Student("Guiseppe");
|
|
|
|
|
Beziehungen herstellen |
|
|
s1.addKurs(k1);
|
|
|
s1.addKurs(k2);
|
|
|
|
|
|
s2.addKurs(k1);
|
|
|
|
|
|
k1.addStudent(s1);
|
|
|
k1.addStudent(s2);
|
|
|
|
|
|
k2.addStudent(s1);
|
|
|
k2.addStudent(s3);
|
|
|
|
|
Ausgaben |
|
|
s1.anzeigen();
|
|
|
System.out.println();
|
|
|
|
|
|
s2.anzeigen();
|
|
|
System.out.println();
|
|
|
|
|
|
k1.anzeigen();
|
|
|
System.out.println();
|
|
|
|
|
|
k2.anzeigen();
|
|
|
}
|
|
|
}
|
|
24.5.4 Betrachtete Themen |
|
- ArrayList
- Ausgabe verknüpfter Objekte
- Bidirektionale Beziehung
- foreach-Schleife
- Generics (List<Kurs>, List<Student>)
- Konsistenz von Beziehungen
- List
- Mehrere Klassen
- Methoden zum Herstellen von Beziehungen
- n:m-Beziehung
- Navigation in beide Richtungen
- Objekte als Listenelemente
- Objekte und Objektreferenzen
- Objektorientierte Modellierung
|
|
24.5.5 Erläuterung |
|
Diese Lösung entspricht einer bidirektionalen n:m-Beziehung. Die Beziehung wird zweimal gespeichert: |
|
- Student "kennt" seine Kurse.
- Kurs "kennt" seine Studierenden.
|
|
Das ist sehr anschaulich, führt aber dazu, dass beim Anlegen einer Beziehung beide Listen gepflegt werden müssen: |
|
|
s1.addKurs(k1);
|
|
|
k1.addStudent(s1);
|
|
Als elegantere Lösung kann eine Assoziationsklasse genutzt werden (vgl. Aufgabe4e). |
|
|
|
24.6 Aufgabe 21 - Klassendiagramm HS |
|
Vom Klassendiagramm zu Java |
|
24.6.1 Aufgabe |
|
Das folgende Klassendiagramm stammt aus [Staud 2019]. Es ist die Abbildung 3.8-1. Vgl. dort für eine Beschreibung. |
|
Erstellen Sie ein Java-Programm, das dieses Klassendiagramm in wesentlichen Teilen umsetzt. Die Beziehungen werden nicht datenbankartig durch Fremdschlüssel realisiert, sondern objektorientiert durch Objektreferenzen und Listen. |
|
Legen Sie Beispieldaten an (zwei Studierende) und demonstrieren Sie den Methodeneinsatz. |
|

|
|
Quelle: [Staud 2019, Abbildung 3.8-1] |
|
|
|
24.6.2 Lernziele |
|
Sie sehen, wie ein UML-Klassendiagramm systematisch in Java-Klassen umgesetzt wird, wie Klassen, Attribute, Methoden und Beziehungen aus einem Modell in Programmcode übertragen werden. Dadurch vertiefen sie ihr Verständnis der objektorientierten Modellierung und erkennen den Zusammenhang zwischen der inhaltlichen Beschreibung eines Anwendungsbereichs und seiner Implementierung in Java. |
|
24.6.3 Lösung |
|
Eine einfache Java-Umsetzung des UML-Diagramms sieht so aus, dabei werden die n:m-Beziehungen mit List<> umgesetzt. Das Prüfungsdreieck wird als eigene Klasse Pruefungsgeschehen modelliert. |
|
Die einzelnen Klassen und Programme sind in einer Datei HochschuleDemo.java zusammengefasst. Das dient hier der vereinfachten Darstellung und Demonstrationszwecken, ist aber i.d.R. nicht empfehlenswert. |
|
Aufpassen: Bei der Übernahme des Programms per Copy/Paste können Trennstriche die Java-Entwicklungsumgebung irritieren. |
|
HochschuleDemo.java |
|
|
package hochschule;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Dozent {
|
|
|
int dozNr;
|
|
|
String anrede, name, vorname, ort, plz, strasse, email;
|
|
|
|
|
|
List<Lehrveranstaltung> lehrveranstaltungen = new ArrayList<>();
|
|
|
List<Studierender> betreuteStudierende = new ArrayList<>();
|
|
|
|
|
|
Dozent(int dozNr, String name, String vorname) {
|
|
|
this.dozNr = dozNr;
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
}
|
|
|
|
|
|
void haltenVorlesung(Lehrveranstaltung lv) {
|
|
|
lehrveranstaltungen.add(lv);
|
|
|
lv.dozenten.add(this);
|
|
|
}
|
|
|
|
|
|
void betreuen(Studierender s) {
|
|
|
betreuteStudierende.add(s);
|
|
|
s.betreuer = this;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Studierender {
|
|
|
String matrikelNr, name, vname, plz, ort, strasse, studiengang;
|
|
|
LocalDate beginnStudium, endeStudium;
|
|
|
int fachsem;
|
|
|
|
|
|
Dozent betreuer;
|
|
|
|
|
|
List<Lehrveranstaltung> besuchteLehrveranstaltungen = new ArrayList<>();
|
|
|
List<Pruefungsgeschehen> pruefungen = new ArrayList<>();
|
|
|
|
|
|
Studierender(String matrikelNr, String name, String vname) {
|
|
|
this.matrikelNr = matrikelNr;
|
|
|
this.name = name;
|
|
|
this.vname = vname;
|
|
|
}
|
|
|
|
|
|
void immatrikulieren() {
|
|
|
beginnStudium = LocalDate.now();
|
|
|
System.out.println(vname + " " + name + " wurde immatrikuliert.");
|
|
|
}
|
|
|
|
|
|
void exmatrikulieren() {
|
|
|
endeStudium = LocalDate.now();
|
|
|
System.out.println(vname + " " + name + " wurde exmatrikuliert.");
|
|
|
}
|
|
|
|
|
|
void besucht(Lehrveranstaltung lv) {
|
|
|
besuchteLehrveranstaltungen.add(lv);
|
|
|
lv.studierende.add(this);
|
|
|
}
|
|
|
|
|
|
int anzahl() {
|
|
|
return pruefungen.size();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Lehrveranstaltung {
|
|
|
String bezLV;
|
|
|
String studiengang;
|
|
|
int semesterSPO;
|
|
|
|
|
|
List<Dozent> dozenten = new ArrayList<>();
|
|
|
List<Studierender> studierende = new ArrayList<>();
|
|
|
List<Pruefungsgeschehen> pruefungen = new ArrayList<>();
|
|
|
|
|
|
Lehrveranstaltung(String bezLV, String studiengang, int semesterSPO) {
|
|
|
this.bezLV = bezLV;
|
|
|
this.studiengang = studiengang;
|
|
|
this.semesterSPO = semesterSPO;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Pruefungstyp {
|
|
|
int prTypNr;
|
|
|
String bezPruef;
|
|
|
int laenge;
|
|
|
|
|
|
Pruefungstyp(int prTypNr, String bezPruef, int laenge) {
|
|
|
this.prTypNr = prTypNr;
|
|
|
this.bezPruef = bezPruef;
|
|
|
this.laenge = laenge;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Pruefungsgeschehen {
|
|
|
Studierender pruefungsteilnehmer;
|
|
|
Lehrveranstaltung pruefungsgegenstand;
|
|
|
Pruefungstyp pruefungstyp;
|
|
|
int note;
|
|
|
|
|
|
Pruefungsgeschehen(
|
|
|
Studierender pruefungsteilnehmer,
|
|
|
Lehrveranstaltung pruefungsgegenstand,
|
|
|
Pruefungstyp pruefungstyp,
|
|
|
int note) {
|
|
|
|
|
|
this.pruefungsteilnehmer = pruefungsteilnehmer;
|
|
|
this.pruefungsgegenstand = pruefungsgegenstand;
|
|
|
this.pruefungstyp = pruefungstyp;
|
|
|
this.note = note;
|
|
|
|
|
|
pruefungsteilnehmer.pruefungen.add(this);
|
|
|
pruefungsgegenstand.pruefungen.add(this);
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(
|
|
|
pruefungsteilnehmer.vname + " " + pruefungsteilnehmer.name
|
|
|
+ " | " + pruefungsgegenstand.bezLV
|
|
|
+ " | " + pruefungstyp.bezPruef
|
|
|
+ " | Note: " + note);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class HochschuleDemo {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Dozent d1 = new Dozent(1, "Müller", "Anna");
|
|
|
|
|
|
Studierender s1 = new Studierender("1001", "Maier", "Paul");
|
|
|
Studierender s2 = new Studierender("1002", "Schulz", "Eva");
|
|
|
|
|
|
Lehrveranstaltung lv1 =
|
|
|
new Lehrveranstaltung("Objektorientierung", "Wirtschaftsinformatik", 2);
|
|
|
|
|
|
Pruefungstyp pt1 = new Pruefungstyp(1, "Klausur", 90);
|
|
|
|
|
|
d1.haltenVorlesung(lv1);
|
|
|
|
|
|
s1.immatrikulieren();
|
|
|
s2.immatrikulieren();
|
|
|
|
|
|
s1.besucht(lv1);
|
|
|
s2.besucht(lv1);
|
|
|
|
|
|
d1.betreuen(s1);
|
|
|
|
|
|
Pruefungsgeschehen p1 = new Pruefungsgeschehen(s1, lv1, pt1, 2);
|
|
|
|
|
|
p1.anzeigen();
|
|
|
|
|
|
System.out.println("Anzahl Prüfungen von "
|
|
|
+ s1.vname + " " + s1.name + ": " + s1.anzahl());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
24.6.4 Ergebnis Programmlauf |
|
|
Paul Maier wurde immatrikuliert.
|
|
|
Eva Schulz wurde immatrikuliert.
|
|
|
Paul Maier | Objektorientierung | Klausur | Note: 2
|
|
|
Anzahl Prüfungen von Paul Maier: 1
|
|
24.6.5 Betrachtete Themen |
|
- Assoziationen
- Assoziationsklasse / Beziehungsklasse
- Attribute
- bidirektionale Verknüpfungen
- Klassen
- Konstruktoren
- List und ArrayList
- Listen zur Umsetzung mehrerer Beziehungen
- LocalDate
- Methoden
- Methodenaufrufe
- n:m-Beziehungen
- Objekte
- Objekte als Listenelemente
- objektorientierter Entwurf
- Objektreferenzen
- UML-Klassendiagramme
- Umsetzung von Modellen in Java
|
|
|
|
25 Übungsaufgaben Teil 6 |
|
|
|
25.1 Aufgabe 22 - Liste |
|
Einfach verkettete Liste |
|
25.1.1 Aufgabenstellung |
|
Ein Zug besteht aus mehreren Waggons. Jeder Waggon "kennt" den jeweils nächsten. Dadurch entsteht eine einfach verkettete Liste. |
|
Erstellen Sie ein Java-Programm mit den Klassen Waggon und AufgabeWaggons. Das Programm soll zunächst einen Zug mit drei Waggons erzeugen: |
|
1 Lokomotive -> 2 Personenwagen -> 3 Speisewagen -> null |
|
Danach soll über eine grafische Eingabemaske ausgewählt werden können: |
|
1. Zug anzeigen |
|
2. Waggon am Ende anhängen |
|
3. Waggon nach einer bestimmten Waggonnummer einfügen |
|
4. Waggon suchen |
|
5. Waggon entfernen |
|
6. Programm beenden |
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|

|
|
usw. |
|
25.1.2 Lernziele |
|
Sie lernen das Prinzip der einfach verketteten Liste kennen, verstehen, wie Objekte über Referenzen zu einer Kette verbunden werden und wie sich Elemente am Ende oder in der Mitte einfügen, suchen und entfernen lassen. Dadurch vertiefen sie ihr Verständnis dynamischer Datenstrukturen und erkennen den Unterschied zwischen verketteten Listen und Arrays. |
|
25.1.3 Lösung |
|
Klasse Waggon |
|
|
package zug;
|
|
|
|
|
|
class Waggon {
|
|
|
|
|
|
int nummer;
|
|
|
String typ;
|
|
|
|
|
Verweis auf den nächsten Waggon |
|
|
Waggon naechster;
|
|
|
|
|
|
Waggon(int nummer, String typ) {
|
|
|
this.nummer = nummer;
|
|
|
this.typ = typ;
|
|
|
this.naechster = null;
|
|
|
}
|
|
|
}
|
|
Hauptprogramm |
|
|
package zug;
|
|
|
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
|
|
public class AufgabeWaggons {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
Anfangsliste erstellen |
|
|
Waggon w1 = new Waggon(1, "Lokomotive");
|
|
|
Waggon w2 = new Waggon(2, "Personenwagen");
|
|
|
Waggon w3 = new Waggon(3, "Speisewagen");
|
|
|
|
|
|
w1.naechster = w2;
|
|
|
w2.naechster = w3;
|
|
|
w3.naechster = null;
|
|
|
|
|
Kopf der Liste |
|
|
Waggon erster = w1;
|
|
|
|
|
|
boolean weiter = true;
|
|
|
|
|
|
while (weiter) {
|
|
|
|
|
|
String auswahl = JOptionPane.showInputDialog(
|
|
|
"Verkettete Liste: Zug mit Waggons\n\n"
|
|
|
+ "1 - Zug anzeigen\n"
|
|
|
+ "2 - Waggon am Ende anhängen\n"
|
|
|
+ "3 - Waggon nach einer bestimmten Waggonnummer einfügen\n"
|
|
|
+ "4 - Waggon suchen\n"
|
|
|
+ "5 - Waggon entfernen\n"
|
|
|
+ "6 - Programm beenden\n\n"
|
|
|
+ "Bitte Auswahl eingeben:"
|
|
|
);
|
|
|
|
|
|
if (auswahl == null) {
|
|
|
weiter = false;
|
|
|
} else if (auswahl.equals("1")) {
|
|
|
zugAnzeigen(erster);
|
|
|
|
|
|
} else if (auswahl.equals("2")) {
|
|
|
erster = waggonAnhaengen(erster);
|
|
|
|
|
|
} else if (auswahl.equals("3")) {
|
|
|
erster = waggonEinfuegen(erster);
|
|
|
|
|
|
} else if (auswahl.equals("4")) {
|
|
|
waggonSuchen(erster);
|
|
|
|
|
|
} else if (auswahl.equals("5")) {
|
|
|
erster = waggonEntfernen(erster);
|
|
|
|
|
|
} else if (auswahl.equals("6")) {
|
|
|
weiter = false;
|
|
|
|
|
|
} else {
|
|
|
JOptionPane.showMessageDialog(null, "Ungültige Eingabe.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void zugAnzeigen(Waggon erster) {
|
|
|
|
|
|
String ausgabe = "Aktueller Zug:\n\n";
|
|
|
|
|
|
Waggon aktuell = erster;
|
|
|
|
|
|
while (aktuell != null) {
|
|
|
ausgabe = ausgabe
|
|
|
+ aktuell.nummer + " "
|
|
|
+ aktuell.typ + "\n";
|
|
|
|
|
|
aktuell = aktuell.naechster;
|
|
|
}
|
|
|
|
|
|
JOptionPane.showMessageDialog(null, ausgabe);
|
|
|
}
|
|
|
|
|
|
static Waggon waggonAnhaengen(Waggon erster) {
|
|
|
|
|
|
int nummer = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Nummer des neuen Waggons:")
|
|
|
);
|
|
|
|
|
|
String typ = JOptionPane.showInputDialog("Typ des neuen Waggons:");
|
|
|
|
|
|
Waggon neuer = new Waggon(nummer, typ);
|
|
|
|
|
|
if (erster == null) {
|
|
|
erster = neuer;
|
|
|
} else {
|
|
|
Waggon aktuell = erster;
|
|
|
|
|
|
while (aktuell.naechster != null) {
|
|
|
aktuell = aktuell.naechster;
|
|
|
}
|
|
|
|
|
|
aktuell.naechster = neuer;
|
|
|
}
|
|
|
|
|
|
return erster;
|
|
|
}
|
|
|
|
|
|
static Waggon waggonEinfuegen(Waggon erster) {
|
|
|
|
|
|
int nachNummer = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog(
|
|
|
"Nach welcher Waggonnummer soll eingefügt werden?"
|
|
|
)
|
|
|
);
|
|
|
|
|
|
int neueNummer = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Nummer des neuen Waggons:")
|
|
|
);
|
|
|
|
|
|
String typ = JOptionPane.showInputDialog("Typ des neuen Waggons:");
|
|
|
|
|
|
Waggon aktuell = erster;
|
|
|
|
|
|
while (aktuell != null amp;amp; aktuell.nummer != nachNummer) {
|
|
|
aktuell = aktuell.naechster;
|
|
|
}
|
|
|
|
|
|
if (aktuell == null) {
|
|
|
JOptionPane.showMessageDialog(null, "Waggon nicht gefunden.");
|
|
|
} else {
|
|
|
Waggon neuer = new Waggon(neueNummer, typ);
|
|
|
|
|
|
neuer.naechster = aktuell.naechster;
|
|
|
aktuell.naechster = neuer;
|
|
|
}
|
|
|
|
|
|
return erster;
|
|
|
}
|
|
|
|
|
|
static void waggonSuchen(Waggon erster) {
|
|
|
|
|
|
int suchNummer = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Welche Waggonnummer wird gesucht?")
|
|
|
);
|
|
|
|
|
|
Waggon aktuell = erster;
|
|
|
|
|
|
while (aktuell != null amp;amp; aktuell.nummer != suchNummer) {
|
|
|
aktuell = aktuell.naechster;
|
|
|
}
|
|
|
|
|
|
if (aktuell == null) {
|
|
|
JOptionPane.showMessageDialog(null, "Waggon nicht gefunden.");
|
|
|
} else {
|
|
|
JOptionPane.showMessageDialog(
|
|
|
null,
|
|
|
"Gefunden:\n"
|
|
|
+ aktuell.nummer + " "
|
|
|
+ aktuell.typ
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static Waggon waggonEntfernen(Waggon erster) {
|
|
|
|
|
|
int suchNummer = Integer.parseInt(
|
|
|
JOptionPane.showInputDialog("Welche Waggonnummer soll entfernt werden?")
|
|
|
);
|
|
|
|
|
|
if (erster == null) {
|
|
|
JOptionPane.showMessageDialog(null, "Der Zug ist leer.");
|
|
|
return erster;
|
|
|
}
|
|
|
|
|
|
// Sonderfall: erster Waggon wird entfernt
|
|
|
if (erster.nummer == suchNummer) {
|
|
|
erster = erster.naechster;
|
|
|
JOptionPane.showMessageDialog(null, "Erster Waggon wurde entfernt.");
|
|
|
return erster;
|
|
|
}
|
|
|
|
|
|
Waggon aktuell = erster;
|
|
|
|
|
|
while (aktuell.naechster != null
|
|
|
amp;amp; aktuell.naechster.nummer != suchNummer) {
|
|
|
aktuell = aktuell.naechster;
|
|
|
}
|
|
|
|
|
|
if (aktuell.naechster == null) {
|
|
|
JOptionPane.showMessageDialog(null, "Waggon nicht gefunden.");
|
|
|
} else {
|
|
|
aktuell.naechster = aktuell.naechster.naechster;
|
|
|
JOptionPane.showMessageDialog(null, "Waggon wurde entfernt.");
|
|
|
}
|
|
|
|
|
|
return erster;
|
|
|
}
|
|
|
}
|
|
25.1.4 Betrachtete Themen |
|
- Einfach verkettete Liste
- Selbstreferenzierende Klasse
- Objektreferenzen
- Verweis auf das nächste Objekt
- Kopf der Liste
- null als Listenende
- Durchlaufen einer Liste
- while-Schleife
- Anhängen am Ende
- Einfügen nach einem bestimmten Element
- Suchen in einer Liste
- Entfernen von Listenelementen
- Sonderfall: erstes Element entfernen
- Methoden mit Rückgabewert
- Statische Hilfsmethoden
- Benutzereingaben mit JOptionPane
- Menüsteuerung
- Objektorientierte Modellierung einer Datenstruktur
|
|
25.1.5 Anmerkungen |
|
Eine wichtige Stelle in der Klasse Waggon ist Waggon naechster; Damit zeigt jedes Objekt der Klasse Waggon auf den nächsten Waggon. Das letzte Objekt verweist auf null: |
|
|
w3.naechster = null;
|
|
Der Anfang der Liste wird durch eine eigene Referenz festgehalten: |
|
|
Waggon erster = w1;
|
|
Didaktisch besonders wichtig sind außerdem diese beiden Fälle: |
|
|
aktuell = aktuell.naechster;
|
|
zum Weitergehen in der Liste und |
|
|
aktuell.naechster = aktuell.naechster.naechster;
|
|
zum Entfernen eines Waggons aus der Liste. |
|
Zentrale Idee |
|
Die Liste wird nicht durch ein Array gebildet, sondern durch Objektverweise: |
|
|
Waggon naechster;
|
|
Ein Waggon zeigt auf den nächsten: |
|
|
Lokomotive -> Personenwagen -> Speisewagen -> null
|
|
Beim Einfügen oder Entfernen werden nur die Verweise geändert. Genau das ist der Kern einer einfach verketteten Liste. |
|
25.1.6 Exkurs - Verkettete Listen |
|
Einfach verkettete Liste |
|
Mit einfach verketteter Liste (singly linked list) meint man eine Liste, bei der jedes Element nur seinen Nachfolger kennt, siehe oben: |
|
|
class Waggon {
|
|
|
int nummer;
|
|
|
Waggon naechster;
|
|
|
}
|
|
Graphisch: |
|
|
Lok -> Personenwagen -> Speisewagen -> null
|
|
Jeder Waggon besitzt also einen Verweis auf den nächsten Waggon. Das letzte Element verweist auf null. Dadurch wird das Ende der Liste markiert. |
|
Vorteil: |
|
- einfacher Aufbau
- geringer Speicherbedarf
|
|
Nachteil: |
|
- man kann die Liste nur in Vorwärtsrichtung durchlaufen
- der Vorgänger eines Elements ist nicht direkt bekannt
|
|
Die in Aufgabe 22 entwickelte Lösung stellt eine einfach verkettete Liste dar. |
|
Doppelt verkettete Liste |
|
Bei einer doppelt verketteten Liste (doubly linked list) kennt jedes Element sowohl seinen Nachfolger als auch seinen Vorgänger. |
|
|
class Waggon {
|
|
|
int nummer;
|
|
|
Waggon vorheriger;
|
|
|
Waggon naechster;
|
|
|
}
|
|
Graphisch: |
|
|
null <- Lok <-> Personenwagen <-> Speisewagen -> null
|
|
Jeder Waggon "weiß" nun: |
|
- Wer vor ihm ist
- Wer nach ihm ist
|
|
Man kann die Liste in beide Richtungen durchlaufen. |
|
Ringliste (zyklische Liste) |
|
Eine weitere Variante ist die zyklisch verkettete Liste. Hier zeigt das letzte Element wieder auf das erste: |
|

|
|
Es gibt also kein null. |
|
Doppelt verkettete Ringliste |
|
Diese stellt eine Kombination aus beidem obigen dar: Ringliste und doppelt verkettet: |
|

|
|
|
|
Von jedem Element kann auf den Vorgänger und Nachfolger geschlossen werden und die Liste bildet einen Kreis. |
|
Wichtig: Bei verketteten Listen werden die Elemente nicht durch ein Array, sondern durch Objektreferenzen miteinander verbunden. Die Struktur der Liste entsteht ausschließlich durch die Verweise zwischen den einzelnen Objekten. Dies ist eines der grundlegenden Konzepte dynamischer Datenstrukturen. |
|
25.2 Aufgabe 23 - Unternehmen |
|
Klassendiagramm Unternehmen |
|
25.2.1 Aufgabenstellung |
|
Setzen Sie das unten angegebene Klassendiagramm in Java um. Fügen Sie beispielhafte Daten hinzu, sodass folgender Programmlauf möglich ist: |
|
- Ausgabe der Angestellten mit ihren Daten, dem zugeordneten PC, den Projekten, in denen sie mitarbeiten, sowie Vorgesetzten und Untergebenen.
- Ausgabe der Abteilungen mit Abteilungsbezeichnung, Standort, Abteilungsleitung und Mitarbeitern.
- Ausgabe der Projekte mit Projektbezeichnung, Standort und Mitarbeitern.
|
|
Das Klassendiagramm stammt aus [Staud 2019] und ist dort Abbildung 3.8-3. Siehe die Erläuterungen dort. |
|

|
|
Abbildung 25.2-1: Klassendiagramm zum Anwendungsbereich Angestellte |
|
Quelle: [Staud 2019, Abbildung 3.8-3] bzw. [OO2025] |
|
25.2.2 Lernziele |
|
Sie lernen, wie ein UML-Klassendiagramm in ein Java-Programm umgesetzt wird. Dabei wird deutlich, wie Klassen, Attribute und Beziehungen schrittweise in Java-Klassen, Referenzen und Objekte übertragen werden. |
|
25.2.3 Lösung |
|
Folgende Java-Programme richten das Klassendiagramm mit beispielhaften Daten ein. |
|
Klasse HP (Hauptprogramm; main) |
|
|
package firma;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
public class HP {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Abteilung entwicklung = new Abteilung(
|
|
|
"Entwicklung", "Dr. Weber", "Hannover"
|
|
|
);
|
|
|
|
|
|
Abteilung verwaltung = new Abteilung(
|
|
|
"Verwaltung", "Frau König", "Bremen"
|
|
|
);
|
|
|
|
|
|
PC pc1 = new PC(1001, "Dell Optiplex", "Desktop");
|
|
|
PC pc2 = new PC(1002, "Lenovo ThinkPad", "Notebook");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(
|
|
|
1, "Müller", "Anna", "30159", "Hannover",
|
|
|
"Marktstraße", LocalDate.of(2020, 3, 1),
|
|
|
LocalDate.of(1995, 5, 12), 2500.00
|
|
|
);
|
|
|
|
|
|
Angestellter a2 = new Angestellter(
|
|
|
2, "Schmidt", "Bernd", "28195", "Bremen",
|
|
|
"Bahnhofstraße", LocalDate.of(2019, 7, 15),
|
|
|
LocalDate.of(1990, 9, 3), 2800.00
|
|
|
);
|
|
|
|
|
|
Angestellter a3 = new Angestellter(
|
|
|
3, "Meier", "Clara", "30161", "Hannover",
|
|
|
"Parkweg", LocalDate.of(2021, 1, 10),
|
|
|
LocalDate.of(1998, 2, 20), 2300.00
|
|
|
);
|
|
|
|
|
|
Projekt p1 = new Projekt("BPMN", "Hannover",
|
|
|
LocalDate.of(2024, 1, 1));
|
|
|
|
|
|
Projekt p2 = new Projekt("Prozessoptimierung", "Bremen",
|
|
|
LocalDate.of(2024, 4, 1));
|
|
|
|
|
Angestellte einer Abteilung zuordnen |
|
|
entwicklung.addMitarbeiter(a1);
|
|
|
entwicklung.addMitarbeiter(a2);
|
|
|
verwaltung.addMitarbeiter(a3);
|
|
|
|
|
PC zuordnen |
|
|
a1.setPc(pc1);
|
|
|
a2.setPc(pc2);
|
|
|
|
|
Projektzuordnungen |
|
|
a1.addProjekt(p1);
|
|
|
a1.addProjekt(p2);
|
|
|
a2.addProjekt(p1);
|
|
|
a3.addProjekt(p2);
|
|
|
|
|
Vorgesetztenbeziehung |
|
|
a1.addUntergebener(a2);
|
|
|
a1.addUntergebener(a3);
|
|
|
|
|
|
a1.anzeigen();
|
|
|
a2.anzeigen();
|
|
|
a3.anzeigen();
|
|
|
|
|
|
System.out.println("\nAbteilungen:");
|
|
|
entwicklung.anzeigen();
|
|
|
verwaltung.anzeigen();
|
|
|
|
|
|
System.out.println("\nProjekte:");
|
|
|
p1.anzeigen();
|
|
|
p2.anzeigen();
|
|
|
}
|
|
|
}
|
|
Klasse Abteilung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Abteilung {
|
|
|
String abtBez;
|
|
|
String abtLeitNa;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Abteilung(String abtBez, String abtLeitNa, String standort) {
|
|
|
this.abtBez = abtBez;
|
|
|
this.abtLeitNa = abtLeitNa;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter angestellter) {
|
|
|
if (!mitarbeiter.contains(angestellter)) {
|
|
|
mitarbeiter.add(angestellter);
|
|
|
angestellter.setAbteilung(this);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(abtBez + " (" + standort + ")");
|
|
|
System.out.println("Leitung: " + abtLeitNa);
|
|
|
System.out.println("Mitarbeiter:");
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
System.out.println("- " + a.vname + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Angestellter |
|
|
package firma;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vname;
|
|
|
String plz;
|
|
|
String ort;
|
|
|
String strasse;
|
|
|
LocalDate datumEinst;
|
|
|
LocalDate gebTag;
|
|
|
double gehalt;
|
|
|
|
|
|
Abteilung abteilung;
|
|
|
PC pc;
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
|
|
|
Angestellter vorgesetzter;
|
|
|
List<Angestellter> untergebene = new ArrayList<>();
|
|
|
|
|
|
Angestellter(int persNr, String name, String vname,
|
|
|
String plz, String ort, String strasse,
|
|
|
LocalDate datumEinst, LocalDate gebTag,
|
|
|
double gehalt) {
|
|
|
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vname = vname;
|
|
|
this.plz = plz;
|
|
|
this.ort = ort;
|
|
|
this.strasse = strasse;
|
|
|
this.datumEinst = datumEinst;
|
|
|
this.gebTag = gebTag;
|
|
|
this.gehalt = gehalt;
|
|
|
}
|
|
|
|
|
|
void addProjekt(Projekt projekt) {
|
|
|
if (!projekte.contains(projekt)) {
|
|
|
projekte.add(projekt);
|
|
|
projekt.addMitarbeiter(this);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void setAbteilung(Abteilung abteilung) {
|
|
|
this.abteilung = abteilung;
|
|
|
}
|
|
|
|
|
|
void setPc(PC pc) {
|
|
|
this.pc = pc;
|
|
|
}
|
|
|
|
|
|
void addUntergebener(Angestellter angestellter) {
|
|
|
untergebene.add(angestellter);
|
|
|
angestellter.vorgesetzter = this;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("\nAngestellter: " + vname + " " + name);
|
|
|
System.out.println("Personalnummer: " + persNr);
|
|
|
System.out.println("Gehalt: " + gehalt);
|
|
|
|
|
|
if (abteilung != null) {
|
|
|
System.out.println("Abteilung: " + abteilung.abtBez);
|
|
|
}
|
|
|
|
|
|
if (pc != null) {
|
|
|
System.out.println("PC: " + pc.bez);
|
|
|
}
|
|
|
|
|
|
System.out.println("Projekte:");
|
|
|
for (Projekt p : projekte) {
|
|
|
System.out.println("- " + p.bez);
|
|
|
}
|
|
|
|
|
|
if (vorgesetzter != null) {
|
|
|
System.out.println("Vorgesetzter: "
|
|
|
+ vorgesetzter.vname + " " + vorgesetzter.name);
|
|
|
}
|
|
|
|
|
|
if (!untergebene.isEmpty()) {
|
|
|
System.out.println("Untergebene:");
|
|
|
for (Angestellter u : untergebene) {
|
|
|
System.out.println("- " + u.vname + " " + u.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Projekt {
|
|
|
String bez;
|
|
|
String standort;
|
|
|
LocalDate tagEinrichtung;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Projekt(String bez, String standort, LocalDate tagEinrichtung) {
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
this.tagEinrichtung = tagEinrichtung;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter angestellter) {
|
|
|
if (!mitarbeiter.contains(angestellter)) {
|
|
|
mitarbeiter.add(angestellter);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(bez + " (" + standort + ")");
|
|
|
System.out.println("Mitarbeiter:");
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
System.out.println("- " + a.vname + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse PC |
|
|
package firma;
|
|
|
|
|
|
class PC {
|
|
|
int invNr;
|
|
|
String bez;
|
|
|
String typ;
|
|
|
|
|
|
PC(int invNr, String bez, String typ) {
|
|
|
this.invNr = invNr;
|
|
|
this.bez = bez;
|
|
|
this.typ = typ;
|
|
|
}
|
|
|
}
|
|
25.2.4 Ergebnis Programmlauf |
|
|
Angestellter: Anna Müller
|
|
|
Personalnummer: 1
|
|
|
Gehalt: 2500.0
|
|
|
Abteilung: Entwicklung
|
|
|
PC: Dell Optiplex
|
|
|
Projekte:
|
|
|
- BPMN
|
|
|
- Prozessoptimierung
|
|
|
Untergebene:
|
|
|
- Bernd Schmidt
|
|
|
- Clara Meier
|
|
|
|
|
|
Angestellter: Bernd Schmidt
|
|
|
Personalnummer: 2
|
|
|
Gehalt: 2800.0
|
|
|
Abteilung: Entwicklung
|
|
|
PC: Lenovo ThinkPad
|
|
|
Projekte:
|
|
|
- BPMN
|
|
|
Vorgesetzter: Anna Müller
|
|
|
|
|
|
Angestellter: Clara Meier
|
|
|
Personalnummer: 3
|
|
|
Gehalt: 2300.0
|
|
|
Abteilung: Verwaltung
|
|
|
Projekte:
|
|
|
- Prozessoptimierung
|
|
|
Vorgesetzter: Anna Müller
|
|
|
|
|
|
Abteilungen:
|
|
|
Entwicklung (Hannover)
|
|
|
Leitung: Dr. Weber
|
|
|
Mitarbeiter:
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
Verwaltung (Bremen)
|
|
|
Leitung: Frau König
|
|
|
Mitarbeiter:
|
|
|
- Clara Meier
|
|
|
|
|
|
Projekte:
|
|
|
BPMN (Hannover)
|
|
|
Mitarbeiter:
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
Prozessoptimierung (Bremen)
|
|
|
Mitarbeiter:
|
|
|
- Anna Müller
|
|
|
- Clara Meier
|
|
25.2.5 Betrachtete Themen |
|
- 1:1-Beziehung
- 1:n-Beziehung
- Attribute und Methoden
- bidirektionale Beziehungen
- foreach-Schleife
- Konstruktoren
- List als Schnittstellentyp
- Listen mit ArrayList
- LocalDate
- mehrere Klassen
- n:m-Beziehung
- Objekte als Listenelemente
- Objekte und Objektreferenzen
- objektorientierte Modellierung
- Pflege konsistenter Objektverknüpfungen
- Selbstbeziehung
- Umsetzung eines UML-Klassendiagramms in Java
- Vermeidung doppelter Listeneinträge mit contains()
|
|
25.2.6 Anmerkung |
|
In dieser Aufgabe werden mehrere Beziehungstypen kombiniert. Eine Abteilung besitzt mehrere Angestellte. Ein Angestellter gehört zu einer Abteilung. Zwischen Angestellten und Projekten besteht eine n:m-Beziehung. Außerdem gibt es eine rekursive Beziehung bei Angestellten: Ein Angestellter kann Vorgesetzter anderer Angestellter sein. |
|
|
|
Aufgabe 24 - Beschäftigung |
|
Klassen verknüpfen |
|
25.2.7 Aufgabenstellung |
|
Hier geht es um Abteilungen und Angestellte und um die 1:n-Beziehung zwischen ihnen. Erstellen Sie die Klassen: |
|
Angestellter mit den Attributen: |
|
|
|
|
und Abteilung mit den Attributen: |
|
|
|
|
Legen Sie zwei Abteilungen und drei Angestellte an. Ordnen Sie jeden Angestellten genau einer Abteilung zu. Lassen Sie vom Programm die Angestellten mit ihrer Abteilungszugehörigkeit ausgeben. Etwa so: |
|
|
Anna Müller arbeitet in der Abteilung Entwicklung.
|
|
25.2.8 Lernziele |
|
Hier wird gezeigt, wie Klassen miteinander verknüpft werden, um einen realitätsnahen Anwendungsbereich abzubilden, wie also Beziehungen zwischen Objekten mithilfe von Referenzen und Sammlungen modelliert und verwaltet werden. |
|
|
|
25.2.9 Lösung |
|
|
package firma;
|
|
|
|
|
|
class Abteilung {
|
|
|
String abtBez;
|
|
|
String standort;
|
|
|
|
|
|
Abteilung(String abtBez, String standort) {
|
|
|
this.abtBez = abtBez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
Abteilung abteilung;
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName, Abteilung abteilung) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
this.abteilung = abteilung;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(vName + " " + name
|
|
|
+ " arbeitet in der Abteilung "
|
|
|
+ abteilung.abtBez + ".");
|
|
|
}
|
|
|
}
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe24 {
|
|
|
public static void main(String[] args) {
|
|
|
Abteilung a1 = new Abteilung("Entwicklung", "Hannover");
|
|
|
Abteilung a2 = new Abteilung("Verwaltung", "Bremen");
|
|
|
|
|
|
Angestellter m1 = new Angestellter(1, "Müller", "Anna", a1);
|
|
|
Angestellter m2 = new Angestellter(2, "Schmidt", "Bernd", a1);
|
|
|
Angestellter m3 = new Angestellter(3, "Meier", "Clara", a2);
|
|
|
|
|
|
m1.anzeigen();
|
|
|
m2.anzeigen();
|
|
|
m3.anzeigen();
|
|
|
}
|
|
|
}
|
|
25.2.10 Ergebnis Programmlauf |
|
|
Anna Müller arbeitet in der Abteilung Entwicklung.
|
|
|
Bernd Schmidt arbeitet in der Abteilung Entwicklung.
|
|
|
Clara Meier arbeitet in der Abteilung Verwaltung.
|
|
25.2.11 Betrachtete Themen |
|
- Assoziationen
- Attribute
- Bildschirmausgabe
- Einfache 1:n-Beziehung
- Klassen
- Klassenverknüpfungen
- Konstruktoren
- Methoden
- Navigation zwischen Objekten
- Objektattribute
- Objekte
- Objekte als Attribute
- Objekterzeugung mit new
- Objektorientierte Modellierung
- Objektreferenzen
- Übergabe von Objekten an Konstruktoren
- Unidirektionale Beziehungen
|
|
25.2.12 Erläuterung |
|
Die eigentliche Verknüpfung befindet sich in der Klasse Angestellter: |
|
|
Abteilung abteilung;
|
|
Hier wird keine Abteilungsbezeichnung gespeichert, sondern eine Referenz auf ein Objekt der Klasse Abteilung. Beim Erzeugen eines Angestellten wird das Abteilungsobjekt übergeben: |
|
|
Angestellter m1 =
|
|
|
new Angestellter(1, "Müller", "Anna", a1);
|
|
Der Angestellte "kennt" dadurch seine Abteilung und kann auf deren Attribute zugreifen: |
|
|
abteilung.abtBez
|
|
|
abteilung.standort
|
|
Beziehungen |
|
Zu einer Abteilung können mehrere Angestellte gehören. Ein Angestellter gehört genau einer Abteilung. Im Programm wird die Beziehung bisher nur in einer Richtung gespeichert: |
|
|
Angestellter -> Abteilung
|
|
Von einem Angestellten kann also auf seine Abteilung zugegriffen werden. Von einer Abteilung aus kann dagegen noch nicht festgestellt werden, welche Angestellten dort arbeiten. Dies wird in der folgenden Aufgabe ergänzt. |
|
|
|
25.3 Aufgabe 25 - Abteilungszugehörigkeit |
|
Mehrere Mitarbeiter pro Abteilung |
|
25.3.1 Aufgabenstellung |
|
Erweitern Sie Aufgabe 24. Eine Abteilung soll nun mehrere Angestellte enthalten. Verwenden Sie dazu eine Liste: |
|
|
List<Angestellter>
|
|
Legen Sie mindestens zwei Abteilungen und drei Angestellte an. Ordnen Sie die Angestellten den Abteilungen zu und geben Sie anschließend alle Mitarbeiter einer Abteilung aus, in etwa so wie hier unten gezeigt. |
|
25.3.2 Ergebnis Programmlauf |
|
|
Abteilung Entwicklung
|
|
|
Standort: Hannover
|
|
|
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
|
|
|
Abteilung Verwaltung
|
|
|
Standort: Bremen
|
|
|
|
|
|
- Clara Meier
|
|
25.3.3 Lernziele |
|
Aufbauend auf Aufgabe 24 erweitern Sie das dort entwickelte Klassenmodell zu einer umfassenderen objektorientierten Anwendung. Sie lernen, bestehende Klassen und Beziehungen sinnvoll zu ergänzen, mehrere Objekte miteinander zu verknüpfen und die Zusammenarbeit der Klassen in einer realitätsnahen Anwendung zu verstehen und umzusetzen. |
|
|
|
25.3.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Abteilung {
|
|
|
String abtBez;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Abteilung(String abtBez, String standort) {
|
|
|
this.abtBez = abtBez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
mitarbeiter.add(a);
|
|
|
a.abteilung = this;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("\nAbteilung " + abtBez);
|
|
|
System.out.println("Standort: " + standort);
|
|
|
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
System.out.println("- " + a.vName + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
Abteilung abteilung;
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe25 {
|
|
|
public static void main(String[] args) {
|
|
|
Abteilung entwicklung = new Abteilung("Entwicklung", "Hannover");
|
|
|
Abteilung verwaltung = new Abteilung("Verwaltung", "Bremen");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna");
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd");
|
|
|
Angestellter a3 = new Angestellter(3, "Meier", "Clara");
|
|
|
|
|
|
entwicklung.addMitarbeiter(a1);
|
|
|
entwicklung.addMitarbeiter(a2);
|
|
|
verwaltung.addMitarbeiter(a3);
|
|
|
|
|
|
entwicklung.anzeigen();
|
|
|
verwaltung.anzeigen();
|
|
|
}
|
|
|
}
|
|
25.3.5 Ergebnis Programmlauf |
|
|
Abteilung Entwicklung
|
|
|
Standort: Hannover
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
|
|
|
Abteilung Verwaltung
|
|
|
Standort: Bremen
|
|
|
- Clara Meier
|
|
25.3.6 Betrachtete Themen |
|
- 1:n-Beziehungen
- ArrayList
- Assoziationen
- Bidirektionale Beziehung
- ForEach-Schleife
- Generics (List<Angestellter>)
- Hinzufügen von Objekten zu Listen
- Iteration über Objektmengen
- Klassen
- Klassenverknüpfungen
- Konstruktoren
- Listen (List)
- Methoden zur Verwaltung von Beziehungen
- Objektattribute
- Objekte
- Objekte als Attribute
- Objekterzeugung mit new
- Objektorientierte Modellierung
- Objektreferenzen
|
|
25.3.7 Erläuterung |
|
Die wesentliche Erweiterung gegenüber Aufgabe 24 befindet sich in der Klasse Abteilung: |
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
Dadurch kann eine Abteilung beliebig viele Angestellte verwalten. Neue Mitarbeiter werden über die Methode |
|
|
void addMitarbeiter(Angestellter a)
|
|
eingefügt: |
|
|
entwicklung.addMitarbeiter(a1);
|
|
|
entwicklung.addMitarbeiter(a2);
|
|
Die Liste wächst dabei automatisch. |
|
Die Beziehung |
|
Die Methode |
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
mitarbeiter.add(a);
|
|
|
a.abteilung = this;
|
|
|
}
|
|
erledigt zwei Dinge: |
|
|
mitarbeiter.add(a);
|
|
fügt den Mitarbeiter in die Mitarbeiterliste der Abteilung ein. |
|
|
a.abteilung = this;
|
|
trägt zusätzlich die Abteilung beim Mitarbeiter ein. Dadurch entsteht eine Beziehung in beide Richtungen: |
|
|
Abteilung <------> Angestellter
|
|
Warum List<Angestellter>? |
|
Früher hätte man beispielsweise schreiben können: |
|
|
Angestellter[] mitarbeiter = new Angestellter[100];
|
|
Das hätte einige Nachteile: |
|
- maximale Größe fest vorgegeben
- eventuell viele ungenutzte Plätze
- Verwaltung der freien Plätze erforderlich
|
|
Mit |
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
wächst die Liste automatisch. Deshalb werden in modernen Java-Programmen für 1:n-Beziehungen meist Listen verwendet. |
|
Theorieaspekte |
|
Diese Aufgabe stellt einen wichtigen Schritt in Richtung realistischer Objektmodelle dar. In Aufgabe 24 wurde lediglich gespeichert: |
|
|
Angestellter -> Abteilung
|
|
Nun wird zusätzlich gespeichert: |
|
|
Abteilung -> Angestellter
|
|
Damit entsteht eine bidirektionale 1:n-Beziehung. |
|
|
|
25.4 Aufgabe 26 - PC |
|
PC-Zuordnung zu Angestellten |
|
25.4.1 Aufgabenstellung |
|
Erstellen Sie zusätzlich zu den Klassen der vorigen Aufgabe eine Klasse PC mit den Attributen: |
|
|
|
|
Ordnen Sie einigen Angestellten einen PC zu. Geben Sie anschließend aus, welcher Angestellte welchen PC nutzt, etwa so: |
|
|
Anna Müller benutzt Dell Optiplex.
|
|
Hinweis: Ein PC ist nur einem einzigen Angestellten zugeordnet. |
|
25.4.2 Lernziele |
|
Hier wird gezeigt, wie Objekte verschiedener Klassen miteinander verknüpft werden. Sie verstehen, wie Referenzen genutzt werden, um Beziehungen zwischen Objekten herzustellen und Informationen über verknüpfte Objekte auszugeben. Dadurch vertiefen sie ihr Verständnis für Klassenbeziehungen und die Zusammenarbeit mehrerer Klassen in einem objektorientierten Programm. |
|
|
|
25.4.3 Lösung |
|
|
package firma;
|
|
|
|
|
|
class PC {
|
|
|
int invNr;
|
|
|
String bez;
|
|
|
String typ;
|
|
|
|
|
|
PC(int invNr, String bez, String typ) {
|
|
|
this.invNr = invNr;
|
|
|
this.bez = bez;
|
|
|
this.typ = typ;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
PC pc;
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
|
|
|
void setPc(PC pc) {
|
|
|
this.pc = pc;
|
|
|
}
|
|
|
|
|
|
void anzeigenPc() {
|
|
|
if (pc != null) {
|
|
|
System.out.println(vName + " " + name + " benutzt " + pc.bez + ".");
|
|
|
} else {
|
|
|
System.out.println(vName + " " + name + " hat keinen PC.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe26 {
|
|
|
public static void main(String[] args) {
|
|
|
PC pc1 = new PC(1001, "Dell Optiplex", "Desktop");
|
|
|
PC pc2 = new PC(1002, "Lenovo ThinkPad", "Notebook");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna");
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd");
|
|
|
Angestellter a3 = new Angestellter(3, "Meier", "Clara");
|
|
|
|
|
|
a1.setPc(pc1);
|
|
|
a2.setPc(pc2);
|
|
|
|
|
|
a1.anzeigenPc();
|
|
|
a2.anzeigenPc();
|
|
|
a3.anzeigenPc();
|
|
|
}
|
|
|
}
|
|
25.4.4 Ergebnis Programmlauf |
|
|
Anna Müller benutzt Dell Optiplex.
|
|
|
Bernd Schmidt benutzt Lenovo ThinkPad.
|
|
|
Clara Meier hat keinen PC.
|
|
25.4.5 Betrachtete Themen |
|
- Assoziationen
- Bedingte Anweisungen (if)
- Einfache 1:1-Beziehung
- Klassen
- Klassenverknüpfungen
- Konstruktoren
- Methoden
- Objektattribute
- Objekte
- Objekte als Attribute
- Objekterzeugung mit new
- Objektorientierte Modellierung
- Objektreferenzen
- Optionale Objektzuordnungen
- Referenzattribute
- Setter-Methode
- Vergleich mit null
|
|
25.4.6 Erläuterung |
|
Die eigentliche Verknüpfung befindet sich in der Klasse Angestellter: PC pc; Hier wird nicht die Inventarnummer oder die Bezeichnung gespeichert, sondern eine Referenz auf ein Objekt der Klasse PC. Durch a1.setPc(pc1); wird die Verbindung zwischen dem Angestellten und dem PC hergestellt. Danach kann über die Referenz auf die Attribute des PCs zugegriffen werden: |
|
|
pc.bez
|
|
|
pc.typ
|
|
|
pc.invNr
|
|
Beispielsweise: |
|
|
System.out.println(pc.bez);
|
|
liefert: |
|
|
Dell Optiplex
|
|
Welche Kardinalität liegt vor? |
|
Im Programm besitzt jeder Angestellte höchstens einen PC: |
|
|
PC pc;
|
|
Es gibt also keine Liste von PCs. Damit gilt auf der Seite des Angestellten: |
|
|
0,1
|
|
Ein Angestellter kann einen PC besitzen oder keinen. Auf der Seite des PCs existiert noch keine Gegenreferenz: |
|
|
Angestellter angestellter;
|
|
ist nicht vorhanden. Deshalb ist die Beziehung zunächst unidirektional: |
|
|
Angestellter -> PC
|
|
Inhaltlich ist jedoch beabsichtigt: |
|
|
Angestellter 0,1 ----- 0,1 PC
|
|
also eine optionale 1:1-Beziehung. |
|
Theorieaspekte |
|
Diese Aufgabe ergänzt das bisherige Unternehmensmodell um eine weitere Objektbeziehung. Während die bisherigen Aufgaben hauptsächlich 1:n-Beziehungen behandelt haben, wird hier eine 1:1-Beziehung modelliert. Besonders wichtig ist dabei die Verwendung eines Referenzattributes PC pc; |
|
|
|
25.5 Aufgabe 27 - Projekte |
|
Angestellte und Projekte |
|
25.5.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Angestellter mit den Attributen |
|
- int persNr
- String name
- String vName
|
|
Außerdem eine Klasse Projekt mit den Attributen: |
|
|
|
|
Ordnen Sie Projekte den Angestellten zu: Ein Angestellter kann in mehreren Projekten arbeiten. Beispiel für eine Auswertung: |
|
|
Anna Müller:
|
|
|
- BPMN
|
|
|
- Prozessoptimierung
|
|
25.5.2 Lernziele |
|
Sie lernen, wie 1:n-Beziehungen zwischen Objekten mit Listen umgesetzt werden, verstehen, wie einem Objekt mehrere andere Objekte zugeordnet und diese Beziehungen verwaltet sowie ausgegeben werden können. |
|
|
|
25.5.3 Lösung |
|
|
package firma;
|
|
|
|
|
|
class Projekt {
|
|
|
String bez;
|
|
|
String standort;
|
|
|
|
|
|
Projekt(String bez, String standort) {
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
|
|
|
void addProjekt(Projekt p) {
|
|
|
projekte.add(p);
|
|
|
}
|
|
|
|
|
|
void zeigeProjekte() {
|
|
|
System.out.println("\n" + vName + " " + name + " arbeitet in:");
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
System.out.println("- " + p.bez);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe27 {
|
|
|
public static void main(String[] args) {
|
|
|
Projekt p1 = new Projekt("BPMN", "Hannover");
|
|
|
Projekt p2 = new Projekt("Prozessoptimierung", "Bremen");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna");
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd");
|
|
|
|
|
|
a1.addProjekt(p1);
|
|
|
a1.addProjekt(p2);
|
|
|
a2.addProjekt(p1);
|
|
|
|
|
|
a1.zeigeProjekte();
|
|
|
a2.zeigeProjekte();
|
|
|
}
|
|
|
}
|
|
25.5.4 Ergebnis Programmlauf |
|
|
Anna Müller arbeitet in:
|
|
|
- BPMN
|
|
|
- Prozessoptimierung
|
|
|
|
|
|
Bernd Schmidt arbeitet in:
|
|
|
- BPMN
|
|
25.5.5 Betrachtete Themen |
|
- add()-Methode
- ArrayList
- Attribute einer Klasse
- Ausgabe von Objektdaten
- eigene Klasse Projekt
- eigene Methode addProjekt()
- einfache 1
- foreach-Schleife
- Konstruktor
- List<Projekt>
- mehrwertiges Attribut
- Objekterzeugung mit new
- Objektreferenzen
- Zuordnung von Projekten zu Angestellten
- Zusammenarbeit mehrerer Klassen
|
|
|
|
26 Übungsaufgaben Teil 7 |
|
|
|
26.1 Aufgabe 28 - n:m-Beziehung |
|
26.1.1 Aufgabenstellung |
|
Erweitern Sie Aufgabe 27. Nun soll auch von jedem Projekt auf die Angestellten geschlossen werden können, die in ihm mitarbeiten. Verwenden Sie: |
|
|
List<Projekt>
|
|
in der Klasse Angestellter und |
|
|
List<Angestellter>
|
|
in der Klasse Projekt. |
|
Beispielhafte Ausgabe: |
|
|
Projekt BPMN
|
|
|
|
|
|
Anna Müller
|
|
|
Bernd Schmidt
|
|
26.1.2 Lernziele |
|
Hier kann man lernen, wie eine n:m-Beziehung zwischen zwei Klassen in Java umgesetzt wird. Sie verstehen, wie Objekte beider Klassen gegenseitig miteinander verknüpft werden und wie die Beziehungen mithilfe von Listen verwaltet werden können. |
|
|
|
26.1.3 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
|
|
|
void addProjekt(Projekt p) {
|
|
|
if (!projekte.contains(p)) {
|
|
|
projekte.add(p);
|
|
|
p.addMitarbeiter(this);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void zeigeProjekte() {
|
|
|
System.out.println("\nProjekte von " + vName + " " + name + ":");
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
System.out.println("- " + p.bez);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Projekt {
|
|
|
String bez;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Projekt(String bez, String standort) {
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
if (!mitarbeiter.contains(a)) {
|
|
|
mitarbeiter.add(a);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void zeigeMitarbeiter() {
|
|
|
System.out.println("\nProjekt " + bez + ":");
|
|
|
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
System.out.println("- " + a.vName + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe28 {
|
|
|
public static void main(String[] args) {
|
|
|
Projekt p1 = new Projekt("BPMN", "Hannover");
|
|
|
Projekt p2 = new Projekt("Prozessoptimierung", "Bremen");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna");
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd");
|
|
|
Angestellter a3 = new Angestellter(3, "Meier", "Clara");
|
|
|
|
|
|
a1.addProjekt(p1);
|
|
|
a1.addProjekt(p2);
|
|
|
a2.addProjekt(p1);
|
|
|
a3.addProjekt(p2);
|
|
|
|
|
|
a1.zeigeProjekte();
|
|
|
a2.zeigeProjekte();
|
|
|
|
|
|
p1.zeigeMitarbeiter();
|
|
|
p2.zeigeMitarbeiter();
|
|
|
}
|
|
|
}
|
|
26.1.4 Ergebnis Programmlauf |
|
|
Projekte von Anna Müller:
|
|
|
- BPMN
|
|
|
- Prozessoptimierung
|
|
|
|
|
|
Projekte von Bernd Schmidt:
|
|
|
- BPMN
|
|
|
|
|
|
Projekt BPMN:
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
|
|
|
Projekt Prozessoptimierung:
|
|
|
- Anna Müller
|
|
|
- Clara Meier
|
|
26.1.5 Betrachtete Themen |
|
- ArrayList
- Ausgabe aus beiden Beziehungsrichtungen
- bidirektionale Beziehung
- bidirektionale n:m-Beziehung
- contains()-Methode
- eigene Methoden addProjekt() und addMitarbeiter()
- foreach-Schleife
- gegenseitige Aktualisierung von Beziehungen
- Konsistenz von Verknüpfungen
- List
- mehrwertige Attribute
- n:m-Beziehung
- Objektreferenzen
- this-Referenz
- Verknüpfung von Objekten
- Vermeidung doppelter Einträge
- Zusammenarbeit mehrerer Klassen
|
|
|
|
26.2 Aufgabe 29 - Rekursive Beziehung |
|
Rekursive Beziehung: Eine Beziehung, bei der Objekte einer Klasse mit anderen Objekten derselben Klasse verknüpft werden. Beispiele sind Vorgesetzte und Untergebene oder Eltern- und Kindknoten in einem Baum. |
|
26.2.1 Aufgabenstellung |
|
Ein Angestellter kann Vorgesetzter anderer Angestellter sein. Legen Sie eine Klasse Angestellter (wie oben) an und setzen Sie folgende Struktur um: Müller ist Vorgesetzte von Schmidt und Meier. Geben Sie dann alle Untergebenen von Müller aus. |
|
Geben Sie mindestens die Daten ein, die im beispielhaften Programmlauf angeführt sind und erzeugen sie eine entsprechende Ausgabe. |
|
26.2.2 Lernziele |
|
Diese Aufgabe zeigt, wie hierarchische Beziehungen zwischen Objekten modelliert werden können. Sie verstehen, wie Vorgesetzte und Untergebene durch gegenseitige Referenzen miteinander verknüpft werden und wie sich solche Hierarchien in einem objektorientierten Programm darstellen und auswerten lassen. Dadurch vertiefen sie ihr Verständnis rekursiver Beziehungen innerhalb einer Klasse und deren praktische Umsetzung in Java. |
|
26.2.3 Ergebnis Programmlauf |
|
|
Untergebene von Anna Müller:
|
|
|
- Bernd Schmidt
|
|
|
- Clara Meier
|
|
|
Anna Müller hat keinen Vorgesetzten.
|
|
|
Bernd Schmidt ist untergeben von Anna Müller.
|
|
|
Clara Meier ist untergeben von Anna Müller.
|
|
|
|
26.2.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
|
|
|
Angestellter vorgesetzter;
|
|
|
List<Angestellter> untergebene = new ArrayList<>();
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
|
|
|
void addUntergebener(Angestellter a) {
|
|
|
untergebene.add(a);
|
|
|
a.vorgesetzter = this;
|
|
|
}
|
|
|
|
|
|
void zeigeUntergebene() {
|
|
|
System.out.println("\nUntergebene von " + vName + " " + name + ":");
|
|
|
|
|
|
for (Angestellter a : untergebene) {
|
|
|
System.out.println("- " + a.vName + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void zeigeVorgesetzten() {
|
|
|
if (vorgesetzter != null) {
|
|
|
System.out.println(vName + " " + name
|
|
|
+ " ist untergeben von "
|
|
|
+ vorgesetzter.vName + " " + vorgesetzter.name + ".");
|
|
|
} else {
|
|
|
System.out.println(vName + " " + name + " hat keinen Vorgesetzten.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe29 {
|
|
|
public static void main(String[] args) {
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna");
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd");
|
|
|
Angestellter a3 = new Angestellter(3, "Meier", "Clara");
|
|
|
|
|
|
a1.addUntergebener(a2);
|
|
|
a1.addUntergebener(a3);
|
|
|
|
|
|
a1.zeigeUntergebene();
|
|
|
|
|
|
a1.zeigeVorgesetzten();
|
|
|
a2.zeigeVorgesetzten();
|
|
|
a3.zeigeVorgesetzten();
|
|
|
}
|
|
|
}
|
|
26.2.5 Betrachtete Themen |
|
- 1:n-Selbstbeziehung
- ArrayList
- Attribut vom Typ der eigenen Klasse
- Aufbau einer Hierarchie
- Ausgabe von Hierarchien
- bidirektionale Beziehung innerhalb einer Klasse
- eigene Methode addUntergebener()
- foreach-Schleife
- gegenseitige Aktualisierung von Beziehungen
- List
- Objektreferenzen auf Objekte derselben Klasse
- Prüfung auf null
- rekursive Beziehung (Selbstbeziehung)
- this-Referenz
- Verknüpfung von Objekten
- Vorgesetzter-Untergebener-Beziehung
|
|
26.2.6 Erläuterung |
|
Die entscheidenden Zeilen sind |
|
|
Angestellter vorgesetzter;
|
|
und |
|
|
List<Angestellter> untergebene = new ArrayList<>();;
|
|
Mit ihnen wird die rekursive Beziehung eingerichtet. |
|
|
|
26.3 Aufgabe 30 - Gehaltsauswertung |
|
26.3.1 Aufgabenstellung |
|
Legen Sie eine Klasse Angestellter an mit den Attributen: |
|
- int persNr;
- String name;
- String vName;
- double gehalt;
|
|
Außerdem eine Klasse Abteilung mit den Attributen |
|
- String abtBez;
- String standort;
|
|
Geben Sie mindestens zwei Abteilungen und drei Angestellte ein und weisen Sie die Angestellten den Abteilungen so zu, dass die Daten in etwa so sind wie im beispielhaften Programmlauf. |
|
26.3.2 Lernziele |
|
Diese Aufgabe zeigt, wie sich Auswertungen über Objektsammlungen durchführen lassen. Sie verstehen, wie numerische Werte - beispielsweise Gehälter - aus mehreren Objekten ermittelt, aufsummiert und ausgewertet werden können. Damit vertiefen sie den Umgang mit Schleifen, Objektbeziehungen und Attributen und erkennen, wie betriebliche Kennzahlen in objektorientierten Programmen berechnet werden. |
|
26.3.3 Ergebnis Programmlauf |
|
|
Abteilung Entwicklung
|
|
|
Gehaltssumme: 6700.0 Euro
|
|
|
|
|
|
Abteilung Verwaltung
|
|
|
Gehaltssumme: 2800.0 Euro
|
|
|
|
26.3.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
double gehalt;
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName, double gehalt) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
this.gehalt = gehalt;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Abteilung {
|
|
|
String abtBez;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Abteilung(String abtBez, String standort) {
|
|
|
this.abtBez = abtBez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
mitarbeiter.add(a);
|
|
|
}
|
|
|
|
|
|
double berechneGehaltssumme() {
|
|
|
double summe = 0.0;
|
|
|
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
summe = summe + a.gehalt;
|
|
|
}
|
|
|
|
|
|
return summe;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("\nAbteilung " + abtBez);
|
|
|
System.out.println("Gehaltssumme: " + berechneGehaltssumme() + " Euro");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe30 {
|
|
|
public static void main(String[] args) {
|
|
|
Abteilung entwicklung = new Abteilung("Entwicklung", "Hannover");
|
|
|
Abteilung verwaltung = new Abteilung("Verwaltung", "Bremen");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna", 3200.00);
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd", 3500.00);
|
|
|
Angestellter a3 = new Angestellter(3, "Meier", "Clara", 2800.00);
|
|
|
|
|
|
entwicklung.addMitarbeiter(a1);
|
|
|
entwicklung.addMitarbeiter(a2);
|
|
|
verwaltung.addMitarbeiter(a3);
|
|
|
|
|
|
entwicklung.anzeigen();
|
|
|
verwaltung.anzeigen();
|
|
|
}
|
|
|
}
|
|
26.3.5 Betrachtete Themen |
|
- Aggregation von Daten
- Aggregationsfunktion berechneGehaltssumme()
- ArrayList
- Auswertung von Objektdaten
- foreach-Schleife
- List
- lokale Variable
- numerische Attribute (double)
- Objektlisten durchlaufen
- Rückgabewert einer Methode (double)
- Summenbildung über Objektattribute
- Zugriff auf Objektattribute
- Zusammenarbeit mehrerer Klassen
|
|
|
|
26.4 Aufgabe 31 - Projektstatistik |
|
26.4.1 Aufgabenstellung |
|
Richten Sie eine Klasse Projekt ein mit den Attributen |
|
- String bez;
- String standort;
|
|
Ebenso eine Klasse Angestellter mit den Attributen |
|
- int persNr;
- String name;
- String vName;
|
|
Richten Sie die zwei Projekte "BPMN" und "Prozessoptimierung" und mindestens drei Angestellte ein. Jedes Projekt verwaltet die ihm zugeordneten Mitarbeiter in einer Liste, setzen Sie dies um. Erweitern Sie außederm die Klasse Projekt um eine Methode zur Ermittlung der Anzahl Mitarbeiter eines Projekts. |
|
Weisen Sie die Angestellten den Projekten zu, etwa so, wie es der beispielhafte Programmlauf zeigt. |
|
26.4.2 Lernziele |
|
Hier wird gezeigt, wie Objekte gesucht und gezielt ausgewertet werden können. Sie verstehen, wie Sammlungen von Objekten durchlaufen werden, um anhand bestimmter Kriterien ein passendes Objekt zu finden und dessen Eigenschaften auszugeben. Dadurch vertiefen sie den Umgang mit Objektlisten, Schleifen und Bedingungen und erkennen, wie Suchfunktionen in objektorientierten Anwendungen umgesetzt werden können. |
|
26.4.3 Ergebnis Programmlauf |
|
|
Projekt BPMN: 2 Mitarbeiter
|
|
|
Projekt Prozessoptimierung: 2 Mitarbeiter
|
|
|
|
26.4.4 Lösung |
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Projekt {
|
|
|
|
|
|
String bez;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Projekt(String bez, String standort) {
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
|
|
|
if (!mitarbeiter.contains(a)) {
|
|
|
mitarbeiter.add(a);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int ermittleAnzahlMitarbeiter() {
|
|
|
return mitarbeiter.size();
|
|
|
}
|
|
|
|
|
|
void anzeigenStatistik() {
|
|
|
|
|
|
System.out.println(
|
|
|
"Projekt " + bez + ": "
|
|
|
+ ermittleAnzahlMitarbeiter()
|
|
|
+ " Mitarbeiter");
|
|
|
}
|
|
|
}
|
|
Klasse Angestellter |
|
|
package firma;
|
|
|
|
|
|
class Angestellter {int persNr;String name;String vName;
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe31 (HP) |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe31 {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Projekt p1 = new Projekt("BPMN", "Hannover");
|
|
|
|
|
|
Projekt p2 = new Projekt("Prozessoptimierung","Bremen");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1,"Müller","Anna");
|
|
|
|
|
|
Angestellter a2 =new Angestellter(2,"Schmidt","Bernd");
|
|
|
|
|
|
Angestellter a3 =new Angestellter(3,"Meier","Clara");
|
|
|
|
|
|
p1.addMitarbeiter(a1);
|
|
|
p1.addMitarbeiter(a2);
|
|
|
|
|
|
p2.addMitarbeiter(a1);
|
|
|
p2.addMitarbeiter(a3);
|
|
|
|
|
|
p1.anzeigenStatistik();
|
|
|
p2.anzeigenStatistik();
|
|
|
}
|
|
|
}
|
|
26.4.5 Betrachtete Themen |
|
- Listen (ArrayList)
- Generics (List<Angestellter>)
- Hinzufügen von Objekten zu Listen
- Methoden mit Rückgabewert
- Rückgabewert vom Typ int
- Aufruf von Methoden
- Verwendung von Rückgabewerten
- Auswertung von Objektlisten
- Methode size()
- Zählen von Objekten
- Einfache Statistikfunktionen
- Objekterzeugung mit new
- n:m-Beziehungen (Vorstufe)
|
|
26.4.6 Erläuterung |
|
Die Mitarbeiter eines Projekts werden in einer Liste gespeichert: |
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
Die Methode |
|
|
int ermittleAnzahlMitarbeiter()
|
|
liefert die Anzahl der in dieser Liste gespeicherten Mitarbeiter zurück. Dazu wird die Methode |
|
|
mitarbeiter.size()
|
|
verwendet. size() gehört zur Klasse ArrayList und liefert die Anzahl der aktuell gespeicherten Elemente. Die Methode |
|
|
int ermittleAnzahlMitarbeiter() {
|
|
|
return mitarbeiter.size();
|
|
|
}
|
|
liefert somit die Anzahl der einem Projekt zugeordneten Mitarbeiter. Dieser Rückgabewert wird anschließend in der Methode anzeigenStatistik() zur Ausgabe verwendet. |
|
|
|
26.5 Aufgabe 32 - Mini-Personalverwaltung |
|
Diese Aufgabe fasst die vorherigen Aufgaben zum Unternehmensgeschehen zusammen. |
|
26.5.1 Aufgabenstellung |
|
Erstellen Sie, aufbauend auf den bisher entwickelten Klassen, ein Programm für eine kleine Personalverwaltung. Das Programm soll mindestens folgende Objekte anlegen: |
|
- 5 Angestellte
- 2 Abteilungen
- 3 Projekte
- 3 PCs
|
|
- Ordnen Sie die Angestellten den Abteilungen zu.
- Ordnen Sie einzelnen Angestellten PCs zu.
- Ordnen Sie Angestellte mehreren Projekten zu.
- Richten Sie außerdem eine einfache Vorgesetztenstruktur ein.
|
|
Geben Sie anschließend aus: |
|
- alle Abteilungen mit ihren Mitarbeitern
- die Gehaltssumme jeder Abteilung
- alle Projekte mit ihren Mitarbeitern
- alle Mitarbeiter mit ihren Projekten
- alle Mitarbeiter mit ihren zugeordneten PCs
- die Anzahl der Mitarbeiter pro Projekt
- die Vorgesetztenstruktur
|
|
26.5.2 Lernziele |
|
Hier werden die zuvor erlernten Konzepte der objektorientierten Programmierung in einem größeren Gesamtprojekt angewandt. Sie lernen, mehrere miteinander verknüpfte Klassen zu einem konsistenten Anwendungssystem zusammenzuführen, Beziehungen zwischen Objekten zu modellieren und umfangreichere Datenstrukturen zu verwalten. Dadurch vertiefen sie ihr Verständnis für die objektorientierte Analyse und Umsetzung eines realitätsnahen Anwendungsbereichs sowie für das Zusammenspiel der verschiedenen OOP-Konzepte. |
|
|
|
26.5.3 Lösung |
|
Klasse Aufgabe32 (HP) |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe32 {
|
|
|
public static void main(String[] args) {
|
|
|
Abteilung entwicklung = new Abteilung("Entwicklung", "Hannover");
|
|
|
Abteilung verwaltung = new Abteilung("Verwaltung", "Bremen");
|
|
|
|
|
|
PC pc1 = new PC(1001, "Dell Optiplex", "Desktop");
|
|
|
PC pc2 = new PC(1002, "Lenovo ThinkPad", "Notebook");
|
|
|
PC pc3 = new PC(1003, "HP EliteBook", "Notebook");
|
|
|
|
|
|
Projekt p1 = new Projekt("BPMN", "Hannover");
|
|
|
Projekt p2 = new Projekt("Prozessoptimierung", "Bremen");
|
|
|
Projekt p3 = new Projekt("Datenmodellierung", "Hannover");
|
|
|
|
|
|
Angestellter a1 = new Angestellter(1, "Müller", "Anna", 4000.00);
|
|
|
Angestellter a2 = new Angestellter(2, "Schmidt", "Bernd", 3600.00);
|
|
|
Angestellter a3 = new Angestellter(3, "Meier", "Clara", 3100.00);
|
|
|
Angestellter a4 = new Angestellter(4, "Fischer", "David", 3300.00);
|
|
|
Angestellter a5 = new Angestellter(5, "Weber", "Eva", 2900.00);
|
|
|
|
|
|
entwicklung.addMitarbeiter(a1);
|
|
|
entwicklung.addMitarbeiter(a2);
|
|
|
entwicklung.addMitarbeiter(a3);
|
|
|
|
|
|
verwaltung.addMitarbeiter(a4);
|
|
|
verwaltung.addMitarbeiter(a5);
|
|
|
|
|
|
a1.setPc(pc1);
|
|
|
a2.setPc(pc2);
|
|
|
a4.setPc(pc3);
|
|
|
|
|
|
a1.addProjekt(p1);
|
|
|
a1.addProjekt(p2);
|
|
|
a2.addProjekt(p1);
|
|
|
a3.addProjekt(p3);
|
|
|
a4.addProjekt(p2);
|
|
|
a5.addProjekt(p3);
|
|
|
|
|
|
a1.addUntergebener(a2);
|
|
|
a1.addUntergebener(a3);
|
|
|
|
|
|
System.out.println("Abteilungen:");
|
|
|
entwicklung.anzeigen();
|
|
|
verwaltung.anzeigen();
|
|
|
|
|
|
System.out.println("\nProjekte:");
|
|
|
p1.zeigeMitarbeiter();
|
|
|
p2.zeigeMitarbeiter();
|
|
|
p3.zeigeMitarbeiter();
|
|
|
|
|
|
System.out.println("\nMitarbeiter mit Projekten:");
|
|
|
a1.zeigeProjekte();
|
|
|
a2.zeigeProjekte();
|
|
|
a3.zeigeProjekte();
|
|
|
a4.zeigeProjekte();
|
|
|
a5.zeigeProjekte();
|
|
|
|
|
|
System.out.println("\nProjektstatistik:");
|
|
|
p1.anzeigenStatistik();
|
|
|
p2.anzeigenStatistik();
|
|
|
p3.anzeigenStatistik();
|
|
|
|
|
|
System.out.println("\nVorgesetztenstruktur:");
|
|
|
a1.zeigeUntergebene();
|
|
|
}
|
|
|
}
|
|
Klasse Angestellter |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vName;
|
|
|
double gehalt;
|
|
|
|
|
|
Abteilung abteilung;
|
|
|
PC pc;
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
|
|
|
Angestellter vorgesetzter;
|
|
|
List<Angestellter> untergebene = new ArrayList<>();
|
|
|
|
|
|
Angestellter(int persNr, String name, String vName, double gehalt) {
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vName = vName;
|
|
|
this.gehalt = gehalt;
|
|
|
}
|
|
|
|
|
|
void setPc(PC pc) {
|
|
|
this.pc = pc;
|
|
|
}
|
|
|
void zeigePc() {
|
|
|
System.out.println(vName + " " + name + ":");
|
|
|
|
|
|
if (pc != null) {
|
|
|
System.out.println("- PC: " + pc.bez + " (" + pc.typ + ")");
|
|
|
} else {
|
|
|
System.out.println("- kein PC zugeordnet");
|
|
|
}
|
|
|
}
|
|
|
void addProjekt(Projekt p) {
|
|
|
if (!projekte.contains(p)) {
|
|
|
projekte.add(p);
|
|
|
p.addMitarbeiter(this);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void addUntergebener(Angestellter a) {
|
|
|
untergebene.add(a);
|
|
|
a.vorgesetzter = this;
|
|
|
}
|
|
|
|
|
|
void zeigeProjekte() {
|
|
|
System.out.println("\n" + vName + " " + name + ":");
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
System.out.println("- " + p.bez);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void zeigeUntergebene() {
|
|
|
System.out.println(vName + " " + name + " ist Vorgesetzter von:");
|
|
|
|
|
|
for (Angestellter a : untergebene) {
|
|
|
System.out.println("- " + a.vName + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
Klasse Abteilung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Abteilung {
|
|
|
String abtBez;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Abteilung(String abtBez, String standort) {
|
|
|
this.abtBez = abtBez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
mitarbeiter.add(a);
|
|
|
a.abteilung = this;
|
|
|
}
|
|
|
|
|
|
double berechneGehaltssumme() {
|
|
|
double summe = 0.0;
|
|
|
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
summe = summe + a.gehalt;
|
|
|
}
|
|
|
|
|
|
return summe;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("\nAbteilung " + abtBez);
|
|
|
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
System.out.println("- " + a.vName + " " + a.name);
|
|
|
}
|
|
|
|
|
|
System.out.println("Gehaltssumme: " + berechneGehaltssumme() + " Euro");
|
|
|
}
|
|
|
}
|
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Projekt {
|
|
|
String bez;
|
|
|
String standort;
|
|
|
|
|
|
List<Angestellter> mitarbeiter = new ArrayList<>();
|
|
|
|
|
|
Projekt(String bez, String standort) {
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void addMitarbeiter(Angestellter a) {
|
|
|
if (!mitarbeiter.contains(a)) {
|
|
|
mitarbeiter.add(a);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int ermittleAnzahlMitarbeiter() {
|
|
|
return mitarbeiter.size();
|
|
|
}
|
|
|
|
|
|
void zeigeMitarbeiter() {
|
|
|
System.out.println("\nProjekt " + bez + ":");
|
|
|
|
|
|
for (Angestellter a : mitarbeiter) {
|
|
|
System.out.println("- " + a.vName + " " + a.name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void anzeigenStatistik() {
|
|
|
System.out.println("Projekt " + bez + ": "
|
|
|
+ ermittleAnzahlMitarbeiter() + " Mitarbeiter");
|
|
|
}
|
|
|
}
|
|
Klasse PC |
|
|
package firma;
|
|
|
|
|
|
class PC {
|
|
|
int invNr;
|
|
|
String bez;
|
|
|
String typ;
|
|
|
|
|
|
PC(int invNr, String bez, String typ) {
|
|
|
this.invNr = invNr;
|
|
|
this.bez = bez;
|
|
|
this.typ = typ;
|
|
|
}
|
|
|
}
|
|
26.5.4 Ergebnis Programmlauf |
|
|
Abteilungen:
|
|
|
|
|
|
Abteilung Entwicklung
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
- Clara Meier
|
|
|
Gehaltssumme: 10700.0 Euro
|
|
|
|
|
|
Abteilung Verwaltung
|
|
|
- David Fischer
|
|
|
- Eva Weber
|
|
|
Gehaltssumme: 6200.0 Euro
|
|
|
|
|
|
Projekte:
|
|
|
|
|
|
Projekt BPMN:
|
|
|
- Anna Müller
|
|
|
- Bernd Schmidt
|
|
|
|
|
|
Projekt Prozessoptimierung:
|
|
|
- Anna Müller
|
|
|
- David Fischer
|
|
|
|
|
|
Projekt Datenmodellierung:
|
|
|
- Clara Meier
|
|
|
- Eva Weber
|
|
|
|
|
|
Mitarbeiter mit Projekten:
|
|
|
|
|
|
Anna Müller:
|
|
|
- BPMN
|
|
|
- Prozessoptimierung
|
|
|
|
|
|
Bernd Schmidt:
|
|
|
- BPMN
|
|
|
|
|
|
Clara Meier:
|
|
|
- Datenmodellierung
|
|
|
|
|
|
David Fischer:
|
|
|
- Prozessoptimierung
|
|
|
|
|
|
Eva Weber:
|
|
|
- Datenmodellierung
|
|
|
|
|
|
Mitarbeiter mit PCs:
|
|
|
Anna Müller:
|
|
|
- PC: Dell Optiplex (Desktop)
|
|
|
Bernd Schmidt:
|
|
|
- PC: Lenovo ThinkPad (Notebook)
|
|
|
Clara Meier:
|
|
|
- kein PC zugeordnet
|
|
|
David Fischer:
|
|
|
- PC: HP EliteBook (Notebook)
|
|
|
Eva Weber:
|
|
|
- kein PC zugeordnet
|
|
|
|
|
|
Projektstatistik:
|
|
|
Projekt BPMN: 2 Mitarbeiter
|
|
|
Projekt Prozessoptimierung: 2 Mitarbeiter
|
|
|
Projekt Datenmodellierung: 2 Mitarbeiter
|
|
|
|
|
|
Vorgesetztenstruktur:
|
|
|
Anna Müller ist Vorgesetzter von:
|
|
|
- Bernd Schmidt
|
|
|
- Clara Meier
|
|
26.5.5 Betrachtete Themen |
|
Zusammenführung der bisher behandelten Konzepte: |
|
- 1:1-Beziehungen
- 1:n-Beziehungen
- Aggregation von Objekten
- Attribute
- Auswertungsmethoden
- Bidirektionale Beziehungen
- einfache Statistikfunktionen
- ForEach-Schleifen
- Generics (List<Angestellter>)
- Klassen
- Konstruktoren
- Listen (ArrayList)
- Methoden
- Methoden mit Rückgabewert
- n:m-Beziehungen
- Objekte
- Objekterzeugung mit new
- Objektverweise
- Referenzen zwischen Objekten
- Schleifen über Listen
- Selbstbeziehungen
- strukturierte Bildschirmausgabe
- Summenbildung
- Zählung von Objekten
|
|
27 Übungsaufgaben Teil 8 |
|
Die folgenden Aufgaben vertiefen zentrale Konzepte der objektorientierten Programmierung in Java. Die Aufgaben bauen inhaltlich aufeinander auf. Ausgangspunkt ist jeweils das Beispiel einer einfachen Personalverwaltung mit Angestellten, Sachbearbeitern, Abteilungsleitern und Projekten. |
|
|
|
27.1 Aufgabe 33 - Vererbung |
|
27.1.1 Aufgabenstellung |
|
Erstellen Sie eine einfache Klassenhierarchie für Angestellte. Die Klasse Angestellter soll als Superklasse dienen. Sie enthält gemeinsame Attribute, die für alle Angestellten gelten. Aus dieser Klasse sollen zwei Subklassen abgeleitet werden: |
|
- Sachbearbeiter
- Abteilungsleiter
|
|
Die Klassen sollen folgende Attribute besitzen: |
|
Angestellter |
|
|
String name;
|
|
|
String vorname;
|
|
Sachbearbeiter |
|
|
String fachgebiet;
|
|
Abteilungsleiter |
|
|
double budget;
|
|
Legen Sie im Hauptprogramm je ein Objekt der Klassen Sachbearbeiter und Abteilungsleiter an. Weisen Sie den Attributen Werte zu und geben Sie die Daten auf dem Bildschirm aus. Beachten Sie dabei, dass die Subklassen sowohl ihre eigenen Attribute als auch die geerbten Attribute der Superklasse besitzen. |
|
27.1.2 Lernziele |
|
Hier wird wieder auf das Konzept der Vererbung eingegangen. Sie verstehen, wie gemeinsame Eigenschaften und Methoden in einer Oberklasse zusammengefasst und von Unterklassen übernommen werden können. Dadurch erkennen sie, wie Vererbung zur Wiederverwendung von Programmcode beiträgt und eine übersichtliche Modellierung verwandter Objekte ermöglicht. |
|
27.1.3 Ergebnis Programmlauf |
|
|
Sachbearbeiter:
|
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
|
|
|
Abteilungsleiter:
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
|
27.1.4 Lösung |
|
Klasse Angestellter, usw. |
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
}
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
}
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
}
|
|
Klasse Aufgabe33 |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe33 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Abteilungsleiter a1 = new Abteilungsleiter();
|
|
|
a1.name = "Schmidt";
|
|
|
a1.vorname = "Bernd";
|
|
|
a1.budget = 500000.0;
|
|
|
|
|
|
System.out.println("Sachbearbeiter:");
|
|
|
System.out.println(s1.vorname + " " + s1.name);
|
|
|
System.out.println("Fachgebiet: " + s1.fachgebiet);
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
System.out.println("Abteilungsleiter:");
|
|
|
System.out.println(a1.vorname + " " + a1.name);
|
|
|
System.out.println("Budget: " + a1.budget);
|
|
|
}
|
|
|
}
|
|
27.1.5 Betrachtete Themen |
|
- Bildschirmausgabe mit System.out.println()
- Eigene Attribute von Subklassen
- Geerbte Attribute
- Gemeinsame und spezielle Eigenschaften
- Klassenhierarchien
- Superklasse
- Objekterzeugung mit new
- Schlüsselwort extends
- Spezialisierung von Klassen
- Subklasse
- Vererbung
- Zugriff auf geerbte Attribute
|
|
27.1.6 Erläuterung |
|
Die Klasse Angestellter enthält die gemeinsamen Eigenschaften aller Angestellten. Sowohl Sachbearbeiter als auch Abteilungsleiter besitzen daher automatisch die Attribute name und vorname. Durch |
|
|
class Sachbearbeiter extends Angestellter
|
|
wird festgelegt, dass Sachbearbeiter eine Subklasse von Angestellter ist. Das bedeutet: Ein Sachbearbeiter ist ein Angestellter, besitzt aber zusätzlich ein eigenes Attribut fachgebiet. Ein Abteilungsleiter ist ebenfalls ein Angestellter, besitzt aber zusätzlich das Attribut budget. |
|
Theorieaspekte |
|
Diese Aufgabe demonstriert nochmals das Konzept der Vererbung. Dabei werden gemeinsame Eigenschaften in einer Superklasse zusammengefasst und von mehreren Subklassen wiederverwendet. Damit wird vermieden, dass identische Attribute mehrfach definiert werden müssen. Die Klassenhierarchie beschreibt eine sogenannte ist-ein-Beziehung: |
|
- Ein Sachbearbeiter ist ein Angestellter.
- Ein Abteilungsleiter ist ein Angestellter.
|
|
Vererbung ermöglicht somit eine übersichtliche und leicht erweiterbare Struktur objektorientierter Programme. Vgl. [Staud 2019] für eine ausführliche Darstellung. |
|
27.2 Aufgabe 34 - Override |
|
Überschreiben von Methoden |
|
27.2.1 Aufgabenstellung |
|
Erweitern Sie die Klassen aus der vorigen Aufgabe. Die Superklasse Angestellter soll eine Methode |
|
|
void anzeigen()
|
|
enthalten. |
|
Diese Methode soll in den Subklassen Sachbearbeiter und Abteilungsleiter überschrieben werden. Die Ausgabe soll je nach Objekt unterschiedlich sein: |
|
- Bei einem Sachbearbeiter sollen Name, Vorname und Fachgebiet ausgegeben werden.
- Bei einem Abteilungsleiter sollen Name, Vorname und Budget ausgegeben werden.
|
|
Legen Sie im Hauptprogramm einen Sachbearbeiter und einen Abteilungsleiter an und rufen Sie für beide Objekte die Methode anzeigen() auf. Beachten Sie, dass dieselbe Methode je nach Klasse ein unterschiedliches Verhalten zeigt. |
|
27.2.2 Lernziele |
|
Es geht um das Konzept des Überschreibens von Methoden (Overriding). Sie verstehen, wie Unterklassen Methoden einer Oberklasse mit einer eigenen Implementierung versehen können und wie dadurch ein an die jeweilige Objektklasse angepasstes Verhalten entsteht. Damit vertiefen sie ihr Verständnis der Vererbung und schaffen die Grundlage für das Konzept der Polymorphie. |
|
27.2.3 Ergebnis Programmlauf |
|
|
Sachbearbeiter:
|
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
|
|
|
Abteilungsleiter:
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
|
27.2.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println("Sachbearbeiter:");
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Fachgebiet: " + fachgebiet);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println("Abteilungsleiter:");
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Budget: " + budget);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe34 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Abteilungsleiter a1 = new Abteilungsleiter();
|
|
|
a1.name = "Schmidt";
|
|
|
a1.vorname = "Bernd";
|
|
|
a1.budget = 500000.0;
|
|
|
|
|
|
s1.anzeigen();
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
a1.anzeigen();
|
|
|
}
|
|
|
}
|
|
27.2.5 Betrachtete Themen |
|
- Annotation @Override
- Dynamische Methodenbindung
- Methoden
- Methoden überschreiben (Method Overriding)
- Methodenaufrufe
- Objektattribute
- Objekterzeugung mit new
- Polymorphes Verhalten (Vorstufe)
- Spezialisierung von Klassen
- Spezialisierung von Verhalten
- Super- und Subklassen
- Vererbung
- Vererbung von Methoden
|
|
27.2.6 Erläuterung |
|
Die Methode anzeigen() existiert bereits in der Superklasse Angestellter. In den Subklassen wird diese Methode neu definiert. Das nennt man Überschreiben oder Override. Die Annotation @Override ist nicht zwingend erforderlich, aber sehr empfehlenswert. Sie zeigt dem Compiler, dass eine Methode aus der Superklasse überschrieben werden soll. Dadurch kann Java prüfen, ob der Methodenname und die Parameter wirklich korrekt sind. |
|
|
|
27.3 Aufgabe 35 - Overload |
|
Überladen von Methoden |
|
27.3.1 Aufgabenstellung |
|
Erweitern Sie die Klasse Angestellter. Die Klasse soll drei Varianten der Methode anzeigen() enthalten: |
|
|
void anzeigen()
|
|
|
void anzeigen(boolean kurzform)
|
|
|
void anzeigen(String titel)
|
|
Alle drei Methoden sollen denselben Namen besitzen, sich jedoch durch ihre Parameterlisten unterscheiden. Implementieren Sie die Methoden wie folgt: |
|
- anzeigen() gibt die vollständigen Personendaten aus.
- anzeigen(true) gibt nur Vorname und Name in Kurzform aus.
- anzeigen(String titel) gibt zunächst eine Überschrift aus und anschließend die vollständigen Personendaten.
|
|
Legen Sie im Hauptprogramm einen Angestellten an und testen Sie alle drei Varianten der Methode. Die Ausgabe soll wie im beispielhaften Programmlauf aussehen. |
|
27.3.2 Lernziele |
|
Diese Aufgabe demonstriert das Konzept der Methodenüberladung (Overloading) kennen. Sie verstehen, dass mehrere Methoden denselben Namen tragen können, sofern sie sich in ihrer Parameterliste unterscheiden. Dadurch erkennen sie, wie Methoden für unterschiedliche Anwendungsfälle bereitgestellt werden können, ohne neue Methodennamen einführen zu müssen. |
|
27.3.3 Ergebnis Programmlauf |
|
|
Name: Müller
|
|
|
Vorname: Anna
|
|
|
|
|
|
Anna Müller
|
|
|
|
|
|
Mitarbeiterdaten:
|
|
|
------------------
|
|
|
Name: Müller
|
|
|
Vorname: Anna
|
|
|
|
27.3.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println("Name: " + name);
|
|
|
System.out.println("Vorname: " + vorname);
|
|
|
}
|
|
|
|
|
|
void anzeigen(boolean kurzform) {
|
|
|
if (kurzform) {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
} else {
|
|
|
anzeigen();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void anzeigen(String titel) {
|
|
|
System.out.println(titel);
|
|
|
System.out.println("--------------------");
|
|
|
anzeigen();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe35 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Angestellter a1 = new Angestellter();
|
|
|
a1.name = "Müller";
|
|
|
a1.vorname = "Anna";
|
|
|
|
|
|
a1.anzeigen();
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
a1.anzeigen(true);
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
a1.anzeigen("Mitarbeiterdaten");
|
|
|
}
|
|
|
}
|
|
27.3.5 Betrachtete Themen |
|
- Mehrere Methoden mit gleichem Namen
- Method Overloading (Methodenüberladung)
- Methoden
- Methodenaufrufe
- Methodenaufrufe innerhalb einer Methode
- Methodensignaturen
- Objektattribute
- Objekterzeugung mit new
- Parameterlisten
- Überladen von Methoden
- Unterschiedliche Parameterdatentypen
- Verzweigungen (if)
- Wiederverwendung von Methoden
|
|
27.3.6 Erläuterung |
|
In Java dürfen mehrere Methoden denselben Namen besitzen. Voraussetzung ist, dass sie sich in ihrer Parameterliste unterscheiden. Deshalb sind die Methoden oben zulässig. Der Compiler erkennt anhand der übergebenen Parameter, welche Methode aufgerufen werden soll. |
|
Beispiele |
|
- a1.anzeigen(); ruft auf: void anzeigen()
- a1.anzeigen(true); ruft auf: void anzeigen(boolean kurzform)
- a1.anzeigen("Mitarbeiterdaten"); ruft auf: void anzeigen(String titel)
|
|
Dieses Verfahren wird als Methodenüberladung (Method Overloading) bezeichnet. |
|
|
|
27.4 Aufgabe 36 - Abstraktes |
|
Abstrakte Klassen |
|
27.4.1 Aufgabenstellung |
|
In einem Unternehmen gibt es verschiedene Gruppen von Angestellten. Die allgemeine Klasse Angestellter dient dabei lediglich als gemeinsame Superklasse und soll nicht direkt zur Erzeugung von Objekten verwendet werden. Erstellen Sie deshalb die Klasse Angestellter als abstrakte Klasse. Die Klasse soll die Attribute |
|
|
|
|
sowie die Methoden |
|
|
|
|
Ergänzen Sie außerdem die abstrakte Methode |
|
|
abstract double berechneBonus();
|
|
Die Subklassen Sachbearbeiter und Abteilungsleiter sollen diese Methode konkret implementieren. Verwenden Sie dabei folgende Regeln: |
|
|
|
| Klasse |
Bonus |
| Sachbearbeiter |
500.0 |
| Abteilungsleiter |
5000.0 |
| |
|
|
Legen Sie im Hauptprogramm einen Sachbearbeiter und einen Abteilungsleiter an. Geben Sie für beide Objekte die Personendaten sowie den berechneten Bonus aus, wie im beispielhaften Programmlauf angegeben. |
|
27.4.2 Lernziele |
|
Hier geht es um abstrakte Klassen. Sie verstehen, dass abstrakte Klassen gemeinsame Eigenschaften und Methoden für mehrere Unterklassen bereitstellen können, ohne selbst instanziiert werden zu können. Außerdem lernen sie, abstrakte Methoden zu definieren, die von den Unterklassen verpflichtend implementiert werden müssen. Dadurch vertiefen sie ihr Verständnis der Vererbung und der gemeinsamen Modellierung ähnlicher Objekte. |
|
27.4.3 Ergebnis Programmlauf |
|
|
Anna Müller
|
|
|
Bonus: 500.0
|
|
|
|
|
|
Bernd Schmidt
|
|
|
Bonus: 5000.0
|
|
|
|
27.4.4 Lösung |
|
Klasse Angestellter usw. |
|
|
package firma;
|
|
|
|
|
|
abstract class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
}
|
|
|
|
|
|
abstract double berechneBonus();
|
|
|
}
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
|
|
|
@Override
|
|
|
double berechneBonus() {
|
|
|
return 500.0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
|
|
|
@Override
|
|
|
double berechneBonus() {
|
|
|
return 5000.0;
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe36 |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe36 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Abteilungsleiter a1 = new Abteilungsleiter();
|
|
|
a1.name = "Schmidt";
|
|
|
a1.vorname = "Bernd";
|
|
|
a1.budget = 500000.0;
|
|
|
|
|
|
s1.anzeigen();
|
|
|
System.out.println("Bonus: " + s1.berechneBonus());
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
a1.anzeigen();
|
|
|
System.out.println("Bonus: " + a1.berechneBonus());
|
|
|
}
|
|
|
}
|
|
27.4.5 Betrachtete Themen |
|
- Abstrakte Klassen
- Abstrakte Methoden
- Vererbung
- Super- und Subklassen
- Spezialisierung von Klassen
- Überschreiben von Methoden
- Annotation @Override
- Methoden mit Rückgabewert
- Rückgabewert vom Typ double
- Gemeinsame und spezialisierte Methoden
- Objekterzeugung mit new
- Methodenaufrufe
- Verhinderung direkter Objekterzeugung
- Verpflichtung zur Implementierung abstrakter Methoden
|
|
27.4.6 Erläuterung |
|
Eine abstrakte Klasse dient als Vorlage für andere Klassen. Sie kann gemeinsame Attribute und Methoden bereitstellen, soll aber selbst nicht zur Erzeugung von Objekten verwendet werden. Folgende Anweisung wäre also nicht erlaubt: |
|
|
Angestellter a = new Angestellter();
|
|
Der Grund: Die Klasse Angestellter enthält eine abstrakte Methode: |
|
Eine abstrakte Methode wie abstract double berechneBonus() besitzt keine Implementierung und endet deshalb mit einem Semikolon. Sie legt lediglich fest, dass jede konkrete Subklasse eine passende Methode bereitstellen muss. Die eigentliche Implementierung erfolgt in den Subklassen. Dadurch kann jede Subklasse ihr eigenes Verhalten festlegen, obwohl alle dieselbe Methodensignatur verwenden. |
|
Theorieaspekte |
|
Diese Aufgabe thematisiert zwei wichtige Konzepte der Objektorientierung: |
|
Abstraktion |
|
Die Klasse Angestellter beschreibt gemeinsame Eigenschaften aller Angestellten. Sie ist jedoch zu allgemein, um direkt als Objekt verwendet zu werden. |
|
Verpflichtende Spezialisierung |
|
Die abstrakte Methode berechneBonus() definiert eine Aufgabe, aber noch keine Lösung. Erst die Subklassen legen fest, wie der Bonus konkret berechnet wird. |
|
Dadurch entsteht eine klare Trennung zwischen allgemeinen Eigenschaften einer Superklasse und den spezifischen Eigenschaften ihrer Subklassen. |
|
|
|
28 Übungsaufgaben Teil 9 |
|
|
|
28.1 Aufgabe 37 - Interface |
|
28.1.1 Aufgabenstellung |
|
Richten Sie folgende Klassen ein: |
|
- Angestellter mit den Attributen name und vorname
- Sachbearbeiter mit dem Attribut fachgebiet
- Projekt mit dem Attribut bez
|
|
Erstellen Sie außerdem die Klasse Sachbearbeiter als Subklasse von Angestellter. |
|
In diesem Unternehmen sollen verschiedene Objekte ausgedruckt werden können. Erstellen Sie dazu ein Interface Druckbar mit der Methode void drucken(); |
|
Legen Sie im Hauptprogramm einen Sachbearbeiter und ein Projekt an und rufen Sie anschließend für beide Objekte die Methode drucken() auf. |
|
Die Klassen Angestellter und Projekt sollen dieses Interface implementieren. Die Methode drucken() soll jeweils eine sinnvolle Ausgabe erzeugen, etwa so wie im beispielhaften Programmlauf. |
|
28.1.2 Lernziele |
|
Hier geht es um das Konzept der Interfaces in Java. Sie verstehen, wie Interfaces gemeinsame Funktionalitäten unabhängig von einer Klassenhierarchie festlegen und wie Klassen diese durch die Implementierung der vorgegebenen Methoden bereitstellen. Dadurch erkennen sie, wie Interfaces zur besseren Strukturierung, Erweiterbarkeit und Wiederverwendbarkeit objektorientierter Programme beitragen. |
|
28.1.3 Ergebnis Programmlauf |
|
|
Angestellter: Anna Müller
|
|
|
Projekt: BPMN-Einführung
|
|
|
|
28.1.4 Lösung |
|
Klasse Projekt, usw. |
|
|
package firma;
|
|
|
|
|
|
interface Druckbar {
|
|
|
void drucken(); }
|
|
|
|
|
|
abstract class Angestellter implements Druckbar {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
@Override
|
|
|
public void drucken() {
|
|
|
System.out.println("Angestellter: " + vorname + " " + name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
}
|
|
|
|
|
|
class Projekt implements Druckbar {
|
|
|
String bez;
|
|
|
|
|
|
Projekt(String bez) {
|
|
|
this.bez = bez;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void drucken() {
|
|
|
System.out.println("Projekt: " + bez);
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe37 |
|
|
package firma;
|
|
|
|
|
|
public class Aufgabe37 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Projekt p1 = new Projekt("BPMN-Einführung");
|
|
|
|
|
|
s1.drucken();
|
|
|
p1.drucken();
|
|
|
}
|
|
|
}
|
|
28.1.5 Betrachtete Themen |
|
- Abstrakte Klassen
- Annotation @Override
- Definition eines Interfaces
- Gemeinsame Fähigkeiten unterschiedlicher Klassen
- Implementierung eines Interfaces
- Interfaces
- Methode im Interface
- Methodenaufrufe
- Methodensignatur
- Objekterzeugung mit new
- Schlüsselwort implements
- Subklassen
- Trennung von Verhalten und Klassenhierarchien
- Überschreiben von Methoden
- Vererbung
|
|
28.1.6 Erläuterung |
|
Ein Interface beschreibt eine Fähigkeit. Das Interface Druckbar sagt: |
|
- Jede Klasse, die dieses Interface implementiert, muss eine Methode drucken() besitzen.
|
|
Die Klassen Angestellter und Projekt sind fachlich völlig unterschiedliche Klassen. Trotzdem können beide druckbare Objekte besitzen. Damit beschreiben sie gemeinsames Verhalten unabhängig von einer gemeinsamen Superklasse. |
|
|
|
28.2 Aufgabe 38 - Mehrere Interfaces |
|
28.2.1 Aufgabenstellung |
|
Diese Aufgabe setzt Aufgabe 37 fort. |
|
Erstellen Sie zusätzlich zum Interface Druckbar ein weiteres Interface Suchbar. Dieses Interface soll folgende Methode enthalten: |
|
|
boolean suchen(String text);
|
|
Die Klasse Projekt soll nun beide Interfaces implementieren: |
|
|
|
|
Die Methode suchen(String text) soll prüfen, ob die Projektbezeichnung den gesuchten Text enthält. Legen Sie im Hauptprogramm ein Projektobjekt an und |
|
- geben Sie die Projektdaten mit der Methode drucken() aus,
- suchen Sie nach einem vorgegebenen Text,
- geben Sie aus, ob der Suchtext gefunden wurde.
|
|
28.2.2 Lernziele |
|
Diese Aufgabe geht nochmals auf Interfaces ein. Sie verstehen, dass mit diesen verschiedene Fähigkeiten unabhängig von der Klassenhierarchie beschrieben werden können. Außerdem erfahren sie, wie mehrere Interfaces gemeinsam genutzt werden, um Klassen flexibel zu erweitern und unterschiedliche Funktionalitäten - beispielsweise Suchen und Drucken - in einer Klasse bereitzustellen. |
|
28.2.3 Ergebnis Programmlauf |
|
|
Projekt: BPMN-Einführung
|
|
|
Suchtext gefunden.
|
|
|
|
28.2.4 Lösung |
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
interface Druckbar {
|
|
|
void drucken();
|
|
|
}
|
|
|
|
|
|
interface Suchbar {
|
|
|
boolean suchen(String text);
|
|
|
}
|
|
|
|
|
|
class Projekt implements Druckbar, Suchbar {
|
|
|
String bez;
|
|
|
|
|
|
Projekt(String bez) {
|
|
|
this.bez = bez;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void drucken() {
|
|
|
System.out.println("Projekt: " + bez);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public boolean suchen(String text) {
|
|
|
return bez.contains(text);
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe38 |
|
|
public class Aufgabe38 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Projekt p1 = new Projekt("BPMN-Einführung");
|
|
|
|
|
|
p1.drucken();
|
|
|
|
|
|
if (p1.suchen("BPMN")) {
|
|
|
System.out.println("Suchtext gefunden.");
|
|
|
} else {
|
|
|
System.out.println("Suchtext nicht gefunden.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
28.2.5 Betrachtete Themen |
|
- Annotation @Override
- Datentyp boolean
- Implementierung von Interfaces
- Interfaces
- Konstruktoren
- Mehrere Interfaces
- Mehrfachimplementierung
- Methode contains()
- Methoden mit Rückgabewert
- Objekterzeugung mit new
- Parameterübergabe
- Suche in Zeichenketten
- Verpflichtung zur Implementierung von Methoden
- Verzweigungen (if)
- Zeichenketten (Strings)
|
|
28.2.6 Erläuterung |
|
Eine Klasse kann in Java nur von einer einzigen Klasse erben. Sie kann aber mehrere Interfaces implementieren. Deshalb ist Folgendes möglich: |
|
|
class Projekt implements Druckbar, Suchbar
|
|
Die Klasse Projekt "verpflichtet sich" damit, alle Methoden aus beiden Interfaces bereitzustellen. Die Methode bez.contains(text) prüft, ob der Suchtext in der Projektbezeichnung enthalten ist. |
|
|
|
28.3 Aufgabe 39 - Polymorphie |
|
28.3.1 Aufgabenstellung |
|
In einem Unternehmen sollen verschiedene Arten von Angestellten verwaltet werden. Erstellen Sie eine abstrakte Klasse Angestellter mit den Attributen |
|
|
|
|
sowie der abstrakten Methode anzeigen(). |
|
Leiten Sie davon die Klassen Sachbearbeiter und Abteilungsleiter ab. Die Klasse Sachbearbeiter erhält zusätzlich das Attribut fachgebiet. Die Klasse Abteilungsleiter erhält zusätzlich das Attribut budget. |
|
Implementieren Sie in beiden Klassen die Methode anzeigen(). Die Ausgabe soll die Art des Angestellten sowie die zugehörigen Daten enthalten. |
|
Legen Sie im Hauptprogramm folgende Objekte an: |
|
Sachbearbeiter |
|
- Anna Müller
- Fachgebiet: Personal
|
|
Abteilungsleiter |
|
- Bernd Schmidt
- Budget: 500000,0
|
|
Speichern Sie beide Objekte in einem Array vom Typ Angestellter[]. Durchlaufen Sie das Array mit einer Schleife und geben Sie die Daten aller Angestellten aus. Verwenden Sie dabei die Methode anzeigen() ohne zu prüfen, um welche konkrete Subklasse es sich handelt. |
|
28.3.2 Lernziele |
|
Sie lernen das Konzept der Polymorphie kennen, verstehen, dass eine Referenz einer Oberklasse auf Objekte verschiedener Unterklassen zeigen kann und dass beim Methodenaufruf automatisch die zur tatsächlichen Objektklasse gehörende Implementierung ausgeführt wird. Dadurch erkennen sie einen der zentralen Vorteile der Vererbung und lernen, flexible und erweiterbare objektorientierte Programme zu entwickeln. |
|
28.3.3 Ergebnis Programmlauf |
|
|
Sachbearbeiter:
|
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
|
|
|
Abteilungsleiter:
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
|
28.3.4 Lösung |
|
Hier mal wieder: Alle Programme bzw. Klassen in einer Datei. |
|
|
package firma;
|
|
|
|
|
|
abstract class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
abstract void anzeigen();
|
|
|
}
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println("Sachbearbeiter:");
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Fachgebiet: " + fachgebiet);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println("Abteilungsleiter:");
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Budget: " + budget);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe39 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Abteilungsleiter a1 = new Abteilungsleiter();
|
|
|
a1.name = "Schmidt";
|
|
|
a1.vorname = "Bernd";
|
|
|
a1.budget = 500000.0;
|
|
|
|
|
|
Angestellter[] personal = {s1, a1};
|
|
|
|
|
|
for (Angestellter a : personal) {
|
|
|
a.anzeigen();
|
|
|
System.out.println();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
28.3.5 Betrachtete Themen |
|
- Abstrakte Klassen
- Abstrakte Methoden
- Vererbung
- Spezialisierung von Klassen
- Super- und Subklassen
- Polymorphie
- Dynamische Bindung
- Überschreiben von Methoden (Override)
- Annotation @Override
- Referenzen auf Superklassen
- Objekterzeugung mit new
- Objektarrays
- Array vom Typ einer Superklasse
- Speicherung unterschiedlicher Objekttypen in einem gemeinsamen Array
- ForEach-Schleife
- Methodenaufrufe über Superklassenreferenzen
- Gemeinsame Verarbeitung unterschiedlicher Objekttypen
|
|
28.3.6 Ziel der Aufgabe, vertieft |
|
Die Aufgabe zeigt das Zusammenspiel von |
|
- abstrakten Klassen,
- Vererbung,
- überschriebenen Methoden und
- Polymorphie.
|
|
Obwohl die Objekte über Referenzen des Typs Angestellter angesprochen werden, wird automatisch die jeweils passende Implementierung der Methode anzeigen() ausgeführt. Dieses Verhalten wird als Polymorphie bezeichnet. |
|
Etwas genauer |
|
Das Array besitzt den Typ: |
|
|
Angestellter[]
|
|
Trotzdem können darin Objekte der Klassen Sachbearbeiter und Abteilungsleiter gespeichert werden. Das funktioniert, weil beide Subklassen von Angestellter sind. Beim Methodenaufruf |
|
|
a.anzeigen();
|
|
entscheidet Java zur Laufzeit, welche konkrete Methode ausgeführt wird. |
|
- Bei einem Sachbearbeiter wird die Methode aus der Klasse Sachbearbeiter ausgeführt.
- Bei einem Abteilungsleiter wird die Methode aus der Klasse Abteilungsleiter ausgeführt.
|
|
Damit sind wir bei der Polymorphie. |
|
28.4 Aufgabe 40 - Laufzeittyp |
|
Laufzeittyp von Objekten mit instanceof |
|
28.4.1 Aufgabenstellung |
|
In den vorhergehenden Aufgaben wurden die Klassen Angestellter, Sachbearbeiter und Abteilungsleiter verwendet. Die Objekte wurden dabei über Referenzen des Typs Angestellter verwaltet. |
|
Erstellen Sie erneut die Klassen |
|
- Angestellter (abstrakte Superklasse)
- Sachbearbeiter
- Abteilungsleiter
|
|
mit den bereits bekannten Attributen. |
|
Legen Sie im Hauptprogramm mindestens einen Sachbearbeiter und einen Abteilungsleiter an und speichern Sie die Objekte in einem Array vom Typ |
|
|
Angestellter[]
|
|
Durchlaufen Sie das Array mit einer Schleife und geben Sie die Daten aller Angestellten aus. Prüfen Sie anschließend für jedes Objekt zur Laufzeit, ob es sich um einen |
|
- Sachbearbeiter oder
- Abteilungsleiter
|
|
handelt. |
|
Verwenden Sie dazu den Operator |
|
|
instanceof
|
|
Geben Sie zusätzlich aus, zu welcher konkreten Klasse das jeweilige Objekt gehört. |
|
28.4.2 Lernziele |
|
Hier wird gelernt, wie mit dem Operator instanceof der tatsächliche Typ eines Objekts zur Laufzeit überprüft werden kann. Sie verstehen, warum solche Typprüfungen insbesondere bei Vererbung und Polymorphie notwendig sein können, und lernen, objektspezifische Methoden oder Attribute sicher zu verwenden. Dadurch vertiefen sie ihr Verständnis des Zusammenspiels von Referenztyp und tatsächlichem Objekttyp in Java. |
|
28.4.3 Ergebnis Programmlauf |
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
Objekttyp: Sachbearbeiter
|
|
|
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
Objekttyp: Abteilungsleiter
|
|
28.4.4 Lösung |
|
Hier mal wieder: Alle Programme in einer Datei. Ist aber nicht empfohlen |
|
|
package firma;
|
|
|
|
|
|
abstract class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
abstract void anzeigen();
|
|
|
}
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Fachgebiet: " + fachgebiet);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Budget: " + budget);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe40 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Abteilungsleiter a1 = new Abteilungsleiter();
|
|
|
a1.name = "Schmidt";
|
|
|
a1.vorname = "Bernd";
|
|
|
a1.budget = 500000.0;
|
|
|
|
|
|
Angestellter[] personal = {s1, a1};
|
|
|
|
|
|
for (Angestellter a : personal) {
|
|
|
a.anzeigen();
|
|
|
|
|
|
if (a instanceof Sachbearbeiter) {
|
|
|
System.out.println("Objekttyp: Sachbearbeiter");
|
|
|
}
|
|
|
|
|
|
if (a instanceof Abteilungsleiter) {
|
|
|
System.out.println("Objekttyp: Abteilungsleiter");
|
|
|
}
|
|
|
|
|
|
System.out.println();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
28.4.5 Betrachtete Themen |
|
- Abstrakte Klassen
- Abstrakte Methoden
- Vererbung
- Spezialisierung von Klassen
- Polymorphie
- Referenzen auf Superklassen
- Überschreiben von Methoden (Override)
- Annotation @Override
- Objekterzeugung mit new
- Objektarrays
- Array vom Typ einer Superklasse
- Speicherung unterschiedlicher Objekttypen in einem gemeinsamen Array
- ForEach-Schleife
- Dynamische Bindung von Methodenaufrufen
- Laufzeittyp eines Objekts
- Operator instanceof
- Typprüfung zur Laufzeit
- Ausgabe typabhängiger Informationen
- Zusammenspiel von Polymorphie und Vererbung
|
|
28.4.6 Erläuterung |
|
Der Operator instanceof prüft, ob ein Objekt zu einer bestimmten Klasse gehört. Beispiel: |
|
|
a instanceof Sachbearbeiter
|
|
Diese Prüfung ergibt true, wenn das Objekt tatsächlich ein Sachbearbeiter ist. Das ist nützlich, wenn man in einem Array oder einer Liste Objekte unterschiedlicher Subklassen gespeichert hat. |
|
Theorieaspekte |
|
Diese Aufgabe demonstriert wiederum das Konzept der Referenzen und zeigt: |
|
Eine Referenz vom Typ der Superklasse kann auf Objekte verschiedener Subklassen zeigen. |
|
Dadurch können unterschiedliche Objekte gemeinsam verwaltet werden, beispielsweise in einem Array vom Typ Angestellter[]. Während die Methode anzeigen() durch Polymorphie automatisch die passende Implementierung der jeweiligen Subklasse ausführt, ermöglicht der Operator instanceof die explizite Feststellung des tatsächlichen Objekttyps zur Laufzeit. Dies bildet die Grundlage für die moderne Variante mit Pattern Matching für instanceof. |
|
Ziel der Aufgabe |
|
Die Aufgabe zeigt u.a., dass unterschiedliche Objekte über Referenzen einer gemeinsamen Superklasse angesprochen werden können. Der tatsächliche Typ eines Objekts ist zwar bei der Erzeugung festgelegt, kann jedoch bei der Verarbeitung über eine Referenz der Superklasse erst zur Laufzeit bestimmt werden. |
|
Mit Hilfe des Operators instanceof kann dieser Laufzeittyp ermittelt werden. Dadurch lassen sich typabhängige Verarbeitungen durchführen. |
|
Vgl. zu den Konzepten Referenz und Typ auch Kapitel 2. |
|
|
|
28.5 Aufgabe 40a - Angestellte |
|
Verwaltung von Informationen zu Angestellten |
|
28.5.1 Aufgabenstellung |
|
Hier wird Aufgabe 40 etwas ausgebaut. |
|
In einem Unternehmen sollen verschiedene Gruppen von Angestellten verwaltet werden. Erstellen Sie eine abstrakte Klasse Angestellter mit den Attributen |
|
|
|
|
sowie der abstrakten Methode |
|
|
anzeigen()
|
|
Leiten Sie davon die Klassen Sachbearbeiter und Abteilungsleiter ab. Die Klasse Sachbearbeiter erhält zusätzlich das Attribut |
|
|
fachgebiet
|
|
Die Klasse Abteilungsleiter erhält zusätzlich das Attribut |
|
|
budget
|
|
Implementieren Sie in beiden Klassen die Methode anzeigen(), sodass die jeweiligen Daten ausgegeben werden. |
|
Legen Sie im Hauptprogramm zunächst folgende Objekte an: |
|
|
|
| Gruppe |
Vorname |
Name |
Zusatzinformation |
| Sachbearbeiter |
Anna |
Müller |
Personal |
| Abteilungsleiter |
Bernd |
Schmidt |
Budget: 500000,0 |
| |
|
|
Speichern Sie die Objekte in einer gemeinsamen Liste vom Typ |
|
|
ArrayList<Angestellter>
|
|
Fragen Sie anschließend mit einem Dialogfenster, ob ein weiterer Angestellter eingegeben werden soll. |
|
Wird die Frage mit Ja beantwortet, soll eine grafische Eingabemaske erscheinen. Die Eingabefelder sollen bereits mit Beispieldaten vorbelegt sein. Diese können unverändert übernommen oder geändert werden. Der Benutzer soll auswählen können, ob ein |
|
- Sachbearbeiter oder
- Abteilungsleiter
|
|
angelegt werden soll. |
|
Das neu erzeugte Objekt ist anschließend in die Liste aufzunehmen. Geben Sie danach alle vorhandenen Angestellten aus. Verwenden Sie zusätzlich die moderne Form von instanceof (Pattern Matching), um den konkreten Typ eines Objekts zu ermitteln und die gruppenabhängigen Attribute auszugeben. |
|
28.5.2 Lernziele |
|
Hier wird gelernt, wie ein Java-Programm um eine einfache grafische Benutzeroberfläche (GUI) erweitert wird. Sie erfahren, wie Eingabefelder, Auswahllisten und Schaltflächen mit Swing erstellt und zur Erfassung von Objektdaten genutzt werden. Außerdem erkennen sie, wie Benutzereingaben verarbeitet und anschließend zur Erzeugung und Ausgabe von Objekten verwendet werden. Dadurch wird der Übergang von reinen Konsolenprogrammen zu ereignisgesteuerten Anwendungen vorbereitet. |
|
28.5.3 Ergebnis Programmlauf |
|
Ohne einem zusätzlichen Angestellten ("Nein") |
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
Objekttyp: Sachbearbeiter
|
|
|
Fachgebiet direkt zugreifbar: Personal
|
|
|
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
Objekttyp: Abteilungsleiter
|
|
|
Budget direkt zugreifbar: 500000.0
|
|
Mit einem zusätzlichen Angestellten ("Ja") |
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
Objekttyp: Sachbearbeiter
|
|
|
Fachgebiet direkt zugreifbar: Personal
|
|
|
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
Objekttyp: Abteilungsleiter
|
|
|
Budget direkt zugreifbar: 500000.0
|
|
|
|
|
|
Clara Weber
|
|
|
Fachgebiet: Einkauf
|
|
|
Objekttyp: Sachbearbeiter
|
|
|
Fachgebiet direkt zugreifbar: Einkauf
|
|
Hinweise |
|
- Verwenden Sie eine
ArrayList<Angestellter> zur Verwaltung der Objekte.
- Nutzen Sie
JOptionPane, JPanel, JTextField, JComboBox und GridLayout für die Eingabemaske.
|
|
Verwenden Sie außerdem die moderne Schreibweise |
|
|
if (a instanceof Sachbearbeiter s)
|
|
anstelle eines expliziten Casts. |
|
28.5.4 Exkurs - Explizit vs, implizit |
|
Ein Cast ist in Java eine Typumwandlung. Man unterscheidet zwischen impliziten und expliziten Casts. Die ältere Schreibweise (mit explizitem Cast) ist wie folgt: |
|
|
if (a instanceof Sachbearbeiter) {
|
|
|
Sachbearbeiter s = (Sachbearbeiter) a;
|
|
|
s.bearbeiteVorgang();
|
|
|
}
|
|
Hier bedeutet (Sachbearbeiter) a den expliziten Cast. Dem Compiler wird mitgeteilt: Behandle die Referenz a jetzt als Sachbearbeiter. Ohne diesen Cast würde der Compiler einen Fehler melden. |
|
Seit Java 16 kann man den Cast direkt mit instanceof verbinden: |
|
|
if (a instanceof Sachbearbeiter s) {
|
|
|
s.bearbeiteVorgang();
|
|
|
}
|
|
Hier geschieht zweierlei gleichzeitig: |
|
- Es wird geprüft, ob a tatsächlich ein Sachbearbeiter ist.
- Ist dies der Fall, wird automatisch die Variable
Sachbearbeiter s angelegt.
|
|
Zusammenfassung |
|
- Expliziter Cast: Der Programmierer schreibt die Typumwandlung selbst, z. B. (Sachbearbeiter) a.
- Moderne Schreibweise: instanceof prüft den Typ und führt die Typumwandlung automatisch durch, sodass kein expliziter Cast mehr erforderlich ist.
|
|
28.5.5 Lösung |
|
Klasse Angestellter |
|
|
package firma;
|
|
|
|
|
|
abstract class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
abstract void anzeigen();
|
|
|
}
|
|
Klasse Sachbearbeiter |
|
|
package firma;
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Fachgebiet: " + fachgebiet);
|
|
|
}
|
|
|
}
|
|
Klasse Abteilungsleiter |
|
|
package firma;
|
|
|
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Budget: " + budget);
|
|
|
}
|
|
|
}
|
|
Klasse Aufgabe40a |
|
|
import java.util.ArrayList;
|
|
|
import javax.swing.*;
|
|
|
import java.awt.GridLayout;
|
|
|
|
|
|
public class Aufgabe40a {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
Sachbearbeiter s1 = new Sachbearbeiter();
|
|
|
s1.name = "Müller";
|
|
|
s1.vorname = "Anna";
|
|
|
s1.fachgebiet = "Personal";
|
|
|
|
|
|
Abteilungsleiter a1 = new Abteilungsleiter();
|
|
|
a1.name = "Schmidt";
|
|
|
a1.vorname = "Bernd";
|
|
|
a1.budget = 500000.0;
|
|
|
|
|
|
ArrayList<Angestellter> personal = new ArrayList<>();
|
|
|
personal.add(s1);
|
|
|
personal.add(a1);
|
|
|
|
|
Fragefenster: Soll überhaupt ein neuer Angestellter eingegeben werden? |
|
|
int antwort = JOptionPane.showConfirmDialog(null,
|
|
|
"Soll ein neuer Angestellter eingegeben werden?","Eingabe",
|
|
|
JOptionPane.YES_NO_OPTION
|
|
|
);
|
|
|
|
|
Nur wenn der Benutzer "Ja" auswählt, wird die Eingabemaske angezeigt. |
|
|
if (antwort == JOptionPane.YES_OPTION) {
|
|
|
JComboBox<String> typAuswahl =
|
|
|
new JComboBox<>(new String[]{"Sachbearbeiter", "Abteilungsleiter"});
|
|
|
|
|
Textfelder mit vorgegebenen Beispielwerten. Diese Werte erscheinen bereits in der Eingabemaske. Der Benutzer kann sie übernehmen oder ändern. |
|
|
JTextField nameFeld = new JTextField("Weber");
|
|
|
JTextField vornameFeld = new JTextField("Clara");
|
|
|
JTextField fachgebietFeld = new JTextField("Einkauf");
|
|
|
JTextField budgetFeld = new JTextField("250000.0");
|
|
|
|
|
JPanel ist ein Behälter für die Elemente der Eingabemaske. GridLayout(0, 2) bedeutet: - beliebig viele Zeilen, aber immer zwei Spalten. Links steht jeweils die Beschriftung, rechts das Eingabefeld. |
|
|
JPanel panel = new JPanel(new GridLayout(0, 2));
|
|
|
|
|
Die einzelnen Bestandteile werden der Maske hinzugefügt. |
|
|
panel.add(new JLabel("Typ:"));
|
|
|
panel.add(typAuswahl);
|
|
|
|
|
|
panel.add(new JLabel("Name:"));
|
|
|
panel.add(nameFeld);
|
|
|
|
|
|
panel.add(new JLabel("Vorname:"));
|
|
|
panel.add(vornameFeld);
|
|
|
|
|
|
panel.add(new JLabel("Fachgebiet:"));
|
|
|
panel.add(fachgebietFeld);
|
|
|
|
|
|
panel.add(new JLabel("Budget:"));
|
|
|
panel.add(budgetFeld);
|
|
|
|
|
Die fertige Eingabemaske wird angezeigt. Der Benutzer kann OK oder Abbrechen wählen. |
|
|
int eingabe = JOptionPane.showConfirmDialog(
|
|
|
null, panel,"Neuer Angestellter",
|
|
|
JOptionPane.OK_CANCEL_OPTION
|
|
|
);
|
|
|
|
|
Nur wenn OK gedrückt wurde, werden die eingegebenen Werte verarbeitet. |
|
|
if (eingabe == JOptionPane.OK_OPTION) {
|
|
|
|
|
Auslesen der ausgewählten Klasse aus der Auswahlliste. |
|
|
String typ = (String) typAuswahl.getSelectedItem();
|
|
|
|
|
Fall 1: Es soll ein Sachbearbeiter erzeugt werden. |
|
|
if (typ.equals("Sachbearbeiter")) {
|
|
|
Sachbearbeiter s2 = new Sachbearbeiter();
|
|
|
|
|
Die Inhalte der Textfelder werden in das neue Objekt übernommen. |
|
|
s2.name = nameFeld.getText();
|
|
|
s2.vorname = vornameFeld.getText();
|
|
|
s2.fachgebiet = fachgebietFeld.getText();
|
|
|
|
|
Das neue Objekt wird zur Liste hinzugefügt. |
|
|
personal.add(s2);
|
|
|
}
|
|
|
|
|
Fall 2: Es soll ein Abteilungsleiter erzeugt werden. |
|
|
if (typ.equals("Abteilungsleiter")) {
|
|
|
Abteilungsleiter a2 = new Abteilungsleiter();
|
|
|
a2.name = nameFeld.getText();
|
|
|
a2.vorname = vornameFeld.getText();
|
|
|
|
|
Der Inhalt eines Textfeldes ist zunächst immer ein String. Für das Budget wird aber ein double-Wert benötigt. Deshalb muss der Text in eine Zahl umgewandelt werden. |
|
|
a2.budget = Double.parseDouble(budgetFeld.getText());
|
|
|
|
|
Auch dieses neue Objekt wird zur Liste hinzugefügt. |
|
|
personal.add(a2);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
for (Angestellter a : personal) {
|
|
|
a.anzeigen();
|
|
|
if (a instanceof Sachbearbeiter s) {
|
|
|
System.out.println("Objekttyp: Sachbearbeiter");
|
|
|
System.out.println("Fachgebiet direkt zugreifbar: "
|
|
|
+ s.fachgebiet);
|
|
|
}
|
|
|
if (a instanceof Abteilungsleiter al) {
|
|
|
System.out.println("Objekttyp: Abteilungsleiter");
|
|
|
System.out.println("Budget direkt zugreifbar: " + al.budget);
|
|
|
}
|
|
|
System.out.println();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
28.5.6 Erläuterungen |
|
- JOptionPane.showConfirmDialog erzeugt ein Dialogfenster.
- JPanel sammelt mehrere Eingabeelemente zu einer Maske.
- JTextField enthält Texteingaben.
- JComboBox bietet eine Auswahl an.
- GridLayout(0, 2) ordnet die Maske zweispaltig an.
- getText() liest den Inhalt eines Textfeldes aus.
- Double.parseDouble() wandelt einen Text in eine Zahl um.
|
|
28.5.7 Betrachtete Themen |
|
- Abstrakte Klassen
- Abstrakte Methoden
- Vererbung
- Spezialisierung von Klassen
- Polymorphie
- Überschreiben von Methoden (Override)
- Annotation @Override
- Referenzen auf Superklassen
- Objekterzeugung mit new
- ArrayList
- Generics (ArrayList<Angestellter>)
- Hinzufügen von Objekten zu Listen
- ForEach-Schleife
- Pattern Matching mit instanceof
- Grafische Benutzerschnittstellen (GUI)
- Swing-Komponenten
- Dialogfenster mit JOptionPane
- Eingabemasken mit JPanel
- Layout-Manager (GridLayout)
- Textfelder (JTextField)
- Auswahllisten (JComboBox)
- Beschriftungen (JLabel)
- Benutzereingaben verarbeiten
- Verzweigungen (if)
- Zeichenkettenvergleich mit equals
- Umwandlung von Zeichenketten in Zahlen (Double.parseDouble)
- Dynamisches Erzeugen von Objekten
- Dynamische Erweiterung einer Objektliste
- Modul java.desktop
|
|
|
|
29 Übungsaufgaben Teil 10 |
|
|
|
29.1 Aufgabe 41 - Records |
|
Daten effizient verwalten |
|
29.1.1 Aufgabenstellung |
|
Erstellen Sie für die Verwaltung von PCs einen Record PC. Ein PC soll folgende Daten besitzen: |
|
|
|
|
Legen Sie mehrere PCs an und geben Sie deren Daten aus. Verwenden Sie dabei die automatisch erzeugten Zugriffsmethoden des Records. |
|
29.1.2 Lernziele |
|
Gegenstand dieser Aufgabe ist das Konzept der Record-Klassen in Java. Sie verstehen, wie sich einfache Datenklassen mit Records besonders kompakt definieren lassen und welche Methoden - beispielsweise Konstruktor, Zugriffsmethoden (Accessor), toString(), equals() und hashCode() - automatisch erzeugt werden. Dadurch erkennen sie, wann Records gegenüber herkömmlichen Klassen eine übersichtliche und effiziente Alternative darstellen. |
|
|
|
29.1.3 Lösung |
|
|
package firma;
|
|
|
|
|
|
record PC(
|
|
|
int invNr,
|
|
|
String bez,
|
|
|
String typ
|
|
|
) {
|
|
|
}
|
|
Obige geschweifte Klammern sind notwendig: Body-Teil der Deklaration. Bei Bedarf kommen hier zusätzliche Methoden rein |
|
|
|
|
|
public class Aufgabe41 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
PC pc1 = new PC(1001, "Dell Optiplex", "Desktop");
|
|
|
PC pc2 = new PC(1002, "Lenovo ThinkPad", "Notebook");
|
|
|
PC pc3 = new PC(1003, "HP EliteDesk", "Desktop");
|
|
|
|
|
|
System.out.println("Inventarnummer: " + pc1.invNr());
|
|
|
System.out.println("Bezeichnung: " + pc1.bez());
|
|
|
System.out.println("Typ: " + pc1.typ());
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
System.out.println(pc2);
|
|
|
System.out.println(pc3);
|
|
|
}
|
|
|
}
|
|
Ergebnis Programmlauf |
|
|
Inventarnummer: 1001
|
|
|
Bezeichnung: Dell Optiplex
|
|
|
Typ: Desktop
|
|
|
|
|
|
PC[invNr=1002, bez=Lenovo ThinkPad, typ=Notebook]
|
|
|
PC[invNr=1003, bez=HP EliteDesk, typ=Desktop]
|
|
29.1.4 Betrachtete Themen |
|
- Ausgabe von Record-Daten
- automatisch erzeugte Methode toString()
- automatisch erzeugte Methoden equals() und hashCode()
- automatisch erzeugte Zugriffsmethoden (Accessor-Methoden)
- automatisch erzeugter Konstruktor
- Erzeugen von Record-Objekten
- kompakte Schreibweise für Datenklassen
- Komponenten eines Records
- Record-Klassen (Records)
- unveränderliche Datenobjekte (Immutable Objects)
- Verwendung der automatisch erzeugten Methoden
- Zugriff ohne Getter-Methoden
|
|
29.1.5 Erläuterung |
|
Ein Record ist eine besonders kurze Schreibweise für Klassen, die vor allem Daten speichern. |
|
Aus |
|
|
record PC(int invNr, String bez, String typ)
|
|
erzeugt Java automatisch: |
|
- einen Konstruktor
- Zugriffsmethoden
- die Methode toString()
- die Methode equals()
- die Methode hashCode()
|
|
Die Zugriffsmethoden heißen nicht getBez(), sondern einfach: |
|
|
|
|
Records sind standardmäßig unveränderlich. Nach der Erzeugung kann man die Werte also nicht mehr direkt ändern. |
|
|
|
29.2 Aufgabe 42 - Projektmitarbeit |
|
Angestellte und ihre Projekte |
|
29.2.1 Aufgabenstellung |
|
Erstellen Sie ein zusammenhängendes Programm zur Verwaltung von Angestellten und Projekten. Das Programm soll mehrere fortgeschrittene OOP-Konzepte miteinander verbinden. |
|
Abstrakte Klasse |
|
Erstellen Sie eine abstrakte Klasse Angestellter. Diese Klasse soll enthalten: |
|
|
String name;
|
|
|
String vorname;
|
|
|
abstract double berechneBonus();
|
|
|
abstract void anzeigen();
|
|
Subklassen |
|
Leiten Sie aus Angestellter zwei Subklassen ab: |
|
- Sachbearbeiter
- Abteilungsleiter
|
|
Ein Sachbearbeiter besitzt zusätzlich: |
|
|
String fachgebiet;
|
|
Ein Abteilungsleiter besitzt zusätzlich: |
|
|
double budget;
|
|
Interfaces |
|
Erstellen Sie zwei Interfaces: |
|
|
interface Druckbar
|
|
mit der Methode: |
|
|
void drucken();
|
|
und |
|
|
interface Suchbar
|
|
mit der Methode: |
|
|
boolean suchen(String text);
|
|
Die Klasse Projekt soll beide Interfaces implementieren. |
|
Polymorphie |
|
Speichern Sie mehrere Angestellte in einer Liste: |
|
|
List<Angestellter>
|
|
Durchlaufen Sie diese Liste und rufen Sie polymorph die Methoden anzeigen() und berechneBonus() auf. |
|
Records |
|
Erstellen Sie zusätzlich einen Record mit der Bezeichnung PC. Ein PC besitzt folgende Attribute: |
|
|
int invNr;
|
|
|
String bez;
|
|
|
String typ;
|
|
Legen Sie mindestens einen PC an und geben Sie ihn aus. |
|
Ausgaben |
|
Das Programm soll ausgeben: |
|
- alle Mitarbeiter
- deren Bonus
- alle Projekte
- Suchergebnisse für Projekte
- mindestens einen PC
|
|
29.2.2 Lernziele |
|
In dieser Aufgabe wenden Sie mehrere grundlegende Konzepte der objektorientierten Programmierung gemeinsam an. Sie lernen, wie sich eine Klassenhierarchie mit Vererbung und abstrakten Klassen aufbauen lässt, wie Interfaces einheitliche Funktionalitäten bereitstellen und wie Polymorphie den einheitlichen Umgang mit unterschiedlichen Objektarten ermöglicht. Darüber hinaus vertiefen Sie den Einsatz von Collections zur Verwaltung mehrerer Objekte. |
|
|
|
29.2.3 Lösung |
|
Klasse Angestellter mit Interfaces |
|
|
package firma;
|
|
|
|
|
|
interface Druckbar {
|
|
|
void drucken();
|
|
|
}
|
|
|
|
|
|
interface Suchbar {
|
|
|
boolean suchen(String text);
|
|
|
}
|
|
|
|
|
|
abstract class Angestellter implements Druckbar {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
Angestellter(String name, String vorname) {
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
}
|
|
|
|
|
|
abstract void anzeigen();
|
|
|
|
|
|
abstract double berechneBonus();
|
|
|
|
|
|
@Override
|
|
|
public void drucken() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
}
|
|
|
}
|
|
Klasse Sachbearbeiter |
|
|
package firma;
|
|
|
|
|
|
class Sachbearbeiter extends Angestellter {
|
|
|
String fachgebiet;
|
|
|
|
|
|
Sachbearbeiter(String name, String vorname, String fachgebiet) {
|
|
|
super(name, vorname);
|
|
|
this.fachgebiet = fachgebiet;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println("Sachbearbeiter:");
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Fachgebiet: " + fachgebiet);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
double berechneBonus() {
|
|
|
return 500.0;
|
|
|
}
|
|
|
}
|
|
Klasse Abteilungsleiter |
|
|
package firma;
|
|
|
|
|
|
class Abteilungsleiter extends Angestellter {
|
|
|
double budget;
|
|
|
|
|
|
Abteilungsleiter(String name, String vorname, double budget) {
|
|
|
super(name, vorname);
|
|
|
this.budget = budget;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
void anzeigen() {
|
|
|
System.out.println("Abteilungsleiter:");
|
|
|
System.out.println(vorname + " " + name);
|
|
|
System.out.println("Budget: " + budget);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
double berechneBonus() {
|
|
|
return 5000.0;
|
|
|
}
|
|
|
}
|
|
Klasse Projekt |
|
|
package firma;
|
|
|
|
|
|
class Projekt implements Druckbar, Suchbar {
|
|
|
String projektNr;
|
|
|
String bezeichnung;
|
|
|
|
|
|
Projekt(String projektNr, String bezeichnung) {
|
|
|
this.projektNr = projektNr;
|
|
|
this.bezeichnung = bezeichnung;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void drucken() {
|
|
|
System.out.println(projektNr + ": " + bezeichnung);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public boolean suchen(String text) {
|
|
|
return bezeichnung.contains(text);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
record PC(
|
|
|
int invNr,
|
|
|
String bez,
|
|
|
String typ
|
|
|
) {
|
|
|
}
|
|
Klasse Aufgabe42 |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
public class Aufgabe42 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
List<Angestellter> personal = new ArrayList<>();
|
|
|
|
|
|
personal.add(new Sachbearbeiter("Müller", "Anna", "Personal"));
|
|
|
personal.add(new Abteilungsleiter("Schmidt", "Bernd", 500000.0));
|
|
|
personal.add(new Sachbearbeiter("Weber", "Clara", "Einkauf"));
|
|
|
|
|
|
System.out.println("Alle Mitarbeiter");
|
|
|
System.out.println("================");
|
|
|
|
|
|
for (Angestellter a : personal) {
|
|
|
a.anzeigen();
|
|
|
System.out.println("Bonus: " + a.berechneBonus());
|
|
|
|
|
|
if (a instanceof Sachbearbeiter) {
|
|
|
System.out.println("Typprüfung: Sachbearbeiter");
|
|
|
}
|
|
|
|
|
|
if (a instanceof Abteilungsleiter) {
|
|
|
System.out.println("Typprüfung: Abteilungsleiter");
|
|
|
}
|
|
|
|
|
|
System.out.println();
|
|
|
}
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
|
|
|
projekte.add(new Projekt("P100", "BPMN-Einführung"));
|
|
|
projekte.add(new Projekt("P200", "Prozessoptimierung"));
|
|
|
projekte.add(new Projekt("P300", "Java-Schulung"));
|
|
|
|
|
|
System.out.println("Alle Projekte");
|
|
|
System.out.println("=============");
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
p.drucken();
|
|
|
}
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
System.out.println("Suchergebnis für 'Java'");
|
|
|
System.out.println("=======================");
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
if (p.suchen("Java")) {
|
|
|
p.drucken();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
|
PC pc1 = new PC(1001, "Dell Optiplex", "Desktop");
|
|
|
|
|
|
System.out.println("PC-Daten");
|
|
|
System.out.println("========");
|
|
|
System.out.println("Inventarnummer: " + pc1.invNr());
|
|
|
System.out.println("Bezeichnung: " + pc1.bez());
|
|
|
System.out.println("Typ: " + pc1.typ());
|
|
|
}
|
|
|
}
|
|
29.2.4 Ergebnis Programmlauf |
|
|
Alle Mitarbeiter
|
|
|
================
|
|
|
Sachbearbeiter:
|
|
|
Anna Müller
|
|
|
Fachgebiet: Personal
|
|
|
Bonus: 500.0
|
|
|
Typprüfung: Sachbearbeiter
|
|
|
|
|
|
Abteilungsleiter:
|
|
|
Bernd Schmidt
|
|
|
Budget: 500000.0
|
|
|
Bonus: 5000.0
|
|
|
Typprüfung: Abteilungsleiter
|
|
|
|
|
|
Sachbearbeiter:
|
|
|
Clara Weber
|
|
|
Fachgebiet: Einkauf
|
|
|
Bonus: 500.0
|
|
|
Typprüfung: Sachbearbeiter
|
|
|
|
|
|
Alle Projekte
|
|
|
=============
|
|
|
P100: BPMN-Einführung
|
|
|
P200: Prozessoptimierung
|
|
|
P300: Java-Schulung
|
|
|
|
|
|
Suchergebnis für 'Java'
|
|
|
=======================
|
|
|
P300: Java-Schulung
|
|
|
|
|
|
PC-Daten
|
|
|
========
|
|
|
Inventarnummer: 1001
|
|
|
Bezeichnung: Dell Optiplex
|
|
|
Typ: Desktop
|
|
29.2.5 Betrachtete Themen |
|
- Abstrakte Klassen
- Abstrakte Methoden
- ArrayList
- Aufruf von super(...)
- Ausgabe von Objektdaten
- Automatisch erzeugte Zugriffsmethoden (Accessor-Methoden)
- Collections mit List
- Dynamische Methodenbindung
- foreach-Schleife
- Implementierung mehrerer Interfaces
- instanceof
- Interfaces
- Konstruktoren
- Methoden mit Rückgabewert
- Superklasse und Subklassen
- Objekterzeugung mit new
- Polymorphe Objektlisten
- Polymorphie
- Records
- Suche mit contains()
- this-Referenz
- Typprüfung zur Laufzeit
- Überschreiben von Methoden (Override)
- Vererbung
- Zusammenarbeit mehrerer Klassen
- Zusammenarbeit verschiedener OOP-Konzepte
|
|
29.2.6 Erläuterung |
|
Dieses Projekt verbindet mehrere wichtige OOP-Konzepte. Die Klasse Angestellter ist abstrakt. Sie beschreibt gemeinsame Merkmale aller Angestellten, kann aber selbst nicht direkt als Objekt erzeugt werden. Die Klassen Sachbearbeiter und Abteilungsleiter erben von Angestellter. Beide Klassen müssen die abstrakten Methoden |
|
- anzeigen()
- berechneBonus()
|
|
konkret implementieren. Durch die Liste |
|
|
List<Angestellter> personal
|
|
können verschiedene Subklassenobjekte gemeinsam verwaltet werden. Beim Aufruf |
|
|
a.anzeigen();
|
|
entscheidet Java zur Laufzeit, ob die Methode aus Sachbearbeiter oder aus Abteilungsleiter ausgeführt wird. Das ist Polymorphie. |
|
Die Klasse Projekt implementiert zwei Interfaces: |
|
|
|
|
Damit besitzt ein Projekt sowohl eine Druckfunktion als auch eine Suchfunktion. Der Record PC zeigt abschließend, wie einfache Datenobjekte in Java kompakt formuliert werden können. |
|
|
|
29.3 Aufgabe 43 - Exception Handling |
|
Vorgedachte Fehlermeldungen |
|
29.3.1 Aufgabenstellung |
|
Ausgangspunkt sind Studierende einer Hochschule. |
|
Erstellen Sie ein Java-Programm Aufgabe43, das eine Matrikelnummer und die aktuelle Semesterzahl von der Tastatur einliest. |
|
Da Benutzereingaben fehlerhaft sein können, soll das Programm die Eingaben gegen ungültige Werte absichern. Verwenden Sie dazu einen try-catch-Block. |
|
Das Programm soll folgende Schritte ausführen: |
|
- Matrikelnummer eingeben
- Semesterzahl eingeben
- Beide Werte als ganze Zahlen (int) speichern
- Die eingelesenen Werte auf dem Bildschirm ausgeben
|
|
Falls anstelle einer Zahl ein anderer Text eingegeben wird, soll das Programm nicht abbrechen, sondern eine verständliche Fehlermeldung ausgeben, z. B.: |
|
|
Fehler: Bitte nur ganze Zahlen eingeben.
|
|
Schließen Sie den verwendeten Scanner am Ende des Programms wieder. |
|
29.3.2 Lernziele |
|
Mit dieser Aufgabe lernen Sie, wie Programme auf fehlerhafte Benutzereingaben reagieren können. Sie lernen den Einsatz von Exception Handling mit try und catch kennen und erfahren, wie die Ausnahme NumberFormatException abgefangen wird, damit das Programm kontrolliert weiterarbeiten bzw. sauber beendet werden kann. |
|
29.3.3 Ergebnis Programmlauf |
|
|
Matrikelnummer: 1009
|
|
|
Semester: 12
|
|
|
Matrikelnummer: 1009
|
|
|
Semester: 12
|
|
bzw. bei fehlerhafter Eingabe: |
|
|
Matrikelnummer: 2002
|
|
|
Semester: abc
|
|
|
Fehler: Bitte nur ganze Zahlen eingeben.
|
|
|
|
29.3.4 Lösung |
|
|
package hochschule;
|
|
|
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
public class Aufgabe43 {
|
|
|
public static void main(String[] args) {
|
|
|
Scanner scanner = new Scanner(System.in);
|
|
|
try {
|
|
|
System.out.print("Matrikelnummer: ");
|
|
|
int matrNr = Integer.parseInt(scanner.nextLine());
|
|
|
System.out.print("Semester: ");
|
|
|
int semester = Integer.parseInt(scanner.nextLine());
|
|
|
System.out.println("Matrikelnummer: " + matrNr);
|
|
|
System.out.println("Semester: " + semester);
|
|
|
} catch (NumberFormatException e) {
|
|
|
System.out.println("Fehler: Bitte nur ganze Zahlen eingeben.");
|
|
|
}
|
|
|
scanner.close();
|
|
|
}
|
|
|
}
|
|
29.3.5 Betrachtete Themen |
|
- Ausgabe einer Fehlermeldung
- Ausnahmebehandlung (Exception Handling)
- Einlesen von Benutzereingaben mit Scanner
- Erkennen fehlerhafter Eingaben
- Klasse NumberFormatException
- Ressourcen mit scanner.close() schließen
- try-catch-Block
- Umwandlung von Zeichenketten in Ganzzahlen (Integer.parseInt())
|
|
29.3.6 Erläuterung |
|
Nicht jede Benutzereingabe ist korrekt. Wird beispielsweise statt einer Zahl der Text abc eingegeben, kann Java diesen Text nicht in eine ganze Zahl umwandeln. Ohne besondere Maßnahmen würde das Programm an dieser Stelle mit einer Fehlermeldung abbrechen. |
|
Deshalb wird der fehleranfällige Programmteil in einen try-Block geschrieben. Tritt dort ein Fehler auf, springt Java automatisch in den catch-Block. Dort kann eine verständliche Meldung ausgegeben werden, ohne dass das Programm unkontrolliert beendet wird. |
|
|
try {
|
|
|
...
|
|
|
}
|
|
|
catch (NumberFormatException e) {
|
|
|
...
|
|
|
}
|
|
Die Methode |
|
|
Integer.parseInt(...)
|
|
wandelt einen Text in eine ganze Zahl (int) um. Ist der Text keine gültige Zahl, erzeugt Java eine NumberFormatException. |
|
Mit scanner.close(); wird der Scanner am Ende des Programms wieder geschlossen. Dadurch werden die verwendeten Systemressourcen ordnungsgemäß freigegeben. |
|
29.4 Aufgabe 44 - Eigene Exception |
|
Eigene Fehlermeldungen |
|
29.4.1 Aufgabenstellung |
|
Erstellen Sie eine eigene Exception-Klasse SemesterException. Entwickeln Sie anschließend eine Klasse Stud mit den Attributen |
|
- Matrikelnummer
- Name
- Semester
|
|
Das Semester wird beim Erzeugen eines Studierenden überprüft. |
|
- Ist das Semester kleiner oder gleich 15, soll das Objekt normal erzeugt werden.
- Ist das Semester größer als 15, soll eine SemesterException ausgelöst werden.
|
|
Fangen Sie diese Exception im Hauptprogramm mit einem try-catch-Block ab und geben Sie die Fehlermeldung auf dem Bildschirm aus. Testen Sie das Programm zunächst mit einem gültigen Semester und anschließend mit einem ungültigen Wert (z. B. 18). |
|
29.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie, wie in Java eigene Fehlermeldungen (Exceptions) definiert und verwendet werden. Sie erfahren, wie eine Klasse selbst Fehler erkennt und diese an das aufrufende Programm weitergibt. Außerdem üben Sie den Umgang mit throw, throws sowie try und catch. |
|
29.4.3 Ergebnis Programmlauf |
|
|
12345 Müller, Semester: 10
|
|
bzw. |
|
|
Fehler: Semester darf nicht größer als 15 sein.
|
|
|
|
29.4.4 Lösung |
|
|
package hochschule;
|
|
|
|
|
|
class SemesterException extends Exception {
|
|
|
SemesterException(String meldung) {
|
|
|
super(meldung);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Stud {
|
|
|
int matrNr;
|
|
|
String name;
|
|
|
int semester;
|
|
|
|
|
|
Stud(int matrNr, String name, int semester) throws SemesterException {
|
|
|
if (semester > 15) {
|
|
|
throw new SemesterException("Semester darf nicht größer als 15 sein.");
|
|
|
}
|
|
|
this.matrNr = matrNr;
|
|
|
this.name = name;
|
|
|
this.semester = semester;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(matrNr + " " + name + ", Semester: " + semester);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe44 {
|
|
|
public static void main(String[] args) {
|
|
|
try {
|
|
|
Stud s1 = new Stud(12345, "Müller", 10);
|
|
|
s1.anzeigen();
|
|
|
} catch (SemesterException e) {
|
|
|
System.out.println("Fehler: " + e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
29.4.5 Betrachtete Themen |
|
- Auslösen einer Exception mit throw
- Eigene Exception-Klassen
- Fehlerbehandlung mit try-catch
- Fehlermeldungen mit getMessage()
- Konstruktor einer Exception
- Objektorientierte Fehlerbehandlung
- Plausibilitätsprüfung von Eingabedaten
- Validierung von Attributwerten
- Vererbung von Exception
- Weitergabe einer Exception mit throws
|
|
29.4.6 Erläuterung |
|
Java besitzt zahlreiche eingebaute Exception-Klassen, beispielsweise für Dateifehler oder ungültige Zahleneingaben. In eigenen Programmen treten jedoch häufig Fehler auf, die nur für den jeweiligen Anwendungsbereich gelten. Dafür können eigene Exception-Klassen definiert werden. |
|
Im vorliegenden Beispiel darf das Semester eines Studierenden höchstens 15 betragen. Diese Regel wird bereits im Konstruktor der Klasse Stud überprüft. |
|
Die Klasse |
|
|
class SemesterException extends Exception
|
|
legt eine neue Exception-Klasse fest. Da sie von Exception erbt, verhält sie sich wie jede andere Java-Exception. Wird ein unzulässiger Wert erkannt, wird die Exception mit throw new SemesterException(...); ausgelöst. Dadurch wird die normale Programmausführung sofort unterbrochen. |
|
Da der Konstruktor eine Exception auslösen kann, muss dies in seiner Methodendeklaration angegeben werden: |
|
|
throws SemesterException
|
|
Das Hauptprogramm erzeugt das Objekt innerhalb eines try-Blocks. Tritt die Exception auf, wird sie im zugehörigen catch-Block abgefangen. Die eigentliche Fehlermeldung wird mit e.getMessage() ausgegeben. Durch diese Vorgehensweise bleibt der Programmcode übersichtlich. Fehler werden dort behandelt, wo sie auftreten, und das Hauptprogramm kann angemessen auf die jeweilige Situation reagieren. |
|
29.5 Aufgabe 45 - Generics |
|
Generische Listen - Eingaben absichern |
|
29.5.1 Aufgabenstellung |
|
Erstellen Sie die Klassen Angestellter und Projekt sowie den Record PC. Legen Sie anschließend für jede dieser Klassen eine eigene generische Liste (ArrayList) an. Fügen Sie jeweils mehrere Objekte in die Listen ein. Geben Sie anschließend |
|
- alle Angestellten,
- alle Projekte und
- alle PCs
|
|
auf dem Bildschirm aus. Verwenden Sie dazu jeweils eine forEach-Schleife. |
|
Erweitern Sie das Programm anschließend um weitere Angestellte, Projekte oder PCs und überprüfen Sie, ob diese automatisch mit ausgegeben werden. |
|
29.5.2 Lernziele |
|
In dieser Aufgabe lernen Sie, wie generische Listen (Generics) in Java verwendet werden. Sie erfahren, wie Objekte unterschiedlicher Klassen in typisierten ArrayList-Objekten gespeichert werden können. Dadurch wird die Typsicherheit erhöht und das Arbeiten mit Sammlungen vereinfacht. |
|
29.5.3 Ergebnis Programmlauf |
|
|
Angestellte:
|
|
|
Anna Müller
|
|
|
Bernd Schmidt
|
|
|
|
|
|
Projekte:
|
|
|
BPMN
|
|
|
Prozessoptimierung
|
|
|
|
|
|
PCs:
|
|
|
PC[invNr=1001, bez=Dell Optiplex, typ=Desktop]
|
|
|
PC[invNr=1002, bez=Lenovo ThinkPad, typ=Notebook]
|
|
|
|
29.5.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
Angestellter(String name, String vorname) {
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
}
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Projekt {
|
|
|
String bez;
|
|
|
|
|
|
Projekt(String bez) {
|
|
|
this.bez = bez;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(bez);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
record PC(int invNr, String bez, String typ) {
|
|
|
}
|
|
|
|
|
|
public class Aufgabe45 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
List<Angestellter> angestellte = new ArrayList<>();
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
List<PC> pcs = new ArrayList<>();
|
|
|
|
|
|
angestellte.add(new Angestellter("Müller", "Anna"));
|
|
|
angestellte.add(new Angestellter("Schmidt", "Bernd"));
|
|
|
|
|
|
projekte.add(new Projekt("BPMN"));
|
|
|
projekte.add(new Projekt("Prozessoptimierung"));
|
|
|
|
|
|
pcs.add(new PC(1001, "Dell Optiplex", "Desktop"));
|
|
|
pcs.add(new PC(1002, "Lenovo ThinkPad", "Notebook"));
|
|
|
|
|
|
System.out.println("Angestellte:");
|
|
|
for (Angestellter a : angestellte) {
|
|
|
a.anzeigen();
|
|
|
}
|
|
|
|
|
|
System.out.println("\nProjekte:");
|
|
|
for (Projekt p : projekte) {
|
|
|
p.anzeigen();
|
|
|
}
|
|
|
|
|
|
System.out.println("\nPCs:");
|
|
|
for (PC pc : pcs) {
|
|
|
System.out.println(pc);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
29.5.5 Betrachtete Themen |
|
- Generics
- Interface List
- Iteration mit der forEach-Schleife
- Klasse ArrayList
- Methode add()
- Objekte in Listen speichern
- Objektlisten verwalten
- Records in Collections
- Typisierte Collections
- Typparameter (<Angestellter>, <Projekt>, <PC>)
- Typsicherheit zur Compilezeit
- Vermeidung von Typumwandlungen (Casting)
|
|
29.5.6 Erläuterung |
|
In vielen Programmen ist die Anzahl der Objekte nicht von Anfang an bekannt. Deshalb verwendet man häufig Collections, also Sammlungen von Objekten. Eine der wichtigsten Collection-Klassen in Java ist die ArrayList. Die Deklaration |
|
|
List<Angestellter> angestellte = new ArrayList<>();
|
|
bedeutet: |
|
- List ist das allgemeine Java-Interface für Listen.
- ArrayList ist eine konkrete Implementierung dieses Interfaces.
- <Angestellter> legt fest, dass ausschließlich Objekte der Klasse Angestellter in dieser Liste gespeichert werden dürfen.
|
|
Diese Schreibweise bezeichnet man als Generics. Der Vorteil besteht darin, dass der Java-Compiler bereits während der Übersetzung überprüft, ob nur passende Objekte eingefügt werden. Fehler werden dadurch früh erkannt. |
|
Neue Elemente werden mit |
|
|
angestellte.add(...);
|
|
an die Liste angehängt. Zur Ausgabe eignet sich die forEach-Schleife: |
|
|
for (Angestellter a : angestellte) {
|
|
|
a.anzeigen();
|
|
|
}
|
|
Sie durchläuft automatisch alle Elemente der Liste, unabhängig davon, wie viele vorhanden sind. Im Beispiel werden drei unterschiedliche Listen verwendet: |
|
- eine Liste von Angestellten,
- eine Liste von Projekten und
- eine Liste von PCs.
|
|
Alle Listen verwenden dieselbe Klasse ArrayList, unterscheiden sich jedoch durch ihren Typparameter. Dadurch kann dieselbe Datenstruktur für beliebige Objektarten genutzt werden, ohne an Typsicherheit zu verlieren. |
|
Generics gehören zu den wichtigen Sprachmitteln der Java-Programmierung. Sie werden in nahezu allen größeren Java-Anwendungen eingesetzt und bilden die Grundlage für den sicheren Umgang mit Collections. |
|
|
|
30 Übungsaufgaben Teil 11 |
|
|
|
30.1 Aufgabe 46 - HashSet |
|
Mengen mit HashSet |
|
30.1.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Projekt mit den Attributen |
|
- Projektbezeichnung
- Standort
|
|
Legen Sie anschließend mehrere Projekte in einer ArrayList an. Verwenden Sie dabei einige Standorte mehrfach, beispielsweise mehrere Projekte in Hannover. Übertragen Sie anschließend alle Standorte in ein HashSet. Geben Sie danach den Inhalt des HashSet auf dem Bildschirm aus. |
|
Vergleichen Sie die Anzahl der Projekte mit der Anzahl der ausgegebenen Standorte und erläutern Sie, warum einige Standorte nur einmal erscheinen. |
|
30.1.2 Lernziele |
|
In dieser Aufgabe lernen Sie die Collection-Klasse HashSet kennen. Sie erfahren, wie sich Werte ohne Duplikate speichern lassen und wie doppelt vorkommende Elemente automatisch entfernt werden. |
|
30.1.3 Ergebnis Programmlauf |
|
|
Standorte:
|
|
|
Bremen
|
|
|
Hannover
|
|
|
Berlin
|
|
|
|
30.1.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Set;
|
|
|
|
|
|
class Projekt {
|
|
|
String bez;
|
|
|
String standort;
|
|
|
|
|
|
Projekt(String bez, String standort) {
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe46 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
Set<String> standorte = new HashSet<>();
|
|
|
|
|
|
projekte.add(new Projekt("BPMN", "Hannover"));
|
|
|
projekte.add(new Projekt("Prozessoptimierung", "Bremen"));
|
|
|
projekte.add(new Projekt("Java-Schulung", "Hannover"));
|
|
|
projekte.add(new Projekt("Datenmodellierung", "Berlin"));
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
standorte.add(p.standort);
|
|
|
}
|
|
|
|
|
|
System.out.println("Standorte:");
|
|
|
|
|
|
for (String s : standorte) {
|
|
|
System.out.println(s);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
30.1.5 Betrachtete Themen |
|
- Automatische Vermeidung doppelter Einträge
- Collection-Klasse HashSet
- Durchlaufen einer Collection mit der forEach-Schleife
- Eindeutige Werte aus einer Objektliste gewinnen
- Einfügen mit add()
- Generics
- Interface Set
- Mengen ohne Duplikate
- Typisierte Collections
- Unterschied zwischen List und Set
|
|
30.1.6 Erläuterung |
|
Während eine Liste (List) Elemente in ihrer Einfügereihenfolge speichert und gleiche Werte mehrfach enthalten kann, arbeitet ein Set nach einem anderen Prinzip: Jeder Wert darf nur ein einziges Mal vorkommen. Die Deklaration |
|
|
Set<String> standorte = new HashSet<>();
|
|
legt eine Menge von Zeichenketten an. Der Typparameter <String> bedeutet, dass nur Zeichenketten gespeichert werden dürfen. Anschließend werden die Standorte aller Projekte in das HashSet übernommen: |
|
|
standorte.add(p.standort);
|
|
Befindet sich ein Standort bereits in der Menge, wird er nicht noch einmal eingefügt. Dadurch enthält das HashSet am Ende nur die unterschiedlichen Standorte. |
|
Im Beispiel existieren mehrere Projekte. Zwei davon befinden sich in Hannover. Obwohl der Standort zweimal eingetragen wird, erscheint er bei der Ausgabe nur einmal. |
|
Der Name HashSet weist darauf hin, dass intern eine Hashfunktion verwendet wird. Diese berechnet aus jedem gespeicherten Wert einen sogenannten Hashwert, der eine sehr schnelle Suche nach bereits vorhandenen Elementen ermöglicht. Dadurch kann das HashSet effizient feststellen, ob ein Wert schon gespeichert wurde. |
|
Ein HashSet eignet sich immer dann, wenn nur eindeutige Werte benötigt werden, beispielsweise |
|
- Standorte von Projekten
- Namen von Abteilungen
- Benutzernamen
- Postleitzahlen
- Artikelnummern
|
|
|
|
30.2 Aufgabe 47 - Maps |
|
Schlüssel-Wert-Paare mit HashMap |
|
30.2.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Stud mit den Attributen |
|
- Matrikelnummer
- Name
- Vorname
|
|
Legen Sie anschließend eine HashMap an, in der die Matrikelnummer als Schlüssel und das zugehörige Objekt Stud als Wert gespeichert wird. Fügen Sie mehrere Studierende in die Map ein. Suchen Sie anschließend einen Studierenden über seine Matrikelnummer und geben Sie dessen Daten aus. |
|
Falls keine passende Matrikelnummer vorhanden ist, soll eine entsprechende Meldung erscheinen. Geben Sie zum Abschluss alle gespeicherten Matrikelnummern aus. Ändern Sie danach den Suchschlüssel und testen Sie sowohl einen erfolgreichen als auch einen erfolglosen Suchvorgang. |
|
30.2.2 Lernziele |
|
In dieser Aufgabe lernen Sie die Collection-Klasse HashMap kennen. Sie erfahren, wie Objekte über einen eindeutigen Schlüssel gespeichert und später schnell wiedergefunden werden können. |
|
30.2.3 Ergebnis Programmlauf |
|
|
Gefundener Studierender:
|
|
|
23456: Clara Meier
|
|
|
|
|
|
Alle Matrikelnummern:
|
|
|
23456
|
|
|
34567
|
|
|
12345
|
|
|
|
30.2.4 Lösung |
|
|
package hochschule;
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
|
|
|
class Stud {
|
|
|
int matrNr;
|
|
|
String name;
|
|
|
String vorname;
|
|
|
|
|
|
Stud(int matrNr, String name, String vorname) {
|
|
|
this.matrNr = matrNr;
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(matrNr + ": " + vorname + " " + name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe47 {
|
|
|
public static void main(String[] args) {
|
|
|
Map<Integer, Stud> studierende = new HashMap<>();
|
|
|
studierende.put(12345, new Stud(12345, "Müller", "Anna"));
|
|
|
studierende.put(23456, new Stud(23456, "Meier", "Clara"));
|
|
|
studierende.put(34567, new Stud(34567, "Weber", "Paul"));
|
|
|
int suchNr = 23456;
|
|
|
Stud gefunden = studierende.get(suchNr);
|
|
|
if (gefunden != null) {
|
|
|
System.out.println("Gefundener Studierender:");
|
|
|
gefunden.anzeigen();
|
|
|
} else {
|
|
|
System.out.println("Kein Studierender mit dieser Matrikelnummer gefunden.");
|
|
|
}
|
|
|
System.out.println("\nAlle Matrikelnummern:");
|
|
|
for (Integer nr : studierende.keySet()) {
|
|
|
System.out.println(nr);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
30.2.5 Betrachtete Themen |
|
- Ausgabe der Schlüssel mit keySet()
- Collection-Klasse HashMap
- Effiziente Suche nach Objekten
- Einfügen mit put()
- Generics
- Interface Map
- Prüfung auf vorhandene Einträge
- Rückgabe von null
- Schlüssel (Key) und Wert (Value)
- Schlüssel-Wert-Paare
- Suchen mit get()
- Typisierte Collections
|
|
30.2.6 Erläuterung |
|
Während eine Liste (List) Objekte der Reihe nach speichert und ein Set eindeutige Werte verwaltet, speichert eine Map ihre Daten als Schlüssel-Wert-Paare. Die Deklaration Map<Integer, Stud> studierende = new HashMap<>(); bedeutet: |
Vgl. Kapitel 32 (NoSQL-DBn) |
- Map ist das allgemeine Interface für Schlüssel-Wert-Sammlungen.
- HashMap ist eine häufig verwendete Implementierung dieses Interfaces.
- Integer ist der Typ des Schlüssels.
- Stud ist der Typ des gespeicherten Objekts.
|
|
Im Beispiel dient die Matrikelnummer als Schlüssel. Da jede Matrikelnummer eindeutig ist, eignet sie sich besonders gut für eine Map. Neue Einträge werden mit |
|
|
studierende.put(12345, new Stud(...));
|
|
angelegt. Der erste Parameter ist der Schlüssel, der zweite das zugehörige Objekt. |
|
Ein großer Vorteil einer Map besteht darin, dass ein Objekt direkt über seinen Schlüssel gefunden werden kann: |
|
|
Stud gefunden = studierende.get(suchNr);
|
|
Existiert der Schlüssel, liefert get() das gespeicherte Objekt zurück. Ist kein entsprechender Eintrag vorhanden, liefert die Methode den Wert null. Deshalb wird anschließend geprüft, |
|
|
if (gefunden != null)
|
|
ob tatsächlich ein Objekt gefunden wurde. Mit |
|
|
studierende.keySet()
|
|
werden alle gespeicherten Schlüssel geliefert. Diese können anschließend beispielsweise mit einer forEach-Schleife ausgegeben werden. |
|
Maps werden überall dort eingesetzt, wo Daten über einen eindeutigen Schlüssel schnell gefunden werden sollen, beispielsweise bei |
|
- Matrikelnummern,
- Personalnummern,
- Kundennummern,
- Artikelnummern oder
- ISBN-Nummern von Büchern.
|
|
|
|
30.3 Aufgabe 48 - Streams |
|
Filtern von Daten mit Streams |
|
30.3.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Angestellter mit den Attributen |
|
|
|
|
Legen Sie mehrere Angestellte in einer ArrayList an. Geben Sie anschließend nur diejenigen Angestellten aus, deren Gehalt größer als 4.000 Euro ist. Verwenden Sie dazu einen Stream, der |
|
- die Liste durchläuft,
- die gewünschten Angestellten auswählt und
- diese anschließend ausgibt.
|
|
Ändern Sie anschließend die Gehälter oder ergänzen Sie weitere Angestellte und beobachten Sie, wie sich das Ergebnis verändert. |
|
30.3.2 Lernziele |
|
In dieser Aufgabe lernen Sie den Einsatz von Streams kennen. Sie erfahren, wie sich Daten aus einer Collection auswählen und anschließend weiterverarbeiten lassen. Dabei lernen Sie den Aufbau einer einfachen Stream-Verarbeitung mit stream(), filter() und forEach() kennen. |
|
30.3.3 Ergebnis Programmlauf |
|
|
Angestellte mit Gehalt über 4000 Euro:
|
|
|
Bernd Schmidt: 5200.0
|
|
|
Clara Weber: 4500.0
|
|
|
|
30.3.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
double gehalt;
|
|
|
|
|
|
Angestellter(String name, String vorname, double gehalt) {
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
this.gehalt = gehalt;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name + ": " + gehalt);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe48 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
List<Angestellter> angestellte = new ArrayList<>();
|
|
|
|
|
|
angestellte.add(new Angestellter("Müller", "Anna", 3800.0));
|
|
|
angestellte.add(new Angestellter("Schmidt", "Bernd", 5200.0));
|
|
|
angestellte.add(new Angestellter("Weber", "Clara", 4500.0));
|
|
|
|
|
|
System.out.println("Angestellte mit Gehalt über 4000 Euro:");
|
|
|
|
|
|
angestellte.stream()
|
|
|
.filter(a -> a.gehalt > 4000.0)
|
|
|
.forEach(a -> a.anzeigen());
|
|
|
}
|
|
|
}
|
|
30.3.5 Betrachtete Themen |
|
- Ausgabe mit forEach()
- Filtern von Daten mit filter()
- Lambda-Ausdrücke (erste Anwendung)
- Methode stream()
- Streams
- Typisierte Collections (List, ArrayList)
- Verarbeitung von Collections
- Verarbeitungsketten (Method Chaining)
- Vergleichsoperatoren
|
|
30.3.6 Erläuterung |
|
Seit Java 8 können Sammlungen (Collections) mit Streams verarbeitet werden. Ein Stream stellt keine eigene Datensammlung dar. Er ermöglicht vielmehr, die Elemente einer vorhandenen Collection nacheinander zu bearbeiten. Die Verarbeitung beginnt mit |
|
|
angestellte.stream()
|
|
Dadurch wird aus der Liste ein Stream erzeugt. Anschließend folgt |
|
|
.filter(a -> a.gehalt > 4000.0)
|
|
Die Methode filter() überprüft jedes Objekt der Reihe nach. Nur diejenigen Angestellten, deren Gehalt größer als 4.000 Euro ist, werden an den nächsten Verarbeitungsschritt weitergegeben. Zum Schluss werden die ausgewählten Objekte ausgegeben: |
|
|
.forEach(a -> a.anzeigen());
|
|
forEach() führt die angegebene Anweisung für jedes gefilterte Objekt aus. |
|
Die drei Methoden bilden gemeinsam eine Verarbeitungskette: Liste -> stream() ->filter() -> forEach(). Dadurch bleibt der Programmcode kurz und gut lesbar. |
|
Streams eignen sich nicht nur zum Filtern. Sie können beispielsweise auch zum |
|
- Sortieren,
- Zählen,
- Gruppieren,
- Berechnen von Summen oder Durchschnittswerten sowie
- Umwandeln von Daten
|
|
verwendet werden. |
|
|
|
30.4 Aufgabe 49 - Lambda |
|
Sortieren mit Lambda-Ausdrücken |
|
30.4.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Angestellter mit den Attributen |
|
|
|
|
Legen Sie mehrere Angestellte in einer ArrayList an. |
|
Sortieren Sie die Liste zunächst alphabetisch nach dem Nachnamen und geben Sie das Ergebnis aus. Sortieren Sie dieselbe Liste anschließend aufsteigend nach dem Gehalt und geben Sie die sortierte Liste erneut aus. Verwenden Sie für beide Sortierungen Lambda-Ausdrücke. |
|
Erweitern Sie das Programm anschließend um weitere Angestellte und überprüfen Sie, ob die Sortierung weiterhin korrekt funktioniert. |
|
30.4.2 Lernziele |
|
In dieser Aufgabe lernen Sie Lambda-Ausdrücke kennen. Sie erfahren, wie sich Listen mit einer kurzen und übersichtlichen Schreibweise sortieren lassen. Dabei lernen Sie zwei verschiedene Sortierkriterien kennen: alphabetisch nach dem Namen und numerisch nach dem Gehalt. |
|
30.4.3 Ergebnis Programmlauf |
|
|
Sortiert nach Name:
|
|
|
Anna Müller: 3800.0
|
|
|
Bernd Schmidt: 5200.0
|
|
|
Jo Staud: 9000.0
|
|
|
Clara Weber: 4500.0
|
|
|
|
|
|
Sortiert nach Gehalt:
|
|
|
Anna Müller: 3800.0
|
|
|
Clara Weber: 4500.0
|
|
|
Bernd Schmidt: 5200.0
|
|
|
Guiseppe Staud: 9000.0
|
|
|
|
30.4.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
class Angestellter {
|
|
|
String name;
|
|
|
String vorname;
|
|
|
double gehalt;
|
|
|
|
|
|
Angestellter(String name, String vorname, double gehalt) {
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
this.gehalt = gehalt;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(vorname + " " + name + ": " + gehalt);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe49 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
List<Angestellter> angestellte = new ArrayList<>();
|
|
|
|
|
|
angestellte.add(new Angestellter("Müller", "Anna", 3800.0));
|
|
|
angestellte.add(new Angestellter("Schmidt", "Bernd", 5200.0));
|
|
|
angestellte.add(new Angestellter("Weber", "Clara", 4500.0));
|
|
|
angestellte.add(new Angestellter("Staud", "Jo", 9000.0));
|
|
|
|
|
|
System.out.println("Sortiert nach Name:");
|
|
|
|
|
|
angestellte.sort(
|
|
|
(a1, a2) -> a1.name.compareTo(a2.name)
|
|
|
);
|
|
|
|
|
|
for (Angestellter a : angestellte) {
|
|
|
a.anzeigen();
|
|
|
}
|
|
|
|
|
|
System.out.println("\nSortiert nach Gehalt:");
|
|
|
|
|
|
angestellte.sort(
|
|
|
(a1, a2) -> Double.compare(a1.gehalt, a2.gehalt)
|
|
|
);
|
|
|
|
|
|
for (Angestellter a : angestellte) {
|
|
|
a.anzeigen();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
30.4.5 Betrachtete Themen |
|
- forEach-Schleife
- Lambda-Ausdrücke
- Mehrfaches Sortieren derselben Liste
- Methode sort()
- Moderne Java-Syntax
- Sortieren von Collections
- Typisierte Collections (List, ArrayList)
- Vergleich numerischer Werte mit Double.compare()
- Vergleich von Zeichenketten mit compareTo()
- Vergleichsfunktionen (Comparator)
|
|
30.4.6 Erläuterung |
|
Listen können in Java mit der Methode sort() sortiert werden. Damit Java weiß, nach welchem Kriterium sortiert werden soll, muss eine Vergleichsfunktion angegeben werden. Im Beispiel geschieht dies mit einem Lambda-Ausdruck: |
|
|
(a1, a2) -> a1.name.compareTo(a2.name)
|
|
Der Ausdruck bedeutet: |
|
- a1 und a2 sind zwei zu vergleichende Angestellte.
- Es werden ihre Nachnamen miteinander verglichen.
- compareTo() liefert einen Wert zurück, der angibt, welches Objekt im Alphabet zuerst stehen soll.
|
|
Dadurch wird die Liste alphabetisch nach den Nachnamen sortiert. |
|
Für die Gehälter wird ein anderer Vergleich verwendet: |
|
|
(a1, a2) -> Double.compare(a1.gehalt, a2.gehalt)
|
|
Double.compare() vergleicht zwei Gleitkommazahlen und liefert ebenfalls das für die Sortierung benötigte Ergebnis zurück. Dadurch werden die Angestellten nach ihrem Gehalt geordnet. |
|
Ein Lambda-Ausdruck ist eine kompakte Schreibweise für eine kleine Funktion. Früher musste hierfür häufig eine eigene Klasse oder ein anonymes Objekt erstellt werden. Heute genügt meist eine einzige Zeile. Die allgemeine Form lautet: |
|
|
(Parameter) -> Anweisung
|
|
oder bei mehreren Anweisungen |
|
|
(Parameter) -> {
|
|
|
...
|
|
|
}
|
|
Lambda-Ausdrücke werden in Java unter anderem verwendet für |
|
- Sortierfunktionen,
- Streams,
- Filter,
- Ereignisbehandlungen in grafischen Oberflächen und
|
|
|
|
30.5 Aufgabe 50 - Projektmitarbeit |
|
Personal- und Projektverwaltung mit Collections |
|
30.5.1 Aufgabenstellung |
|
Erstellen Sie eine Klasse Angestellter mit den Attributen |
|
- Personalnummer
- Name
- Vorname
- Gehalt
|
|
Überprüfen Sie im Konstruktor, ob das angegebene Gehalt gültig ist. Ein negatives Gehalt soll nicht akzeptiert werden. In diesem Fall soll eine IllegalArgumentException ausgelöst werden. |
|
Erstellen Sie außerdem eine Klasse Projekt mit den Attributen |
|
- Projektnummer
- Projektbezeichnung
- Standort
|
|
Legen Sie anschließend mehrere Angestellte in einer ArrayList an. Übertragen Sie die Angestellten zusätzlich in eine HashMap. Verwenden Sie dabei die Personalnummer als Schlüssel und das zugehörige Angestelltenobjekt als Wert. Legen Sie außerdem mehrere Projekte in einer weiteren ArrayList an. |
|
Das Programm soll anschließend folgende Auswertungen durchführen: |
|
- Ausgabe aller Angestellten.
- Suchen eines Angestellten über seine Personalnummer in der HashMap.
- Ausgabe aller Projekte.
- Mit einem Stream Filtern aller Projekte, deren Bezeichnung das Wort "Java" enthält.
- Ermitteln aller unterschiedlichen Projektstandorte mit einem HashSet.
- Sortieren der Angestellten mit einem Lambda-Ausdruck, aufsteigend nach ihrem Gehalt.
- Abfangen einer möglichen IllegalArgumentException mit einem try-catch-Block.
|
|
Testen Sie das Programm anschließend auch mit einem negativen Gehalt und beobachten Sie die Reaktion des Programms. |
|
30.5.2 Ergebnis Programmlauf |
|
|
Alle Angestellten:
|
|
|
1: Anna Müller, Gehalt: 3800.0
|
|
|
2: Bernd Schmidt, Gehalt: 5200.0
|
|
|
3: Clara Weber, Gehalt: 4500.0
|
|
|
|
|
|
Suche Angestellter mit Personalnummer 2:
|
|
|
2: Bernd Schmidt, Gehalt: 5200.0
|
|
|
|
|
|
Alle Projekte:
|
|
|
P100: BPMN (Hannover)
|
|
|
P200: Prozessoptimierung (Bremen)
|
|
|
P300: Java-Schulung (Hannover)
|
|
|
|
|
|
Projekte mit Java im Namen:
|
|
|
P300: Java-Schulung (Hannover)
|
|
|
|
|
|
Alle Standorte:
|
|
|
Bremen
|
|
|
Hannover
|
|
|
|
|
|
Angestellte sortiert nach Gehalt:
|
|
|
1: Anna Müller, Gehalt: 3800.0
|
|
|
3: Clara Weber, Gehalt: 4500.0
|
|
|
2: Bernd Schmidt, Gehalt: 5200.0
|
|
30.5.3 Lernziele |
|
In dieser Aufgabe wenden Sie mehrere wichtige Konzepte der Java-Programmierung gemeinsam an. Sie wiederholen den Umgang mit Exceptions, generischen Listen, Maps, Sets, Streams und Lambda-Ausdrücken. |
|
Ziel ist es, Daten zu Angestellten und Projekten in unterschiedlichen Collections zu speichern, zu durchsuchen, zu filtern, auszuwerten und zu sortieren. |
|
|
|
30.5.4 Lösung |
|
|
package firma;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
|
|
|
class Angestellter {
|
|
|
int persNr;
|
|
|
String name;
|
|
|
String vorname;
|
|
|
double gehalt;
|
|
|
|
|
|
Angestellter(int persNr, String name, String vorname, double gehalt) {
|
|
|
if (gehalt < 0) {
|
|
|
throw new IllegalArgumentException("Gehalt darf nicht negativ sein.");
|
|
|
}
|
|
|
|
|
|
this.persNr = persNr;
|
|
|
this.name = name;
|
|
|
this.vorname = vorname;
|
|
|
this.gehalt = gehalt;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(persNr + ": " + vorname + " " + name
|
|
|
+ ", Gehalt: " + gehalt);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Projekt {
|
|
|
String projektNr;
|
|
|
String bez;
|
|
|
String standort;
|
|
|
|
|
|
Projekt(String projektNr, String bez, String standort) {
|
|
|
this.projektNr = projektNr;
|
|
|
this.bez = bez;
|
|
|
this.standort = standort;
|
|
|
}
|
|
|
|
|
|
void anzeigen() {
|
|
|
System.out.println(projektNr + ": " + bez + " (" + standort + ")");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class Aufgabe50 {
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
try {
|
|
|
List<Angestellter> personal = new ArrayList<>();
|
|
|
|
|
|
personal.add(new Angestellter(1, "Müller", "Anna", 3800.0));
|
|
|
personal.add(new Angestellter(2, "Schmidt", "Bernd", 5200.0));
|
|
|
personal.add(new Angestellter(3, "Weber", "Clara", 4500.0));
|
|
|
|
|
|
Map<Integer, Angestellter> personalMap = new HashMap<>();
|
|
|
|
|
|
for (Angestellter a : personal) {
|
|
|
personalMap.put(a.persNr, a);
|
|
|
}
|
|
|
|
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
|
|
|
|
projekte.add(new Projekt("P100", "BPMN", "Hannover"));
|
|
|
projekte.add(new Projekt("P200", "Prozessoptimierung", "Bremen"));
|
|
|
projekte.add(new Projekt("P300", "Java-Schulung", "Hannover"));
|
|
|
|
|
|
System.out.println("Alle Angestellten:");
|
|
|
for (Angestellter a : personal) {
|
|
|
a.anzeigen();
|
|
|
}
|
|
|
|
|
|
System.out.println("\nSuche Angestellter mit Personalnummer 2:");
|
|
|
Angestellter gefunden = personalMap.get(2);
|
|
|
|
|
|
if (gefunden != null) {
|
|
|
gefunden.anzeigen();
|
|
|
}
|
|
|
|
|
|
System.out.println("\nAlle Projekte:");
|
|
|
for (Projekt p : projekte) {
|
|
|
p.anzeigen();
|
|
|
}
|
|
|
|
|
|
System.out.println("\nProjekte mit Java im Namen:");
|
|
|
projekte.stream()
|
|
|
.filter(p -> p.bez.contains("Java"))
|
|
|
.forEach(p -> p.anzeigen());
|
|
|
|
|
|
Set<String> standorte = new HashSet<>();
|
|
|
|
|
|
for (Projekt p : projekte) {
|
|
|
standorte.add(p.standort);
|
|
|
}
|
|
|
|
|
|
System.out.println("\nAlle Standorte:");
|
|
|
for (String s : standorte) {
|
|
|
System.out.println(s);
|
|
|
}
|
|
|
|
|
|
System.out.println("\nAngestellte sortiert nach Gehalt:");
|
|
|
personal.sort(
|
|
|
(a1, a2) -> Double.compare(a1.gehalt, a2.gehalt)
|
|
|
);
|
|
|
|
|
|
for (Angestellter a : personal) {
|
|
|
a.anzeigen();
|
|
|
}
|
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
System.out.println("Fehler: " + e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
30.5.5 Betrachtete Themen |
|
- Auslösen einer IllegalArgumentException
- Ausnahmebehandlung mit try-catch
- Filtern mit filter()
- forEach-Schleifen
- Generics
- Interface List
- Interface Map
- Interface Set
- Klasse ArrayList
- Klasse HashMap
- Klasse HashSet
- Klassen und Objekte
- Konstruktoren
- Lambda-Ausdrücke
- Method Chaining
- Numerischer Vergleich mit Double.compare()
- Plausibilitätsprüfung von Attributwerten
- Schlüssel-Wert-Paare
- Sortieren mit sort()
- Streams
- Suchen mit get()
- Typisierte Collections
- Verarbeitung mit forEach()
- Vermeidung doppelter Werte
|
|
30.5.6 Erläuterung |
|
Diese Aufgabe verbindet mehrere Konzepte, die in den vorherigen Aufgaben einzeln behandelt wurden. Dadurch entsteht eine kleine Personal- und Projektverwaltung. |
|
Prüfung des Gehalts |
|
Im Konstruktor der Klasse Angestellter wird geprüft, ob das Gehalt negativ ist: |
|
|
if (gehalt < 0) {
|
|
|
throw new IllegalArgumentException(
|
|
|
"Gehalt darf nicht negativ sein."
|
|
|
);
|
|
|
}
|
|
Ein negatives Gehalt wird als ungültiger Wert betrachtet. Deshalb wird eine IllegalArgumentException ausgelöst. Bei dieser Exception handelt es sich um eine bereits in Java vorhandene Exception-Klasse. Es muss daher keine eigene Exception-Klasse erstellt werden. Die Exception wird im Hauptprogramm abgefangen: |
|
|
try {
|
|
Programmanweisungen |
|
|
} catch (IllegalArgumentException e) {
|
|
|
System.out.println("Fehler: " + e.getMessage());
|
|
|
}
|
|
Dadurch kann das Programm auf den Fehler reagieren und eine verständliche Meldung ausgeben. |
|
Speicherung in einer Liste |
|
Die Angestellten werden zunächst in einer ArrayList gespeichert: |
|
|
List<Angestellter> personal = new ArrayList<>();
|
|
Eine Liste eignet sich, wenn mehrere Objekte nacheinander gespeichert und vollständig durchlaufen werden sollen. |
|
Neue Angestellte werden mit add() eingefügt: |
|
|
personal.add(
|
|
|
new Angestellter(1, "Müller", "Anna", 3800.0)
|
|
|
);
|
|
Speicherung in einer Map |
|
Zusätzlich werden die Angestellten in einer HashMap gespeichert: |
|
|
Map<Integer, Angestellter> personalMap = new HashMap<>();
|
|
Die Personalnummer dient dabei als Schlüssel. Das Angestelltenobjekt bildet den zugehörigen Wert. Die Übertragung aus der Liste in die Map erfolgt mit einer forEach-Schleife: |
|
|
for (Angestellter a : personal) {personalMap.put(a.persNr, a);}
|
|
Danach kann ein Angestellter direkt über seine Personalnummer gesucht werden: |
|
|
Angestellter gefunden = personalMap.get(2);
|
|
Wird kein passender Schlüssel gefunden, liefert get() den Wert null. Deshalb sollte das Ergebnis geprüft werden: |
|
|
if (gefunden != null) {
|
|
|
gefunden.anzeigen();
|
|
|
}
|
|
Filtern mit einem Stream |
|
Die Projektliste wird mit einem Stream verarbeitet: |
|
|
projekte.stream()
|
|
|
.filter(p -> p.bez.contains("Java"))
|
|
|
.forEach(p -> p.anzeigen());
|
|
Die Verarbeitung besteht aus drei Schritten: Projektliste -> -> stream() -> filter() -> forEach(). |
|
- stream() erzeugt einen Stream aus der Liste.
- filter() lässt nur diejenigen Projekte passieren, deren Bezeichnung das Wort „Java“ enthält.
- forEach() gibt die ausgewählten Projekte aus.
|
|
Der Ausdruck |
|
|
p -> p.bez.contains("Java")
|
|
ist ein Lambda-Ausdruck. p steht jeweils für ein Projekt. Das Ergebnis des Ausdrucks ist entweder true oder false. |
|
Eindeutige Standorte mit einem Set |
|
Für die Projektstandorte wird ein HashSet verwendet: |
|
|
Set<String> standorte = new HashSet<>();
|
|
Alle Projektstandorte werden in diese Menge eingefügt: |
|
|
for (Projekt p : projekte) {
|
|
|
standorte.add(p.standort);
|
|
|
}
|
|
Ein Set speichert jeden Wert höchstens einmal. Da zwei Projekte den Standort Hannover besitzen, wird Hannover bei der Ausgabe trotzdem nur einmal angezeigt. |
|
Sortieren mit einem Lambda-Ausdruck |
|
Die Liste der Angestellten wird nach dem Gehalt sortiert: |
|
|
personal.sort(
|
|
|
(a1, a2) -> Double.compare(a1.gehalt, a2.gehalt)
|
|
|
);
|
|
Jeweils zwei Angestellte werden miteinander verglichen. Double.compare() prüft die beiden Gehälter und bestimmt daraus ihre Reihenfolge. Die Sortierung erfolgt aufsteigend. Der Angestellte mit dem niedrigsten Gehalt steht anschließend am Anfang der Liste. |
|
Zusammenspiel der Collections |
|
Die Aufgabe zeigt, dass unterschiedliche Collections für unterschiedliche Zwecke eingesetzt werden: |
|
- Eine List speichert mehrere Objekte in einer bestimmten Reihenfolge.
- Eine Map ermöglicht den direkten Zugriff über einen Schlüssel.
- Ein Set speichert nur unterschiedliche Werte.
- Ein Stream verarbeitet und filtert die Elemente einer Collection.
- Ein Lambda-Ausdruck beschreibt kurz, wie gefiltert oder sortiert werden soll.
|
|
Damit fasst Aufgabe 50 wesentliche Inhalte der Aufgaben 43 bis 49 in einem gemeinsamen Programm zusammen. |
|
31 Exkurs - Zusammenhänge |
|
Wie ist der Gesamtzusammenhang zwischen Listen, Array-Listen, Link-Arrays, usw.? |
|
|
|
31.1 Die Grundidee |
|
Mehrere Objekte verwalten |
|
Angenommen, Sie möchten mehrere Studierende verwalten: |
|
|
Stud1
|
|
|
Stud2
|
|
|
Stud3
|
|
|
Stud4
|
|
|
...
|
|
Dafür gibt es verschiedene Techniken. |
|
31.2 Arrays |
|
Die einfachste Lösung ist ein Array: |
|
|
Stud[] gruppe = new Stud[100];
|
|
Hier wird Platz für 100 Referenzen reserviert. |
|

|
|
Vorteile: |
|
- einfach
- schneller Zugriff über Index: gruppe[2]
|
|
Nachteile: |
|
- Größe ist fest
- Einfügen und Löschen aufwendig
|
|
31.3 Verkettete Listen |
|
Hier kennt jedes Objekt seinen Nachfolger: |
|
|
class Stud {
|
|
|
String name;
|
|
|
Stud naechster;
|
|
|
}
|
|
Beispiel: |
|
|
s1 -> s2 -> s3 -> s4 -> null
|
|
Vorteile: |
|
- beliebig erweiterbar
- Einfügen und Löschen einfach
|
|
Nachteile: |
|
- kein direkter Zugriff auf das 3. oder 10. Element
- man muss die Liste durchlaufen
|
|
31.4 ArrayList |
|
Die Klasse ArrayList kombiniert die Vorteile von Arrays und Listen. |
|
|
List<Stud> gruppe = new ArrayList<>();
|
|
Intern arbeitet sie mit einem Array, vergrößert dieses aber automatisch. |
|
|
gruppe.add(s1);
|
|
|
gruppe.add(s2);
|
|
Vorteile: |
|
- Größe flexibel
- einfache Programmierung
- direkter Zugriff mit gruppe.get(2)
|
|
Deshalb wird sie heute in Java am häufigsten verwendet. |
|
31.5 LinkedList |
|
Java besitzt zusätzlich die Klasse LinkedList. |
|
|
List<Stud> gruppe = new LinkedList<>();
|
|
Intern ist sie eine verkettete Liste. |
|
|
s1 <-> s2 <-> s3 <-> s4
|
|
Für Einsteiger ist sie interessant, weil sie dem theoretischen Listenkonzept entspricht. |
|
31.6 Link-Arrays |
|
Hier kommt eine andere Ebene ins Spiel. |
|
Link-Arrays bei Beziehungen |
|
Nehmen wir eine n:m-Beziehung: |
|
|
Angestellter ---- Projekt
|
|
Ein Angestellter arbeitet in mehreren Projekten. Ein Projekt hat mehrere Angestellte. Dann speichert man oft Referenzen: |
|
|
class Angestellter {
|
|
|
List<Projekt> projekte;
|
|
|
}
|
|
oder einfacher: |
|
|
class Angestellter {
|
|
|
Projekt[] projekte;
|
|
|
}
|
|
Dieses Array enthält Links zu Projekten. Deshalb sprechen manche Lehrbücher von einem Link-Array. |
|
|
Angestellter Meier
|
|
|
|
|
Das ist also kein eigener Datentyp, sondern lediglich ein Array, dessen Elemente Referenzen auf andere Objekte enthalten. |
|
31.7 Zusammenfassung |
|

|
|
|
|
Link-Arrays sind ein Modellierungsmittel für Beziehungen zwischen Objekten, während Listen und ArrayLists allgemeine Datenstrukturen zur Verwaltung beliebig vieler Objekte sind. |
|
32 Exkurs - Sammlungen (collection) |
|
In Java bezeichnet man als Sammlung (engl. Collection) eine Datenstruktur, die mehrere Objekte gemeinsam verwaltet. Statt viele einzelne Variablen anzulegen, |
|
|
Stud s1;
|
|
|
Stud s2;
|
|
|
Stud s3;
|
|
kann man die Objekte in einer Sammlung zusammenfassen: |
|
|
List<Stud> studierende = new ArrayList<>();
|
|
Die Sammlung enthält dann beliebig viele Objekte des Typs Stud. |
|
|
|
32.1 Warum braucht man Sammlungen? |
|
Angenommen, eine Hochschule verwaltet Studierende. Mit einzelnen Variablen: |
|
|
Stud s1 = new Stud();
|
|
|
Stud s2 = new Stud();
|
|
|
Stud s3 = new Stud();
|
|
ist die Anzahl fest vorgegeben. Mit einer Sammlung: |
|
|
List<Stud> studierende = new ArrayList<>();
|
|
|
|
|
|
studierende.add(s1);
|
|
|
studierende.add(s2);
|
|
|
studierende.add(s3);
|
|
können jederzeit weitere Studierende hinzugefügt werden. |
|
32.2 Wichtige Sammlungen in Java |
|
Die bekanntesten Sammlungen stammen aus dem Paket |
|
|
import java.util.*;
|
|
32.2.1 List |
|
Speichert Elemente in einer Reihenfolge. |
|
|
List<String> namen = new ArrayList<>();
|
|
|
|
|
|
namen.add("Anna");
|
|
|
namen.add("Ben");
|
|
|
namen.add("Clara");
|
|
Ausgabe: |
|
|
Anna
|
|
|
Ben
|
|
|
Clara
|
|
32.2.2 Set |
|
Speichert Elemente ohne Duplikate. |
|
|
Set<String> namen = new HashSet<>();
|
|
|
|
|
|
namen.add("Anna");
|
|
|
namen.add("Anna");
|
|
|
namen.add("Ben");
|
|
Das zweite "Anna" wird nicht übernommen. |
|
32.2.3 Map |
|
Speichert Schlüssel-Wert-Paare. |
|
|
Map<Integer, String> studenten = new HashMap<>();
|
|
|
|
|
|
studenten.put(1001, "Maier");
|
|
|
studenten.put(1002, "Schulz");
|
|
Hier dient die Matrikelnummer als Schlüssel. |
|
32.3 Sammlungen und Arrays |
|
Ein Array ist keine Collection, erfüllt aber einen ähnlichen Zweck. |
|
Array: |
|
|
Stud[] gruppe = new Stud[3];
|
|
Vorteil: |
|
- einfach
- gut für Einsteiger
|
|
Nachteil: |
|
|
|
|
Collection: |
|
|
List<Stud> gruppe = new ArrayList<>();
|
|
Vorteil: |
|
- wächst automatisch
- bietet viele Hilfsmethoden
|
|
32.4 Zusammenhang mit obigen |
|
In den bisherigen Aufgaben kamen Sammlungen bereits vor: |
|
|
List<Note> noten = new ArrayList<>();
|
|
Diese Sammlung speichert alle Noten eines Studierenden. Ebenso bei der n:m-Beziehung: |
|
|
List<Projekt> projekte = new ArrayList<>();
|
|
Ein Angestellter kann dadurch beliebig viele Projekte besitzen. Oder bei der Assoziationsklasse: |
|
|
List<Mitarbeit> mitarbeitListe = new ArrayList<>();
|
|
Hier enthält die Sammlung alle vorhandenen Beziehungen zwischen Angestellten und Projekten. |
|
Für den Einstieg ist es sinnvoll, sich eine Sammlung einfach als einen Container für viele Objekte desselben Typs vorstellen. Sie entspricht dem UML-Konzept eines mehrwertigen Attributs (Multiplizität 0..* oder 1..*), wird in Java aber meist durch Klassen wie ArrayList realisiert. |
|
33 Exkurs - NoSQL? |
|
Die Schlüssel-Wert-Paare von Java erinnern an die NoSQL-Key-Value - Datenbanken, deshalb hier eine kurze Betrachtung. |
|
|
|
33.1 Vergleich |
|
Sie beruhen auf demselben Grundprinzip, sind aber nicht identisch. Die Java-Klasse |
|
|
Map<Integer, String> studenten = new HashMap<>();
|
|
und eine Key-Value-Datenbank wie z. B. Redis oder Amazon DynamoDB speichern beide Daten als Schlüssel-Wert-Paare: |
|
|
1001 -> Maier
|
|
|
1002 -> Schulz
|
|
|
1003 -> Weber
|
|
Der Unterschied liegt vor allem darin, wo und wie die Daten gespeichert werden. |
|
|
|
| Java Map |
Key-Value-Datenbank |
| Liegt im Arbeitsspeicher eines Programms |
Liegt dauerhaft in einer Datenbank |
| Existiert nur während der Programmausführung |
Bleibt nach dem Programmende erhalten |
| Wird von einem einzelnen Programm genutzt |
Kann von vielen Programmen gleichzeitig genutzt werden |
| Sehr schnell innerhalb des Programms |
Netzwerkzugriff möglich |
| Keine Datensicherung |
Dauerhafte Speicherung |
| |
Vergleich
|
|
Java: |
|
|
Map<Integer, String> studenten = new HashMap<>();
|
|
|
|
|
|
studenten.put(1001, "Maier");
|
|
|
studenten.put(1002, "Schulz");
|
|
NoSQL-Key-Value-Datenbank: |
|
|
Key: 1001
|
|
|
Value: Maier
|
|
|
|
|
|
Key: 1002
|
|
|
Value: Schulz
|
|
Das Konzept ist also praktisch identisch. |
|
33.2 Objekte als Werte |
|
In Java speichert man häufig ganze Objekte: |
|
|
Map<Integer, Stud> studenten = new HashMap<>();
|
|
Dann enthält die Map: |
|
|
1001 -> Stud-Objekt von Maier
|
|
|
1002 -> Stud-Objekt von Schulz
|
|
Viele moderne Key-Value-Datenbanken machen genau dasselbe. Der Value ist dann nicht nur ein String, sondern ein komplexes Objekt, oft im JSON-Format: |
|
|
{
|
|
|
"matrNr": 1001,
|
|
|
"name": "Maier",
|
|
|
"vorname": "Paul"
|
|
|
}
|
|
33.3 Historischer Zusammenhang |
|
Didaktisch kann man sagen: |
|

|
|
|
|
Die NoSQL-Key-Value-Datenbanken übertragen das aus Java bekannte Map-Prinzip auf eine dauerhaft gespeicherte, verteilte Datenbank. Eine Key-Value-Datenbank kann man sich zunächst wie eine riesige, dauerhaft gespeicherte Map vorstellen. Die tatsächlichen Systeme bieten zusätzlich Datensicherung, Parallelzugriffe, Verteilung auf mehrere Rechner und oft sehr große Datenmengen. |
|
34 Themenindex |
|
A |
|
|
Abstrakte Klassen ................ Aufgabe 36
|
|
|
Abstrakte Methoden ............... Aufgabe 36
|
|
|
Accessor-Methoden ................ Aufgabe 41
|
|
|
add()-Methode .................... Aufgaben 20, 27, 28
|
|
|
addKurs() ........................ Aufgabe 20
|
|
|
addMitarbeiter() ................. Aufgaben 28, 30
|
|
|
addProjekt() ..................... Aufgaben 27, 28
|
|
|
addStudent() ..................... Aufgabe 20
|
|
|
addUntergebener() ................ Aufgabe 29
|
|
|
Adresse .......................... Aufgaben 19, 19b
|
|
|
Aggregation (UML) ................ Kapitel UML
|
|
|
Aggregation von Daten ............ Aufgabe 30
|
|
|
Aggregationsfunktion ............. Aufgabe 30
|
|
|
Angestellter ..................... Aufgaben 23 ... 41
|
|
|
Anonyme Objekte .................. Aufgabe 3
|
|
|
Array ............................ Aufgaben 1 ... 3
|
|
|
ArrayList ........................ Aufgaben 20, 22, 27...30
|
|
|
Assoziation ...................... Aufgaben 4a...4e, 19...30
|
|
|
Assoziationsklasse ............... Aufgabe 4e
|
|
|
Attribute ........................ Aufgaben 1...41
|
|
|
Auswertungsmethoden .............. Aufgabe 30
|
|
B |
|
|
Basisklasse ...................... Aufgaben 7, 33...40
|
|
|
Beziehungen zwischen Klassen ..... Aufgaben 4, 19...30
|
|
|
Bidirektionale Beziehung ......... Aufgaben 4c, 19b, 28
|
|
|
Bidirektionale n:m-Beziehung ..... Aufgabe 28
|
|
|
Body eines Records ............... Aufgabe 41
|
|
|
Boolean .......................... Aufgabe 9
|
|
|
BufferedReader ................... HS Daten 19.5
|
|
|
BufferedWriter ................... HS Daten 19.3
|
|
C |
|
|
CSV-Datei ....................... HS Daten 19.8
|
|
|
contains() ...................... Aufgabe 28
|
|
|
Collection ...................... siehe List
|
|
|
Compiler ........................ HS-Projekte
|
|
D |
|
|
Dateien ......................... HS Daten Kapitel 19
|
|
|
Datei erzeugen .................. HS Daten 19.1
|
|
|
Datei lesen ..................... HS Daten 19.4...19.8
|
|
|
Datei schreiben ................. HS Daten 19.2, 19.3
|
|
|
Dateipfad ....................... HS Daten
|
|
|
Datenaggregation ................ Aufgabe 30
|
|
|
Datenklasse ..................... Aufgabe 41
|
|
|
Datenkapselung .................. Aufgabe 8, HS8
|
|
|
Datensatz ....................... Aufgabe 41
|
|
|
double .......................... Aufgaben 30, 36
|
|
|
Druckbar (Interface) ............ Aufgabe 37
|
|
|
Durchlaufen einer Liste ......... Aufgaben 20, 22, 27...30
|
|
E |
|
|
Eclipse ..........................HS-Projekte, hsdaten
|
|
|
Einlesen von Dateien ............ HS Daten 19.4...19.8
|
|
|
equals() ........................ Aufgabe 6, Aufgabe 41
|
|
|
equals()-Methode ................ Aufgaben 6, 41
|
|
|
Exception ....................... HS Daten 19
|
|
|
Exception-Behandlung ............ HS Daten 19
|
|
|
extends ......................... Aufgaben 7, 33
|
|
F |
|
|
Fachattribute ................... Aufgaben 4, 23...41
|
|
|
Datei (File) .................... HS Daten 19.1
|
|
|
File-Klasse ..................... HS Daten 19.1
|
|
|
FileNotFoundException ........... HS Daten 19.4, 19.8
|
|
|
FileReader ...................... HS Daten 19.4, 19.8
|
|
|
FileWriter ...................... HS Daten 19.2, 19.3
|
|
|
foreach-Schleife ................ Aufgaben 20, 22, 27...30
|
|
G |
|
|
Gehaltsauswertung ............... Aufgabe 30
|
|
|
Gehaltssumme .................... Aufgabe 30
|
|
|
Generalisierung ................. Aufgabe 33
|
|
|
Getter .......................... Aufgabe 8
|
|
|
Getter-Methoden ... ............. Aufgabe 8
|
|
|
GUI ............................. Aufgaben 22, 40a
|
|
H |
|
|
hashCode() ...................... Aufgabe 6, Aufgabe 41
|
|
|
Hierarchie ...................... Aufgabe 29
|
|
|
Hierarchische Beziehungen ....... Aufgabe 29
|
|
|
Hochschulbeispiel ............... Aufgaben 1...22
|
|
|
hsdaten ......................... Kapitel 19
|
|
|
IOException ..................... HS Daten 19
|
|
|
Immutable Objects ............... Aufgabe 41
|
|
|
Inheritance (engl.) ............. siehe Vererbung
|
|
|
Instanz ......................... Aufgaben 1...41
|
|
|
Interface ....................... Aufgaben 37, 38
|
|
|
Interfaces ...................... Aufgaben 37, 38
|
|
|
Inventarnummer .................. Aufgabe 41
|
|
|
is-a-Beziehung .................. Aufgabe 33
|
|
I |
|
|
Immutable Objects ............... Aufgabe 41
|
|
|
Instanz ......................... Aufgaben 1...41
|
|
|
Interface ....................... Aufgaben 37, 38
|
|
|
Interfaces ...................... Aufgaben 37, 38
|
|
|
Inventarnummer .................. Aufgabe 41
|
|
|
is-a-Beziehung .................. Aufgabe 33
|
|
|
instanceof ...................... Aufgabe 40
|
|
J |
|
|
JOptionPane ..................... Aufgaben 22, 40a
|
|
K |
|
|
Klassendiagramm ................. Aufgaben 21, 23
|
|
|
Klassenattribute ................ Grundlagen
|
|
|
Klassenbeziehungen .............. Aufgaben 4, 19...30
|
|
|
Komposition ..................... UML-Kapitel
|
|
|
Konstruktor ..................... Aufgaben 2, 7, 11, 19...41
|
|
|
Konstruktorüberladung ........... Aufgaben 9, 35
|
|
|
Konsistenz von Beziehungen ...... Aufgabe 28
|
|
|
Konsolenausgabe ................. zahlreiche Aufgaben
|
|
|
Konstruktor eines Records ....... Aufgabe 41
|
|
|
Kurs ............................ Aufgabe 20
|
|
L |
|
|
Lesen von Dateien ............... HS Daten 19.4...19.8
|
|
|
LinkedList ...................... Aufgabe 22
|
|
|
List ............................ Aufgaben 20, 22, 27...30
|
|
|
List ............................ Aufgaben 4, 19
|
|
|
List ............................ Aufgaben 4a...4c
|
|
|
Lokale Variablen ................ Aufgaben 5, 30
|
|
M |
|
|
Matrikelnummer .................. Aufgaben 1...22
|
|
|
Mehrfachvererbung (über Interf.). Aufgabe 38
|
|
|
Mehrere Interfaces .............. Aufgabe 38
|
|
|
Mehrwertige Attribute ........... Aufgaben 4, 20, 27, 28
|
|
|
Methoden überladen .............. Aufgaben 9, 35
|
|
|
Methoden überschreiben .......... Aufgaben 7, 34
|
|
|
Methodensignatur ................ Aufgaben 9, 35
|
|
|
Mitarbeiter ..................... Aufgaben 23...32
|
|
|
Modellierung .................... Aufgaben 21...30
|
|
|
Modellierung von Beziehungen .... Aufgaben 4, 19...30
|
|
|
module-info.java ................ HS-Projekte
|
|
|
n:m-Beziehung ................... Aufgaben 4d, 4e, 20, 21, 28
|
|
|
null ............................ Aufgabe 29
|
|
|
null-Prüfung .................... Aufgabe 29
|
|
|
Numerische Attribute ............ Aufgabe 30
|
|
O |
|
|
Objekterzeugung ................. Aufgaben 1...41
|
|
|
Objekthierarchie ................ Aufgabe 29
|
|
|
Objektlisten .................... Aufgaben 20, 22, 27...30
|
|
|
Objektreferenz .................. Aufgaben 4...41
|
|
|
Objektverknüpfung ............... Aufgaben 4...30
|
|
|
Objektzustand ................... Aufgaben 8, 30
|
|
|
Superklasse ..................... Aufgaben 7, 33...40
|
|
|
Overloading (Überladen) ......... Aufgaben 9, 35
|
|
|
Overriding (Überschreiben) ...... Aufgaben 7, 34
|
|
P |
|
|
PC .............................. Aufgaben 23...41
|
|
|
Polymorphie ..................... Aufgaben 39, 40
|
|
|
private ......................... Aufgabe 8, HS8
|
|
|
Projekt ......................... Aufgaben 23...32
|
|
|
Projektzuordnung ................ Aufgaben 27, 28
|
|
|
Prüfung auf null ................ Aufgabe 29
|
|
R |
|
|
Reader .......................... HS Daten 19
|
|
|
Record .......................... Aufgabe 41
|
|
|
Records ......................... Aufgabe 41
|
|
|
Rekursive Beziehung............. Aufgabe 29
|
|
|
Rückgabewert .................... Aufgaben 30, 36
|
|
S |
|
|
Scanner ......................... Aufgaben 5, HS Daten 19.4, 19.8
|
|
|
Schreiben von Dateien ........... HS Daten 19.2, 19.3
|
|
|
Selbstbeziehung ................. Aufgabe 29
|
|
|
Setter .......................... Aufgabe 8
|
|
|
Setter-Methoden ................. Aufgabe 8
|
|
|
Spezialisierung ................. Aufgabe 33
|
|
|
Standardkonstruktor ............. HS8
|
|
|
Standort ........................ Aufgaben 23...32
|
|
|
Student ......................... Aufgaben 1...22
|
|
|
Stud ............................ HS-Projekte
|
|
|
super ........................... Aufgaben 7, 33
|
|
|
Summenbildung ................... Aufgabe 30
|
|
|
Swing ........................... Aufgaben 22, 40a
|
|
T |
|
|
this ............................ Aufgaben 28, 29
|
|
|
this-Referenz ................... Aufgaben 28, 29
|
|
|
toString() ...................... Aufgaben 6, 41
|
|
|
Typumwandlung ................... Aufgabe 40
|
|
U |
|
|
Überladen ....................... Aufgaben 9, 35
|
|
|
Überschreiben ................... Aufgaben 7, 34
|
|
|
UML ............................. Aufgaben 21...41
|
|
|
UML-Klassendiagramm ............. Aufgaben 21, 23
|
|
|
Unidirektionale Beziehung ....... Aufgaben 4a, 4b, 19
|
|
|
Unveränderliche Datenobjekte .... Aufgabe 41
|
|
|
Untergebene ..................... Aufgabe 29
|
|
V |
|
|
Vererbung ....................... Aufgaben 7, 33...40
|
|
|
Verkettete Liste ................ Aufgabe 22
|
|
|
Verknüpfung von Objekten ........ Aufgaben 4...30
|
|
|
Verwendung mehrerer Klassen ..... Aufgaben 4...41
|
|
|
Vorgesetzter .................... Aufgabe 29
|
|
W |
|
|
while-Schleife .................. Aufgabe 22
|
|
|
Writer .......................... HS Daten 19
|
|
Z |
|
|
Zugriff auf Objektattribute ..... zahlreiche Aufgaben
|
|
|
Zugriffsmethoden ................ Aufgaben 8, 41
|
|
|
Zusammenarbeit
|
|
|
mehrerer Klassen .............. Aufgaben 4...41
|
|
|
|
|
|
|
35 Literatur |
|
|
|
H |
|
Habelitz 2022 Habelitz, Hans-Peter: Programmieren lernen mit Java. (7. Auflage). Print-Ausgabe. Bonn 2022 (Rheinwerk). |
|
Habelitz 2025 Habelitz, Hans-Peter: Programmieren lernen mit Java. (8. Auflage). E-Book. Bonn 2025 (Rheinwerk) |
|
Kofler 2022 Kofler, Michael: Java. Der Grundkurs. Bonn 2022 (Rheinwerk) |
|
Pepper 2007 Pepper, Peter: Programmieren lernen. Eine grundlegende Einführung mit Java (3. Auflage), Berlin und Heidelberg 2007 (Springer-Verlag) |
|
Ratz et al. 2018 Ratz, Dietmar; Schulmeister-Zimolong, Dennis; Seese, Detlef; Wiesenberger, Jan: Grundkurs Programmieren in Java (8. Auflage). München 2018 |
|
Staud |
|
Staud 2019 Staud, Josef Ludwig: Unternehmensmodellierung - Objektorientierte Theorie und Praxis mit UML 2.5. (2. Auflage). Berlin u.a. 2019 (Springer Gabler) |
|
Staud 2021 Staud, Josef Ludwig: Relationale Datenbanken. Grundlagen, Modellierung, Speicherung, Alternativen. 2. Auflage 2021. Verlag tredition GmbH, Paperback: 978-3-347-35883-6 Hardcover: 978-3-347-35884-3 E-Book: 978-3-347-35885-0 |
|
Staud 2024 Staud, Josef Ludwig: Geschäftsprozesse und ihre Modellierung mit der Methode Business Procass Model and Notation (BPMN 2.0). (2. Auflage). Hamburg 2024 (tredition) Als Hardcover, Softcover, E-Book |
|
Staud 2025 Staud, Josef Ludwig: Ereignisgesteuerte Prozessketten. Das Werkzeug für die Modellierung von Geschäftsprozessen. (2. Auflage), Hamburg 2025 (tredition) |
|
Staud 2026a Staud, Josef Ludwig: Objektorientierte Modellierung mit der UML 2.5. Mit Java-Beispielen (Version 2026/7). Web-Text: https://www.staud.info/leitOO.php |
|
Staud 2026b Staud, Josef Ludwig: Java-Programme. Lern- und Lesehilfe für die Java-Programme in [Staud 2026a] (Version 2026/7). Web-Text: https://www.staud.info/leitOO.php |
|
Steppan 2020 Steppan, Berhard: Einstieg in Java mit Eclipse. München 2020 (Hanser) |
|
U |
|
Ullenboom 2022 Ullenboom, Christian: Java ist auch eine Insel. Einführung, Ausbildung, Praxis. (16. Auflage). Bonn 2022 (Rheinwerk-Verlag) |
|
|