Begleitunterlagen

Werbung
Lukas Fässler, Barbara Scheuner, David Sichau
Programmieren mit Java
Begleitunterlagen
Zum Onlinekurs
Programmieren mit Java
Begleitunterlagen
Zum Onlinekurs
Lukas Fässler, Barbara Scheuner, David Sichau
iii
Trotz sorgfältiger Arbeit schleichen sich manchmal Fehler ein. Die Autoren sind Ihnen
für Anregungen und Hinweise per Email an [email protected] dankbar!
Dieses Material steht unter der Creative-Commons-Lizenz
Namensnennung - Nicht kommerziell - Keine Bearbeitungen 4.0 International.
Um eine Kopie dieser Lizenz zu sehen, besuchen Sie
http://creativecommons.org/licenses/by-nc-nd/4.0/deed.de
Herstellung und Verlag: BoD – Books on Demand, Norderstedt
ISBN 978-3-7412-4989-1
Bibliografische Information der Deutschen Nationalbibliothek
Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der
Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind
im Internet über http://dnb.dnb.de abrufbar.
iv
Version: 2, Datum: 07 August 2017, Hash: a9ee87a
Inhaltsverzeichnis
Wie soll dieses Buch verwendet werden?
1
0 Programme erstellen in Java
3
Theorieteil
0.1 Modulübersicht . . . . . . . . . . . . . . . . . . . . . .
0.2 Schreiben von Computerprogrammen . . . . . . . . . .
0.2.1 Computerprogramme bestehen aus Daten und
0.2.2 Programme müssen übersetzt werden . . . . .
0.3 Anweisung . . . . . . . . . . . . . . . . . . . . . . . . .
0.4 Kommentare . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . .
. . . . . . . .
Instruktionen
. . . . . . . .
. . . . . . . .
. . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1 Variablen und Datentypen
Theorieteil
1.1 Modulübersicht . . . . . . . . . . . . . . . . . . . . .
1.2 Darstellen von Zahlen und Zeichen im Computer . .
1.2.1 Binäres System . . . . . . . . . . . . . . . .
1.2.2 Darstellung von Zahlen im binären System .
1.2.3 Darstellung von Zeichen im binären System
1.3 Datentypen . . . . . . . . . . . . . . . . . . . . . . .
1.4 Variablen und Konstanten . . . . . . . . . . . . . . .
1.4.1 Deklaration . . . . . . . . . . . . . . . . . .
1.4.2 Initialisierung und Wertzuweisung . . . . . .
1.4.3 Konstanten . . . . . . . . . . . . . . . . . .
1.5 Operatoren und Ausdrücke . . . . . . . . . . . . . . .
1.5.1 Operatoren (Teil I) . . . . . . . . . . . . . .
1.5.2 Ausdrücke . . . . . . . . . . . . . . . . . . .
1.5.3 Weitere Arithmetische Operatoren . . . . .
1.6 Der Datentyp String . . . . . . . . . . . . . . . . . .
4
4
4
5
6
6
7
9
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
10
10
10
10
10
11
11
14
14
15
16
17
17
17
18
19
v
1.7
Ein- und Ausgabe von Daten . . . . . . . . . . . . . . . . . . . . . . . . .
1.7.1 Ausgabe in die Konsole . . . . . . . . . . . . . . . . . . . . . . . .
1.7.2 Eingabe über die Tastatur . . . . . . . . . . . . . . . . . . . . . .
Selbstständiger Teil
1.8 Bremsweg-Berechnung . . . . . . . . . . . . . . . . . . .
1.8.1 Einführung . . . . . . . . . . . . . . . . . . . .
1.8.2 Aufgabenstellung und Programmanforderungen
1.9 Zinseszins-Berechnung . . . . . . . . . . . . . . . . . . .
1.9.1 Einführung . . . . . . . . . . . . . . . . . . . .
1.9.2 Aufgabenstellung und Programmanforderungen
1.9.3 Erweiterung . . . . . . . . . . . . . . . . . . . .
1.10 Geldautomat . . . . . . . . . . . . . . . . . . . . . . . .
1.10.1 Einführung . . . . . . . . . . . . . . . . . . . .
1.10.2 Aufgabenstellung . . . . . . . . . . . . . . . . .
1.10.3 Zwischenschritte . . . . . . . . . . . . . . . . .
1.10.4 Erweiterungen . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2 Kontrollstrukturen und Logik
Theorieteil
2.1 Modulübersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Anweisungen und Blöcke . . . . . . . . . . . . . . . . . .
2.2 Operatoren (Teil II) . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1 Relationale Operatoren . . . . . . . . . . . . . . . . . . .
2.2.2 Logische Operatoren . . . . . . . . . . . . . . . . . . . .
2.3 Verzweigungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.1 Einseitige Verzweigung: bedingte Programmausführung .
2.3.2 Zweiseitige Verzweigung . . . . . . . . . . . . . . . . . .
2.3.3 Mehrstufige Verzweigungen . . . . . . . . . . . . . . . .
2.3.4 Fallauswahl (Switch) . . . . . . . . . . . . . . . . . . . .
2.4 Schleifen (Loops) . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.1 for-Schleife . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.2 while-Schleife . . . . . . . . . . . . . . . . . . . . . . . .
2.4.3 do-while Schleife . . . . . . . . . . . . . . . . . . . . . .
2.4.4 Geschachtelte Schleifen . . . . . . . . . . . . . . . . . . .
19
20
20
22
22
22
22
22
22
23
23
23
23
23
24
24
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
28
28
28
29
29
30
30
31
31
32
33
34
34
35
36
37
Selbstständiger Teil
2.5 Notendurchschnitt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.5.1 Aufgabenstellung . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.5.2 Programmanforderungen . . . . . . . . . . . . . . . . . . . . . . .
39
39
39
39
vi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2.6
2.7
2.8
2.5.3 Zwischenschritte . . . . . . . . . . . . . . . . . .
Zinseszins mit Schleifen . . . . . . . . . . . . . . . . . . . .
2.6.1 Einführung . . . . . . . . . . . . . . . . . . . . .
2.6.2 Aufgabenstellung und Programmanforderungen .
2.6.3 Zwischenschritte . . . . . . . . . . . . . . . . . .
Zahlen raten . . . . . . . . . . . . . . . . . . . . . . . . . .
2.7.1 Aufgabenstellung . . . . . . . . . . . . . . . . . .
2.7.2 Programmanforderungen . . . . . . . . . . . . . .
2.7.3 Zwischenschritte . . . . . . . . . . . . . . . . . .
2.7.4 Erweiterungen . . . . . . . . . . . . . . . . . . . .
Pokern . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.8.1 Einführung . . . . . . . . . . . . . . . . . . . . .
2.8.2 Ausgangssituation und Programmanforderungen
2.8.3 Zwischenschritte . . . . . . . . . . . . . . . . . .
2.8.4 Erweiterungen . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Arrays
39
40
40
40
40
41
41
41
41
42
42
42
42
44
45
47
Theorieteil
3.1 Modulübersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Eindimensionale Arrays . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.1 Arrays deklarieren . . . . . . . . . . . . . . . . . . . . . . .
3.2.2 Arrays erzeugen . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.3 Arrays initialisieren . . . . . . . . . . . . . . . . . . . . . . .
3.2.4 Auf Array-Elemente zugreifen . . . . . . . . . . . . . . . . .
3.2.5 Array-Durchlauf mit Schleifen . . . . . . . . . . . . . . . . .
3.2.6 Länge eines Arrays bestimmen . . . . . . . . . . . . . . . .
3.3 Zwei- und mehrdimensionale Arrays . . . . . . . . . . . . . . . . . . .
3.3.1 Initialisieren und Erzeugen eines zweidimensionalen Arrays
3.3.2 Werte ins zweidimensionale Array ein- und auslesen . . . . .
3.3.3 Mehrdimensionale Arrays . . . . . . . . . . . . . . . . . . .
3.4 Zeichenketten (Strings) als Arrays . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
48
48
48
49
49
50
51
51
52
52
52
53
53
53
Selbstständiger Teil
3.5 Bowling . . . . . . . . . .
3.5.1 Einführung . . .
3.5.2 Aufgabenstellung
3.5.3 Zwischenschritte
3.5.4 Erweiterungen . .
3.6 Tic Tac Toe . . . . . . . .
3.6.1 Einführung . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
55
55
55
55
56
56
56
56
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
vii
3.6.2 Aufgabenstellung . .
3.6.3 Zwischenschritte . .
3.6.4 Erweiterungen . . . .
3.7 Such- und Sortieralgorithmen
3.7.1 Einführung . . . . .
3.7.2 Suchalgorithmen . .
3.7.3 Erweiterungen . . . .
3.7.4 Sortieralgorithmen .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Methoden und Funktionen
56
57
57
58
58
58
59
59
63
Theorieteil
4.1 Modulübersicht . . . . . . . . . . . . . . . . . . . . .
4.2 Methoden . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1 Methoden ohne Rückgabewert (Prozeduren)
4.2.2 Methoden mit Rückgabewert (Funktionen) .
4.2.3 Methoden mit Parametern . . . . . . . . . .
4.3 Methoden aus der Klasse Math . . . . . . . . . . . .
4.4 Überladen von Methoden . . . . . . . . . . . . . . . .
4.5 Gültigkeitsbereiche von Variablen . . . . . . . . . . .
4.6 Rekursion . . . . . . . . . . . . . . . . . . . . . . . .
4.6.1 Beispiel 1: Fakultät . . . . . . . . . . . . . .
4.6.2 Beispiel 2: Fibonacci . . . . . . . . . . . . .
4.7 Fehlerbehandlung mit Exceptions . . . . . . . . . . .
4.7.1 Werfen einer Exception . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
64
64
64
64
65
67
67
68
69
71
71
72
73
73
Selbstständiger Teil
4.8 Erweiterungen Pandemie-Simulation .
4.8.1 Einführung . . . . . . . . . .
4.8.2 Setzen der Startbedingungen
4.8.3 Erweiterungen . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
75
75
75
75
75
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Objekte
Theorieteil
5.1 Modulübersicht . . . . . . . . . . . . . . . . . . . . . . .
5.2 Klassen und Objekte . . . . . . . . . . . . . . . . . . . .
5.2.1 Klassen . . . . . . . . . . . . . . . . . . . . . .
5.2.2 Objektvariablen und Methoden . . . . . . . . .
5.2.3 Erstellen von Objekten unter Verwendung einer
viii
77
. . . .
. . . .
. . . .
. . . .
Klasse
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
78
78
78
79
79
80
Selbstständiger Teil
5.3 Hotel-Verwaltung . . . . .
5.3.1 Aufgabenstellung
5.3.2 Zwischenschritte
5.3.3 Erweiterungen . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
85
85
85
86
86
ix
Wie soll dieses Buch verwendet
werden?
Das vorliegende Buch enthält alle Begleitunterlagen zum Onlinekurs Programmiergrundlagen mit Java. Für den kostenlosen Kurs können Sie sich über folgende URL
registrieren und einschreiben:
https://et.ethz.ch
Der Kurs besteht aus folgenden 6 Modulen:
1.
2.
3.
4.
5.
6.
Programme erstellen in Java
Variablen und Datentypen
Kontrollstrukturen
Arrays
Methoden
Objekte
Jedes Modul dauert abhängig von Ihrem Vorwissen 4 bis 8 Arbeitsstunden. Die Materialien in diesem Buch und auf der Webseite begleiten Sie von der Einführung der
Begriffe und Konzepte, über deren Verwendung in einfachen Programmier-Beispielen bis
hin zur selbstständigen Anwendung der Programmier-Konzepte in kleinen ProgrammierProjekten.
Jedes Modul ist wie folgt organisiert:
1. SEE: Kurze Einführung in die wichtigsten Begriffe und Programmier-Konzepte
des Moduls.
2. TRY: Computerbasierte Einführung an einfachen Programmier-Beispielen direkt
in einer Programmierumgebung. Angeleitet werden Sie dabei von einem elektronischen Tutorial (E.Tutorial® ).
3. DO: Selbstständige Umsetzung kleiner Programmier-Projekte. Verknüpfung der
neuen Programmier-Konzepte mit den bereits bekannten.
4. EXPLAIN: Diskussion der individuellen Resultate aus Phase 3 mit Fokus auf die
neuen Konzepte aus Phase 1.
Dieses Buch enthält alle Begleitmaterialien für die Phasen 1 und 3.
Danksagung
Wir danken Dennis Komm und Jens Maue für das Korrekturlesen.
1
Programmieren mit Java Modul 0
Programme erstellen in Java
Theorieteil
Autoren:
Lukas Fässler, Barbara Scheuner
Begriffe
Programmiersprache
Bytecode
Programm
Klasse
Programmierumgebung
Kommentar
Editor
Algorithmus
Syntax
Quelltext
Semantik
Compiler
Anweisung
3
Theorieteil
0.1 Modulübersicht
Die Entwicklung des Computers ermöglicht uns, Rechenarbeit durch Maschinen erledigen zu lassen. Der Computer kann jedoch allein keine Probleme lösen, sondern ihm
muss ein Lösungsweg (eine Bearbeitungsvorschrift) gegeben werden. Dieser Lösungsweg
wird ihm in Form eines Programms mitgeteilt. Dies geschieht wiederum in einer speziellen Sprache, der Programmiersprache. Eine Bearbeitungsvorschrift zur Lösung
einer Aufgabe wird Algorithmus genannt. Hierbei fordern wir, dass ein Algorithmus
seine Arbeit immer beendet, also nicht unendlich lange braucht, wenn er ausgeführt wird
und für jede Eingabe eine sinnvolle Ausgabe generiert. Algorithmus ist somit ein recht
abstrakter Begriff. Wir können z.B. ein Kuchenrezept oder eine Wegbeschreibung als
einen Algorithmus verstehen. Wir betrachten hier hingegen nur Alogrithmen, die konkret
in einer Programmiersprache ausformuliert worden sind.
0.2 Schreiben von Computerprogrammen
Wenn zwei Menschen miteinander kommunizieren, wird dies von vielen Dingen, wie
beispielsweise Mimik und Gestik, begleitet. Auf die Frage „Wie geht es dir?“ kann
eine Antwort „Gut.“ ganz unterschiedlich interpretiert werden, abhängig davon, wie der
Antwortende dies zum Beispiel betont. Menschen besitzen einen Intellekt, der es ihnen
ermöglicht, einen Dialog zu interpretieren und in einen Kontext zu setzen. Computer
haben diese Fähigkeit nicht. Um mit einem Rechner zu kommunizieren, müssen wir uns
exakt ausdrücken. Der Computer weiss nicht, was wir eigentlich gemeint haben, sollten
wir uns falsch ausgedrückt haben. Für die ersten Computer war dies eine sehr mühselige
Aufgabe, denn die Sprache, die ein Computer versteht, ist für Menschen nicht sehr intuitiv.
Deshalb wurden sogenannte Hochsprachen entwickelt, die unserer natürlichen Sprache
näher sind. In diesem Kurs werden Sie eine solche Sprache, nämlich Java, verwenden,
um Algorithmen als Computerprogramme umzusetzen.
4
0.2.1 Computerprogramme bestehen aus Daten und Instruktionen
Ein Computerprogramm ist im Wesentlichen eine Auswahl von Daten und eine Folge
von Instruktionen, die – wenn sie ausgeführt werden – jeweils eine bestimmte Funktion
erfüllen. Eine Instruktion kann beispielsweise eine Berechnung ausführen. Zum besseren
Verständnis können Sie sich, wie oben erwähnt, ein Kochrezept vorstellen. Es enthält
als erstes die Mengenangaben der Zutaten (Daten) und danach die Reihenfolge der
Schritte (Instruktionen), die man ausführen muss, um ein bestimmtes Gericht zu kochen.
Das Grundschema eines Rezepts ist meistens dasselbe: zuerst die Zutaten, danach die
einzelnen Arbeitsschritte.
Mit einem Computerprogramm verhält es sich ähnlich. Jedes Programm folgt ebenfalls
einem Grundschema. Bei der Programmierung spricht man allerdings nicht von Schema,
sondern von der Syntax einer Programmiersprache, d.h. von den Regeln, die für
den Aufbau eines Programms befolgt werden müssen. Wie bereits erwähnt, gibt es
allerdings einen wesentlichen Unterschied zu den Schritten in einem Kochrezept. Bei den
Instruktionen müssen wir präzise sein. Vorschriften analog zu „nach eigenem Ermessen
würzen“ werden wir hier nicht finden, da der Computer sie nicht eindeutig auswerten
kann.
Folgende Zeilen zeigen ein sehr einfaches Beispiel für ein Programm in der Programmiersprache Java:
public class HalloWelt {
public static void main(String[] args) {
System.out.println("Willkommen zur Javaprogrammierung.");
}
}
Unser Programm enthält in diesem Fall
• ein Grundgerüst, bestehend aus einer Klasse mit dem Namen „HalloWelt“. Der
Name der Klasse muss zwingend mit dem Namen der Datei übereinstimmen, in der
das Programm gespeichert ist. Unser Code wird deshalb in der Datei HalloWelt.java
gespeichert. Die Klasse enthält eine Methode, die „Hauptmethode“ (main) genannt
wird.
• eine Instruktion in der Hauptmethode (System.out.println() als Anweisung).
• die Daten (hier den Text Willkommen zur Javaprogrammierung.).
Wird dieses Programm nun ausgeführt, wird folgende Zeile in die Konsole ausgegeben:
Willkommen zur Javaprogrammierung.
5
Das, was ein Programm ausführt, also seine Bedeutung, nennt man die Semantik des
Programms.
0.2.2 Programme müssen übersetzt werden
Programme in einer Programmiersprache wie Java sind für uns Menschen lesbar und
verständlich. Wie bereits erwähnt, versteht ein Computer sie aber nicht direkt, sondern
nur nach einer Umwandlung in Instruktionen für seinen Prozessor. Diese sind für uns
nicht nur schwer verständlich, sondern auch wesentlich simpler als die Anweisungen eines
Programms in einer Hochsprache wie Java. Das heisst, eine einzelne Instruktion eines
Programms führt zu einer Folge mehrerer Prozessor-Instruktionen.
Damit nun ein Computer unser Programm ausführen kann, müssen die Anweisungen des
Programms in Instruktionen des Computers übersetzt werden. Für das Übersetzen von
Programmen aus einer Programmiersprache in eine Folge von Prozessor-Instruktionen
gibt es spezielle Computerprogramme, so genannte Kompilierer (Compiler, Übersetzer).
Der Vorgang des Übersetzens wird deshalb auch kompilieren genannt.
Schreiben und Ausführen eines Java-Programms
Programme werden in Dateien gespeichert. Um diese Dateien editieren und abspeichern
zu können, brauchen wir einen Editor. Für Java gibt es eine Vielzahl von Editoren und
Entwicklungsumgebungen. Nachdem Sie ein Programm geschrieben haben, wird es als
Quellcode gespeichert. Dateien, die Java-Quellcode enthalten, haben die Erweiterung
.java. Im nächsten Schritt übersetzt der Compiler den Quellcode in ein Format namens
Bytecode, das für die Anwenderin oder den Anwender nicht lesbar ist. Dieser bekommt
die Endung .class.
0.3 Anweisung
Eine Anweisung (statement) ist die kleinste ausführbare Einheit eines Programms.
Wie in vielen anderen Programmiersprachen auch, wird eine Anweisung mit einem
Strichpunkt oder Semikolon (;) abgeschlossen.
Schreibweise:
Anweisung;
6
Beispiel:
System.out.println("Hallo Welt");
0.4 Kommentare
Kommentare sind Lesehilfen für uns Menschen. Sie dienen der Dokumentation des
Programmcodes. Es können beliebig viele Kommentare eingefügt werden. Der Compiler
liest über die Kommentare hinweg und ignoriert diese vollständig. Es muss festgelegt werden, wo ein Kommentar beginnt und wo er endet. In Java können Kommentare auf zwei
Arten geschrieben werden. Einerseits gibt es Zeilenkommentare, welche nur eine Zeile
lang sein können (also ohne Zeilenumbruch). Andererseits gibt es Blockkommentare,
welche über mehrere Zeilen gehen können und ein einleitendes sowie ein abschliessendes
Zeichen besitzen.
Schreibweise Zeilenkommentar: Im folgenden Beispiel werden die Zeilen 1 und 3 vom
Compiler ignoriert, die 2. Zeile wird hingegen übersetzt.
// Dies ist ein Kommentar und wird vom Compiler ignoriert.
System.out.println("Zeile wird vom Compiler übersetzt.");
// Dies ist ein Kommentar und wird vom Compiler ignoriert.
Schreibweise Blockkommentar:
Compiler ignoriert.
Im folgenden Beispiel werden alle drei Zeilen vom
/* Dies ist ein Kommentar und wird vom Compiler ignoriert.
Diese Zeile wird vom Compiler ebenfalls ignoriert.
Diese Zeile wird vom Compiler ebenfalls ignoriert. */
7
Programmieren mit Java Modul 1
Variablen und Datentypen
Theorieteil
Autoren:
Lukas Fässler, Barbara Scheuner, David Sichau
Begriffe
Binärsystem
Deklaration
Bit/Byte
Wertzuweisung
Datentyp
Initialisierung
ASCII-Code
Konstante
Ganzzahl (Integer)
Gleitkommazahl (Double)
Arithmetische Operatoren
Zeichenkette (String)
Bildschirm Ein- und Ausgabe
Variable
Typenkonvertierung
9
Theorieteil
1.1 Modulübersicht
Die beiden Konzepte Variablen und Datentypen sind für jede Programmierung grundlegend. Bei Variablen handelt es sich um Speicherbereiche, in denen Werte gespeichert
werden können, und der Datentyp gibt an, welche Werte erlaubt sind (z.B. nur Ganzzahlen). In einem Programm werden Daten verarbeitet, die sich in ihrer Art unterscheiden,
z.B. Zeichen, Zahlen oder logische Daten. Digitale Daten werden immer durch Ziffern
dargestellt. Daher auch der Name, digit bedeutet Ziffer.
1.2 Darstellen von Zahlen und Zeichen im Computer
Um die Darstellung von Zeichen, Zahlen und Texten im Computer zu verstehen, muss
man das binäre System verstehen.
1.2.1 Binäres System
Alle Rechner stellen Informationen im binären System dar. Dieses kennt nur zwei Ziffern,
nämlich 0 und 1 (im Gegensatz zum Dezimalsystem mit den Ziffern 0 bis 9). Eine solche
Ziffer wird als Bit bezeichnet (Abkürzung für Binary Digit, übersetzt „Binäre Ziffer“).
Ein Bit entspricht dem kleinsten speicherbaren Wert in einem Computer. Jeweils 8 Bit
werden zu einem Byte zusammengefasst. Ein Byte kann somit 28 = 256 verschiedene
Sequenzen von je 8 Bit speichern.
1.2.2 Darstellung von Zahlen im binären System
Betrachten wir die Zahl 91, die binär mit 8 Bit als 01011011 dargestellt wird (siehe
Tabelle 1.1). Wir reden deswegen in diesem Zusammenhang von der Binärdarstellung
von 91 (und nicht von der Dezimaldarstellung, die für uns lesefreundlicher ist).
Eine 8-Bit-Zahl, wie in unserem Beispiel, kann Werte zwischen 00000000 (0 im Dezimalsystem) und 11111111 (255 im Dezimalsystem) speichern. Für die Umrechnung vom
10
Bit
8
Binärwert
0
7
6
1
7
5
0
6
1
5
4
4
3
2
1
1
0
1
1
3
2
1
Wertigkeit
2 =
128
2 =
64
2 =
32
2 =
16
2 =
8
2 =
4
2 =
2
20 =
1
Dezimalwert
0
64
0
16
8
0
2
1
= 91
Tabelle 1.1: Binäre Darstellung der Dezimalzahl 91. Details siehe Text.
Binär- in den Dezimalwert multiplizieren wir für jedes Bit den Binärwert mit der Wertigkeit des Bits (0 oder 1) und summieren diese auf. Ist die Zahl, die wir darstellen wollen,
grösser, muss ein grösserer Speicherbereich als 8 Bits bereitgestellt werden.
1.2.3 Darstellung von Zeichen im binären System
Für die Darstellung von Zeichen im Computer wurde der so genannte ASCII-Code
entwickelt. ASCII steht für American Standard Code for Information Interchange, was
übersetzt so viel heisst wie Amerikanische Standardcodierung für den Datenaustausch.
Mit Hilfe des 7-Bit-ASCII-Codes können 128 verschiedene Zeichen (27 ) dargestellt werden
oder umgekehrt wird jedem Zeichen ein Bitmuster aus 7 Bit zugeordnet (siehe Tabelle
1.2). Die Zeichen entsprechen weitgehend einer Computertastatur. Der ASCII-Code
wurde später auf 8 Bit erweitert, was die Darstellung von 256 Zeichen (28 ) erlaubt.
Die ASCII-Tabelle enthält auch nicht darstellbare Zeichen (wie etwa ein Zeichen, das
einen Zeilenumbruch repräsentiert). Die wichtigsten sind in Tabelle 1.3 dargestellt.
1.3 Datentypen
Der Datentyp gibt an, welche Daten in einem Programm gespeichert werden können. Programmiersprachen besitzen vordefinierte Datentypen, die sich in der Art der
Interpretation der gespeicherten Daten und in der Grösse unterscheiden. Die meisten
Programmiersprachen unterscheiden folgende Datentypen:
• Typ für Zahlenwerte
• Typ für Zeichenwerte
• Typ für Wahrheitswerte (siehe Modul 2)
Tabelle 1.4 gibt einen Überblick über die wichtigsten Datentypen, die in vielen Programmiersprachen vorkommen.
11
0-31
31-63
64-95
Dez
Zeichen
Dez
Zeichen
Dez
Zeichen
Dez
Zeichen
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
LF
VT
FF
CR
SO
SI
DLE
DC1
DC2
DC3
DC4
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
SP
!
“
#
$
%
&
’
(
)
*
+
,
.
/
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
ˆ
_
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
‘
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
DEL
Tabelle 1.2: ASCII-Tabelle.
12
96-127
Dez
Zeichen
Bedeutung
8
BS
Backspace. Linkes Zeichen löschen
10
NL
New Line. Neue Zeile beginnen
32
SP
Space. Leerzeichen
127
DEL
Delete. Rechtes Zeichen löschen
Tabelle 1.3: Nicht darstellbare Zeichen der ASCII-Tabelle.
Typ
Beschreibung
Grösse
Wertebereich
in Bit
boolean
Wahrheitswert
1
char
Zeichen
byte
Ganzzahl
8
short
Ganzzahl
16
−320 768 . . . 320 767 (−215 . . . + 215 − 1)
int
Ganzzahl
32
−20 1470 4830 648 . . . 20 1470 4830 647 (−231 . . . + 231 − 1)
long
Ganzzahl
64
−90 2230 3720 0360 8540 7750 808 . . .
16
true oder false
Unicode-Zeichen
−128 . . . 127 (−27 . . . + 27 − 1)
90 2230 3720 0360 8540 7750 807 (−263 . . . + 263 − 1)
float
Gleitkommazahl
32
+/ − 3.40282347 × 1038
double
Gleitkommazahl
64
+/ − 1.79769313486231569 × 10308
Tabelle 1.4: Die wichtigsten Datentypen in Java.
13
1.4 Variablen und Konstanten
Variablen können wir uns als Behälter zur Aufbewahrung von Werten vorstellen. Sie
haben einen Namen, über den sie aufgerufen werden können, und speichern einen konkreten Wert. Der Wert der Variablen kann sich während der Ausführung des Programms
ändern (er kann variieren, daher der Name).
Um eine Variable in einem Programm verwenden zu können, sind folgende Operationen
notwendig:
1. Deklaration
2. Initialisierung
1.4.1 Deklaration
Bevor eine Variable in einem Programm verwendet werden kann, muss sie deklariert
werden. Das heisst, dass Sie als Programmiererin oder Programmierer einen Speicherbereich für einen bestimmten Datentyp belegen und diesem Speicherplatz einen Namen
geben. Über diesen Namen kann der Speicherbereich während des Programmablaufs
aufgerufen werden. Namen von Variablen beginnen in Java gemäss Konvention jeweils
mit einem Kleinbuchstaben, sie dürfen keine Leerzeichen enthalten und sollten möglichst
aussagekräftig sein.
Schreibweise:
Datentyp name;
Beispiel:
// Variable a vom Typ Integer.
int a;
// Variable b vom Typ Double.
double b;
// Variable c vom Typ Character.
char c;
Mehrere Variablen vom gleichen Typ können auch wie in folgendem Beispiel in einer
gemeinsamen Deklaration geschrieben werden:
// 3 Variablem vom Typ Integer.
int meineZahl1, meineZahl2, meineZahl3;
14
1.4.2 Initialisierung und Wertzuweisung
Das Speichern von Werten geschieht mit dem Zuweisungsoperator. In Java wird
hierfür ein Gleichheitszeichen (=) verwendet. Dabei wird der Wert des Ausdrucks
rechts des Zuweisungsoperators der Variablen auf der linken Seite zugewiesen. Wenn einer
Variable das erste Mal ein Wert zugewiesen wird, spricht man von ihrer Initialisierung.
Schreibweise:
variable = wert;
Beispiel:
meineZahl = 4;
// meineZahl hat den Wert 4.
Wie erwähnt kann sich der Wert einer Variablen während der Ausführung eines Programms ändern. In folgendem Beispiel wird in der Variablen meineZahl zuerst der
Wert 4 gespeichert, der dann in einer weiteren Zeile mit dem Wert 6 überschrieben wird:
meineZahl = 4;
// Wert von meineZahl ist 4.
meineZahl = 6;
// Wert von meineZahl ist 6.
Bei einer Zuweisung handelt es sich also immer um einen schreibenden Zugriff auf
eine Variable mit dem Resultat, dass sich deren Wert ändern kann. Der alte Wert wird
überschrieben. Damit einer Variablen ein Wert zugewiesen werden kann, darf die Variable
nicht als Konstante definiert sein (siehe nächster Abschnitt) und der Typ der Variablen
muss mit dem Typ des Werts kompatibel sein. Auf jeden Fall kompatibel sind Variablen
und Werte desselben Datentypes. Wenn die Datentypen nicht übereinstimmen, nimmt
Java eine implizite Typkonvertierung vor. Dies ist jedoch eine häufige Fehlerquelle und
sollte daher vermieden werden. Bei der impliziten Typkonvertierung in Java werden nur
dann eine Typkonvertierung durchgeführt, wenn sie ohne Informationsverlust erfolgen
kann, also wenn der Zieldatentyp einen gleichen oder grösseren Wertebereich hat als der
Ausgangsdatentyp.
15
Beispiel:
// Variable ganzeZahl vom Typ Integer.
int ganzeZahl;
// Variable kommaZahl vom Typ Double.
double kommaZahl;
ganzeZahl = 4;
kommaZahl = ganzeZahl;
// Variable kommaZahl wird zum Typ Integer konvertiert.
Ein Wert vom Typ int kann einer Variablen vom Typ double zugewiesen werden:
Möchte man eine Zuweisung machen, bei der der Zieldatentyp einen kleineren Wertebereich hat, muss eine explizite Typenkonvertierung durchgeführt werden, das sogenannte
Typecasting. Die Programmiererin/der Programmierer ist dabei selber dafür verantwortlich, dass die Zuweisung möglich ist.
Beispiel:
// Variable d vom Typ Double.
double d = 1.3;
float f = (float)d;
// Variable d muss explizit zum Typ Float konvertiert werden.
Eine Variable kann in einem Programm nur in einem bestimmten Bereich des Programms
gelten. Weiteres dazu erfahren Sie in einem späteren Modul.
1.4.3 Konstanten
Konstanten werden wie Variablen mit einem Namen bezeichnet. Sie enthalten während
der gesamten Programmausführung einen konstanten Wert. Es kann also nach der
Initialisierung keine weitere Wertzuweisung vorgenommen werden. Konstanten können
jedoch Teil einer Wertzuweisung an Variablen sein. Eine Konstante wird zusätzlich zu
Namen und Datentyp mit dem Schlüsselwort final deklariert.
Schreibweise:
final Datentyp name;
16
Beispiel:
// Deklaration und Initialisierung der Konstante k.
final int k = 4;
1.5 Operatoren und Ausdrücke
1.5.1 Operatoren (Teil I)
Um in einem Programm Berechnungen durchzuführen zu können, stehen diverse arithmetische Operatoren zur Verfügung, die in Tabelle 1.5 gezeigt sind.
Operator
Ausdruck
Beschreibung
Liefert
+
a+b
Addition
Summe
-
a-b
Subtraktion
Differenz
∗
a∗b
Multiplikation
Produkt
/
a/b
Division
Quotient
%
a%b
Modulo
Ganzzahliger Rest einer Division
Tabelle 1.5: Arithmetische Operatoren in Java.
Weitere Operatoren (logische und Vergleichsoperatoren) lernen Sie in Modul 2 kennen.
1.5.2 Ausdrücke
Ausdrücke (expressions) sind in einer Programmiersprache Teil der kleinsten ausführbaren Einheiten eines Programms. Dabei handelt es sich um Verarbeitungsvorschriften,
die sich aus Variablen, Konstanten und Operatoren zusammensetzen können und
ein Resultat ergeben. Variablen und Konstanten, die mit einem Operator verknüpft werden, nennt man Operanden. Ein Ausdruck kann auch aus einer einzelnen Variablen
bestehen.
Folgendes Beispiel zeigt einen Ausdruck, der aus einer Variablen i, einem Operator +
und einer Konstanten 5 besteht. Somit sind i und 5 Operanden.
i + 5
17
Das Resultat des Ausdrucks kann wieder in einer Variablen gespeichert werden. In
folgendem Beispiel nutzen wir hierzu die Variable i. Der vorherige Wert von i wird
dadurch überschrieben.
i = i + 5;
Die Reihenfolge, in der Ausdrücke bearbeitet werden, kann durch die Wahl des Operators
und durch Klammern beeinflusst werden. Hierfür gelten die mathematischen Regeln, wie
wir sie in der Schule gelernt haben, also „Klammern zuerst, dann Punkt vor Strich“.
Beispiel:
5 * (2 + 10)
Die Klammern erzwingen, dass die Addition vor der Multiplikation ausgeführt wird.
1.5.3 Weitere Arithmetische Operatoren
Es gibt in Java noch weitere arithmetische Operatoren.
Zuweisungsoperator:
i
i
i
i
i
+=
-=
*=
/=
%=
1;
1;
1;
1;
1;
//
//
//
//
//
entspricht
entspricht
entspricht
entspricht
entspricht
i
i
i
i
i
=
=
=
=
=
i
i
i
i
i
+
*
/
%
1;
1;
1;
1;
1;
Die Zuweisungsoperatoren dienen dazu die Anweisungen kompakter darzustellen, da
man weniger Zeichen benötigt.
Increment und Decrement Operatoren:
i++; // entspricht i = i + 1;
i--; // entspricht i = i - 1;
Diese Operatoren sind meistens in sogenannten for-Schleifen anzutreffen, wo sie einen
Zähler hochzählen (siehe Modul 2) .
18
1.6 Der Datentyp String
Der Datentyp String unterscheidet sich von den bisher thematisierten Datentypen insofern, dass er eine Zusammenfassung von mehreren gleichartigen Variablen darstellt.
Dieser Datentyp ist auch kein primitiver Datentyp mehr, da er mehrere Elemente zusammenfasst. Er speichert nämlich alle Buchstaben einzeln in je einer char-Variablen.
Wie diese Zusammenfassung der einzelnen Buchstaben funktioniert, lernen Sie, wenn
es um die Objektorientierung geht. Die Deklaration und Initialisierung der Variablen
funktioniert jedoch wie in 1.4.1 und 1.4.2 beschreiben.
Bei der Initialisierung von String-Variablen muss der Wert zwischen Anführungszeichen (") angegeben werden.
Beispiel:
// Deklaration des Strings vorname.
String vorname;
// Initialisierung mit dem Wert "Paul".
vorname = "Paul";
Da ein String mehrere char-Variablen enthält, kann dem String auch ein einzelner char
zugewiesen werden.
Beispiel:
String name;
name = "a";
Mehrere Strings können mit einem Plus-Operator (+) verbunden werden. So entsteht
aus mehreren Einzelteilen ein neuer Text.
Beispiel:
String text;
text = "Hallo, " + "das " + "sind " + "mehrere " + "Wörter.";
1.7 Ein- und Ausgabe von Daten
Oft möchte man, dass die Benutzerin oder der Benutzer des Programms mit diesem interagieren kann. Das bedeutet, dass die Benutzerin oder der Benutzer etwas eingeben kann
19
(zum Beispiel über die Tastatur) oder das Programm eine Ausgabe macht (zum Beispiel
das Resultat einer Berechnung oder einen Text). Um dies zu realisieren verwenden wir
Funktionalitäten, welche von Java zur Verfügung gestellt werden.
1.7.1 Ausgabe in die Konsole
Damit die Benutzerin oder der Benutzer sieht, was im Programm berechnet wurde, kann
im Programmcode angegeben werden, dass ein bestimmter Text oder der Wert einer
Variablen ausgegeben wird.
Beispiel: Ausgabe eines vorgegebenen Texts
System.out.println("Das Programm hat geendet.");
Im obigen Beispiel wird der Text „Das Programm hat geendet.” in der Konsole ausgegeben. Der Text, der ausgegeben wird, steht zwischen einem Paar von Anführungs- und
Schlusszeichen, die nicht mit ausgegeben werden. Man möchte aber nicht immer nur
vorgegebenen Text ausgeben, sondern z.B. das Resultat einer Berechnung, das in einer
Variablen (z.B. ganzeZahl) gespeichert ist.
Beispiel: Ausgabe des Wertes einer Variablen
System.out.println(ganzeZahl);
Diese Anweisung gibt den Wert der Variablen ganzeZahl in der Konsole aus.
Variablenwerte und Text können in Java mit einem Plus-Zeichen (+) verbunden werden.
Beispiel: Ausgabe von Text und Variablenwert
System.out.println("Es wurde " + ganzeZahl + " berechnet.");
1.7.2 Eingabe über die Tastatur
Oft möchte man den Wert einer Variablen durch die Benutzerin oder den Benutzer eines
Programms bestimmen lassen. Eine häufige Form der Eingabe ist über die Tastatur
der Benutzerin oder des Benutzers. Der Programmablauf wird solange gestoppt, wie die
Benutzerin oder der Benutzer über die Tastatur eine Eingabe macht, welche mit der
Return-Taste beendet wird.
Eine Benutzereingabe ist in Java etwas aufwändiger als bei anderen Programmiersprachen. Sie beinhaltet folgende zwei Schritte:
20
• Schritt 1: Paket einbinden
• Schritt 2: Werte einlesen
Schritt 1: Paket einbinden Mit folgender Importanweisung zu Beginn unseres JavaProgramms muss zunächst die Klasse Scanner des Pakets util eingebunden werden:
import java.util.Scanner;
Schritt 2: Werte einlesen Mit folgenden zwei Zeilen können wir Werte in Form von
Zeichenketten (String) vom Konsolenfenster einlesen und einer Variablen (z.B. wert)
zuweisen:
Scanner eingabe = new Scanner(System.in);
String wert = eingabe.next();
Nun weisen wir den eingelesenen Wert unserer Variablen wert zu. Hierfür muss der
eingelesene Text noch in einen Integer umgewandelt werden:
Integer.parseInt(wert);
Beispiel: Mit den folgenden Anweisungen übergeben wir eine Eingabezahl von der
Konsole an die Variable x vom Typ Integer:
int x;
Scanner eingabe = new Scanner(System.in);
String wert = eingabe.next();
x = Integer.parseInt(wert);
Einlesen von Datentypen
Für das Einlesen der Standard-Datentypen (siehe Tabelle 1.4) bietet Scanner auch Möglichkeiten, diese direkt einzulesen.
Beispiel:
int ganzeZahl;
double kommaZahl;
ganzeZahl= eingabe.nextInt();
kommaZahl= eingabe.nextDouble();
21
Selbstständiger Teil
1.8 Bremsweg-Berechnung
1.8.1 Einführung
Der Anhalteweg ist die Strecke, die ein Fahrzeug vom Zeitpunkt des Auftretens eines Hindernisses bis zum Stillstand zurücklegt. Der Anhalteweg setzt sich aus dem Reaktionsweg
und dem Bremsweg zusammen:
Anhalteweg = Reaktionsweg + Bremsweg
Reaktionsweg und Bremsweg lassen sich vereinfacht mit folgenden Formeln berechnen
(Reaktionsweg und Bremsweg in Metern; Geschwindigkeit in km/h):
Reaktionsweg = 3 ·
Bremsweg =
Geschwindigkeit
10
Geschwindigkeit Geschwindigkeit
·
10
10
1.8.2 Aufgabenstellung und Programmanforderungen
Schreiben Sie ein Java-Programm, welches den Reaktionsweg, den Bremsweg und den
Anhalteweg (in Metern) für eine eingegebene Geschwindigkeit berechnet und auf dem
Bildschirm ausgibt.
1.9 Zinseszins-Berechnung
1.9.1 Einführung
Wir möchten berechnen, wie viel Geld wir auf dem Konto haben, wenn wir 2000 Franken
bei 2% für 10 Jahre anlegen.
22
1.9.2 Aufgabenstellung und Programmanforderungen
Schreiben Sie ein Java-Programm, welches für jedes Jahr angibt, wie viel Zins hinzugekommen ist, und wie hoch der Betrag nach der Zinsgutschrift auf dem Konto ist.
Die Ausgabe soll für jedes Jahr so aussehen:
Im x. Jahr gibt es xx Fr. Zins. Neuer Kontostand: xxx Fr.
1.9.3 Erweiterung
Die Benutzerin oder der Benutzer soll als Parameter eingeben können, wie viel Geld sie
oder er zu wie viel Prozent angelegen möchte.
1.10 Geldautomat
1.10.1 Einführung
Bei dieser Aufgabe geht es um das Speichern und Überschreiben von Werten in Variablen.
Zudem kommen zwei verschiedene Divisions-Operatoren zum Einsatz.
1.10.2 Aufgabenstellung
In dieser Aufgabe sollen Sie einen Geldautomaten simulieren. Der Kunde soll eingeben können, wie viel Geld er oder sie abheben möchte. Der Geldautomat soll dann
berechnen, wie viele und welche Banknoten (100er, 50er, 20er und 10er) er ausgeben soll.
Die Anzahl der verwendeten Variablen soll möglichst klein gehalten werden, indem sie
wiederverwendet werden.
So könnte beispielsweise die Ausgabe für den Betrag 571 aussehen:
Wie viel möchten Sie abheben? 571
Eingegebener Geldbetrag: 571 Fr.
100er 5
50er 1
20er 1
10er 0
Rest: 1
23
1.10.3 Zwischenschritte
• Erstellen Sie eine Benutzereingabe für einen beliebigen Geldbetrag und speichern
Sie den Wert in einer Variablen.
• Definieren Sie für jede Art von Banknoten (100er, 50er, 20er, 10er) je eine
Variable.
• Berechnen Sie zuerst, wie viele 100er-Noten herausgegeben werden sollen und
geben Sie den Wert auf dem Bildschirm aus.
Ganzzahliger Wert einer Division
Mit a/100 erhalten Sie den ganzzahligen Wert der Division von a durch
100. Beispiel: 571/100 = 5.
• Berechnen Sie den Restwert.
Ganzzzahliger Rest einer Division
Mit a%100 erhalten Sie den Rest einer Division von a und 100. Beispiel:
571%100 = 71
• Berechnen Sie analog zu den 100er-Noten Schritt für Schritt die Anzahlen aller
anderen Banknoten.
Tipp: Kopieren Sie den Anweisungsblock für die 100er-Noten und ändern Sie
ihn für die anderen Noten ab.
1.10.4 Erweiterungen
Für diese Erweiterungen benötigen Sie Bedingungsprüfungen, die erst im
nächsten Modul ausführlich behandelt werden.
Bedingte Programmausführung
Syntax: Die Anweisungen werden nur ausgeführt, wenn die Bedingung zutrifft:
if (Bedingung) {
Anweisungen
}
24
• Überprüfen Sie nach der Eingabe des Geldbetrags, ob abgerundet werden muss
und informieren Sie den Kunden über den tatsächlich ausbezahlten Betrag.
• Lassen Sie nur die Banknotenarten anzeigen, die tatsächlich ausgegeben werden.
• Nehmen Sie an, dass nur ein bestimmter Maximalbetrag abgehoben werden kann.
Prüfen Sie deshalb, ob die gewünschte Summe des Kunden dieses Limit nicht
überschreitet, und informieren Sie ihn darüber, falls dies der Fall sein sollte.
• Es kann sein, dass der Kunde gerne etwas kleinere Noten haben möchte. Fragen
Sie ihn deshalb danach (Anwort z.B. mit 0=nein, 1=ja), ob er gemischte Noten
wünscht. Überlegen Sie sich zuerst, wie Sie die Noten zusammenstellen wollen.
Ändern Sie danach das Programm entsprechend.
25
Programmieren mit Java Modul 2
Kontrollstrukturen und Logik
Theorieteil
Autoren:
Lukas Fässler, Barbara Scheuner, David Sichau
Begriffe
Anweisungsblock
Verzweigung
Anweisungskopf
for-Schleife
Anweisungskörper
while-Schleife
logische Operatoren
Wahrheitswert
do-while-Schleife
relationale Operatoren
geschachtelte Schleife
27
Theorieteil
2.1 Modulübersicht
Ein Algorithmus, der als Programm formuliert ist, besteht in der Regel aus mehreren
Anweisungen. Diese Anweisungen werden in einer von der Programmiererin oder dem
Programmierer festgelegten Reihenfolge abgearbeitet. Diese Abfolge verläuft selten linear. Oft kommt es vor, dass sich eine Programmsequenz (Folge von Anweisungen) in
zwei oder mehrere Programmsequenzen verzweigt, wobei jede nur unter bestimmten
Bedingungen ausgeführt wird (Verzweigung). Um einen Algorithmus zu vereinfachen,
werden oft bestimmte Programmsequenzen wiederholt ausgeführt (Schleifen). Mit Hilfe
von Kontrollstrukturen, die in den meisten Programmiersprachen vorkommen, kann
der Programmablauf beeinflusst werden. Die Entscheidung, wie der Ablauf gesteuert
wird, muss in Bedingungen formuliert werden.
2.1.1 Anweisungen und Blöcke
Wie bereits in Modul 0 erwähnt, werden einzelne Anweisungen durch ein Semikolon
abgeschlossen. Mehrere Anweisungen können in einem Anweisungsblock zusammengefasst werden. In Java werden zur Markierung von Anweisungsblöcken geschweifte
Klammern {} verwendet.
{ \\öffnet den Block
anweisung1;
anweisung2;
...
} \\schliesst den Block
Die Ausführung von Blöcken kann durch Kontrollstrukturen (z.B. Verzweigungen oder
Schleifen) gesteuert werden. Diese Kontrollstrukturen bestehen aus einem Kopf (head)
und Körper (body).
28
\\Kopf (head)
{
\\Körper (body)
}
Bei folgendem Programm wird der Anweisungsblock 1 durch einen Anweisungsblock 2
unterbrochen:
\\Beginn Anweisungsblock 1
Kopf 1 {
\\Körper 1
\\Beginn Anweisungsblock 2
Kopf 2 {
\\Körper 2
} \\Ende Anweisungsblock 2
\\Fortsetzung Körper 1
} \\Ende Anweisungsblock 1
2.2 Operatoren (Teil II)
Die arithmetischen Operatoren sind bereits in Modul 1 beschrieben worden. Im Zusammenhang mit Kontrollstrukturen kommen logische und relationale Operatoren
zum Einsatz.
2.2.1 Relationale Operatoren
Relationale Operatoren werden gebraucht, um Werte (Operanden) miteinander zu
vergleichen. Sie liefern ein logisches Ergebnis wahr (true) oder falsch (false). Werte,
die mit relationalen Operatoren verknüpft sind, nennt man in der Aussagenlogik auch
Elementaraussagen.
Die relationalen Operatoren in Java sind in Tabelle 2.1 zusammengefasst.
29
Operator
Ausdruck
Beschreibung
Liefert wahr (true), wenn...
>
a>b
grösser als
a grösser ist als b.
<
a<b
kleiner als
a kleiner ist als b.
==
a == b
gleich
a und b denselben Wert haben.
!=
a != b
ungleich
a und b ungleiche Werte haben.
>=
a >= b
grösser oder gleich
a grösser oder gleich b ist.
<=
a <= b
kleiner oder gleich
a kleiner oder gleich b ist.
Tabelle 2.1: Relationale Operatoren in Java.
2.2.2 Logische Operatoren
Logische Operatoren verknüpfen Elementaraussagen miteinander. Dabei werden Wahrheitswerte miteinander verglichen. Das Ergebnis ist ebenfalls ein Wahrheitswert, also
wahr (true) oder falsch (false). Da dies die Operanden und Operatoren der Boolschen
Aussagenlogik sind, heisst der Datentyp Boolean. Die in Java verwendeten logischen
Operatoren sind in Tabelle 2.2 dargestellt.
Operator
Ausdruck
Liefert wahr (true), wenn...
!
!a
a falsch ist (NOT).
&&
a && b
sowohl a als auch b wahr sind (AND).
Ist a falsch, wird b nicht ausgewertet.
k
akb
mindestens a oder b wahr sind (OR).
Ist a wahr, wird b nicht mehr ausgewertet.
ˆ
aˆb
a und b unterschiedliche Wahrheitswerte haben
Tabelle 2.2: Logische Operatoren in Java.
2.3 Verzweigungen
Verzweigungen überprüfen einen Zustand des Programms. Je nachdem, ob eine bestimmte Bedingung erfüllt ist oder nicht, fährt das Programm mit unterschiedlichen
Blöcken von Anweisungen fort. Verzweigungen werden in Java, so wie in vielen anderen
30
Programmiersprachen auch, mit dem Schlüsselwort if eingeleitet. Die Bedeutung des
if ist analog zur englischen Sprache.
If it is raining, then I will take the bus, otherwise I will walk.
Dies könnte in Java wie folgt geschrieben werden:
if (rain) {bus} else {walk};
Falls die Bedingung rain wahr (true) ist, wird der Block mit der Anweisung bus
ausgeführt, andernfalls wird der Block mit der Anweisung walk ausgeführt.
Allgemein kann mit einer if-Anweisung zur Laufzeit entschieden werden, ob eine Anweisung oder ein Anweisungsblock ausgeführt werden soll oder nicht. Um Bedingungen zu
formulieren, können sowohl Boolsche Variablen, Relationen wie Gleichheit, grösser oder
kleiner als auch logische Operatoren verwendet werden.
Je nachdem wie viele Fälle zu unterscheiden sind, ist eine einseitige (2.3.1), zweiseitige
(2.3.2) oder mehrstufige Verzeigung (2.3.3) zu wählen.
2.3.1 Einseitige Verzweigung: bedingte Programmausführung
Eine einseitige Verzweigung besteht aus einer Bedingungsabfrage und einem Anweisungsblock, welcher ausgeführt wird oder nicht.
Schreibweise:
if (Bedingung) {
Anweisungsblock;
}
Beispiel:
if (rain == true) {
System.out.println("Es regnet.");
}
Der Satz "Es regnet." wird nur ausgegeben, wenn die Variable rain den Wert true
hat.
2.3.2 Zweiseitige Verzweigung
Bei einer zweiseitigen Verzeigung kann zusätzlich angegeben werden, was im anderen
Fall (else), wenn also die Bedingung nicht zutrifft, ausgeführt werden soll.
31
Schreibweise:
if (Bedingung) {
Anweisungsblock1;
}
else {
Anweisungsblock2;
}
Beispiel:
if (rain == true) {
System.out.println("Es regnet.");
}
else {
System.out.println("Es regnet nicht.");
}
Hat die Variable rain den Wert true, wird der Satz "Es regnet." ausgegeben, im
anderen Fall (false) wird der Satz "Es regnet nicht." ausgegeben.
2.3.3 Mehrstufige Verzweigungen
Mit einer mehrstufigen Verzweigung können mehrere Vergleiche gemacht werden.
Das kann nötig sein, wenn Sie unterschiedliche Möglichkeiten in einer bestimmten Reihenfolge prüfen möchten.
Schreibweise:
if (Bedingung1) {
Anweisungsblock1;
}
else if (Bedingung2) {
Anweisungsblock2;
}
else if (Bedingung3) {
Anweisungsblock3;
}
...
32
Beispiel:
if (rain == true) {
System.out.println("Es regnet.");
}
else if (snow == true) {
System.out.println("Es schneit.");
}
else if (sun == true) {
System.out.println("Es scheint die Sonne.");
}
else {
System.out.println("Die Wetterlage ist unklar.");
}
Hat die Variable rain den Wert true, wird wieder der Satz "Es regnet." ausgegeben.
Hat sie hingegen den Wert false, wird als nächstes die Variable snow geprüft. Hat
snow den Wert true, wird der Satz "Es schneit." ausgegeben. Hat snow den Wert
false, wird als nächstes die Variable sun geprüft. Hat sun den Wert true, wird der
Satz "Es scheint die Sonne." ausgegeben. Hat sun auch den Wert false, wird
der Satz "Die Wetterlage ist unklar." ausgegeben.
2.3.4 Fallauswahl (Switch)
Eine andere Möglichkeit, während des Programmablaufs zwischen unterschiedlichen
Möglichkeiten auszuwählen, ist die switch-Anweisung. Dabei wird der Wert einer
Variablen mit unterschiedlichen Werten verglichen.
Schreibweise:
switch (ausdruck){
case constant:
Anweisungsblock;
default:
Anweisungsblock;
}
Im Gegensatz zur if-Verzweigung kann mit dem switch-Statement nur auf Gleichheit
geprüft werden. Vergleiche auf grösser oder kleiner sind nicht möglich. Als Ausdruck im
switch-Statement sind alle ganzzahligen Datentypen und, seit Java 7, auch String-Typen
zugelassen. Zusätzlich werden bei einem switch-Statement alle Anweisungen ab dem
33
Einstiegspunkt abgearbeitet. Ist dies nicht erwünscht, sollte der Anweisungsblock mit
einem break abgeschlossen werden.
Beispiel:
switch (test)
{
case 1:
System.out.println("Ich wurde ausgewählt.");
break;
case 2:
System.out.println("Du wurdest ausgewählt.");
break;
case 3:
System.out.println("Wir wurden ausgewählt.");
break;
default:
System.out.println("Keiner wurde ausgewählt.");
}
2.4 Schleifen (Loops)
Mit Hilfe von Schleifen (loops) können dieselben Anweisungen wiederholt ausgeführt
werden. Wie in anderen Programmiersprachen gibt es auch in Java verschiedene Schleifenarten. Eine Schleife besteht aus einem Schleifenkopf und einem Schleifenkörper.
Der Schleifenkörper enthält den zu wiederholenden Anweisungsblock. Der Schleifenkopf
steuert die Schleife. Er gibt an, wie oft oder unter welchen Bedingungen die Anweisungen
des Schleifenkörpers wiederholt werden sollen.
2.4.1 for-Schleife
Bei der zählergesteuerten for-Schleife wird die Anzahl der Schleifendurchläufe durch
eine Laufvariable von einem Startwert- bis zu einem Endwert durchgezählt. Bei jedem
Schleifendurchgang wird der Zähler verändert.
34
Schreibweise:
for (init; test; update){
Anweisungsblock
}
• Initialisierung (init): Deklarieren der Laufvariable und setzen des Startwerts.
• Logischer Ausdruck (test): Es wird bei jedem Durchlaufen geprüft, ob die
Schleife weiterlaufen muss oder der Endwert schon erreicht worden ist.
• Aktualisierung (update): Die Laufvariable wird nach jedem Durchlaufen der
Schleife verändert.
Beispiel:
Folgende Anweisung gibt die Werte 0 bis 4 am Bildschirm aus:
for (int i=0; i<5; i++){
System.out.println(i);
}
Zunächst wird die Laufvariable i deklariert (Datentyp Integer) und auf den Anfangswert
0 gesetzt. Danach wird geprüft, ob i kleiner ist als 5. Ist dies der Fall, werden die
Anweisungen des Schleifenkörpers durchlaufen und dann der Wert von i um 1 erhöht.
2.4.2 while-Schleife
Es ist nicht immer vorhersehbar, wie oft Anweisungen wiederholt werden müssen, da die
Anzahl der Wiederholungen von dem abhängen kann, was im Schleifenkörper passiert.
Hier geraten wir bei zählergesteuerten Schleifen an eine Grenze. Bei bedingungsabhängigen Schleifen wird die Anzahl der Wiederholungen nicht von einem Zähler, sondern
von einer Bedingung abhängig gemacht. Diese Bedingung wird bei jedem Schleifendurchgang überprüft. While- und do-while-Schleifen unterscheiden sich dadurch, ob
diese Bedingung vor oder nach dem Anweisungsblock überprüft wird.
Schreibweise:
Initialisierung der Variablen
while (Bedingung){
Anweisungsblock
Aktualisierung
}
• Initialisierung: Deklarieren einer oder mehrerer Variablen und initialisieren der
Startwerte.
35
• Bedingung: Die Bedingung wird geprüft, sobald die while-Schleife erreicht wird.
Ist die Bedingung wahr (true), wird der Schleifenkörper ausgeführt. Ist die Bedingung falsch (false), wird die Schleife abgebrochen und die Anweisungen des
Schleifenkörpers werden nicht mehr ausgeführt. Nach jedem Durchlaufen der Schleife wird die Bedingung erneut geprüft.
• Aktualisierung: Innerhalb des Schleifenkörpers müssen sich Werte so verändern,
dass die Bedingung irgendwann erreicht wird, sonst droht eine Endlosschleife, was
der Definition eines Algorithmus widerspricht (ein Algorithmus muss seine Arbeit
immer beenden).
Beispiel:
Folgende Anweisung gibt die Werte 0 bis 4 am Bildschirm aus:
int i=0;
while (i<5){
System.out.println(i);
i++;
}
Zunächst wird eine Variable i initialisiert und auf 0 gesetzt. Zu Beginn der Schleife
wird geprüft, ob i kleiner ist als 5. Ist dies der Fall (true), wird der Schleifenkörper
ausgeführt. Ist dies nicht der Fall (false), wird die Schleife abgebrochen. Die Variable
i wird innerhalb des Schleifenkörpers jedes Mal um 1 erhöht.
2.4.3 do-while Schleife
Der Schleifenkörper einer do-while-Schleife wird im Gegensatz zur while-Schleife mindestens einmal ausgeführt, da die Bedingungsprüfung zur Wiederholung jeweils am Ende
des Schleifenkopfs erfolgt.
Schreibweise:
Initialisierung der Variablen
do {
Anweisungsblock
Aktualisierung
} while (Bedingung);
• Initialisierung: Deklarieren einer Variable und setzen des Startwerts.
• Aktualisierung: Innerhalb des Schleifenkörpers müssen sich Werte so verändern,
dass die Bedingung irgendwann erreicht wird, sonst droht eine Endlosschleife.
36
• Bedingung: Die Bedingungsprüfung findet erst statt, nachdem der Schleifenkörper
durchlaufen ist. Sie enthält die Bedingung zum Wiederholen der Schleife. Trifft diese
Bedingung zu, wird die Schleife erneut durchlaufen, sonst wird sie abgebrochen.
Beispiel:
Folgende Anweisung gibt die Werte 0 bis 4 am Bildschirm aus:
int i=0;
do {
System.out.println(i);
i++;
} while (i<5);
Es wird eine Variable i initialisiert und auf 0 gesetzt. Im Schleifenkörper wird die
Variable i um 1 erhöht. Erst jetzt wird geprüft, ob i kleiner ist als 5. Sobald i den Wert
5 erreicht, wird die Schleife abgebrochen.
2.4.4 Geschachtelte Schleifen
Beim Programmieren kommt es oft vor, dass zwei Schleifen ineinander geschachtelt
werden (nested loops). Das hat zur Folge, dass eine äussere Schleife eine innere steuert.
Dies kann wie folgt dargestellt werden:
Äussere Schleife {
Innere Schleife {
Anweisungsblock
}
}
Eine Analogie zu den geschachtelten Schleifen findet man bei unserer Erde, die sich
um die Sonne dreht. Eine Umkreisung in einem Jahr wäre mit der äusseren Schleife
vergleichbar, und eine Drehung der Erde um die eigene Achse innerhalb eines Tages wäre
mit der inneren Schleife vergleichbar.
In Java könnte ein Programm zur Anzeige von Tagen und Stunden eines Jahres (das
kein Schaltjahr ist) mit folgender geschachtelten Schleife geschrieben werden:
37
for (int tage=0; tage<365; tage++){
for (int stunden=0; stunden<24; stunden++) {
System.out.println("Tag " + tage);
System.out.println("Stunde " + stunden);
}
}
Die ersten drei Ausgaben lauten:
Tag 0: Stunde 0
Tag 0: Stunde 1
Tag 0: Stunde 2
Die letzten drei Ausgaben lauten:
Tag 364: Stunde 21
Tag 364: Stunde 22
Tag 364: Stunde 23
38
Selbstständiger Teil
2.5 Notendurchschnitt
2.5.1 Aufgabenstellung
Ein Programm soll beliebig viele Noten einlesen können und daraus den Notendurchschnitt berechnen.
2.5.2 Programmanforderungen
Schreiben Sie ein Programm, bei dem der User beliebig viele Noten eingeben kann. Er
oder sie soll Noten eingeben können, bis ein bestimmter Wert (z.B. 0) eingegeben wird.
In diesem Fall endet die Noteneingabe und es wird der Durchschnitt der eingegebenen
Noten berechnet.
So könnte die Ausgabe Ihres Programms aussehen:
Bitte geben Sie ihre Noten ein (0 für Eingabe beenden):
1. Note: 3
2. Note: 4.5
3. Note: 5
4. Note: 6
5. Note: 0
Sie haben 4 Noten eingegeben. Schnitt = 4.625
2.5.3 Zwischenschritte
• Schreiben Sie die Noteneingabe für eine Note und speichern Sie den eingegeben
Wert in einer Variablen (Datentyp beachten!).
• Konstruieren Sie eine Schleife zur Eingabe beliebig vieler Noten. Folgende Fragen
müssen geklärt werden:
– Schleifenkopf: Wie wird die Schleife abgebrochen?
– Schleifenkörper: Welche Anweisungen werden wiederholt?
39
Tipp: Eine Möglichkeit besteht darin, so lange nach Noten zu fragen, wie ein
definierter Wert (z.B. 0 oder 9) nicht eingegeben wird.
• Führen Sie weitere Variablen für die Berechnung des Durchschnitts (nächster
Schritt) ein:
– Zähler: Zählt die Anzahl eingegebener Noten.
– Summe: Enthält die Summe aller eingegebenen Noten.
– Durchschnitt: Speichert den Notendurchschnitt (Summe/Zähler).
Tipp: Es empfiehlt sich zu Testzwecken, die Variablenwerte bei jedem Schleifendurchgang anzuzeigen. So werden Sie allfällige Berechnungsfehler schneller
erkennen und beheben können.
• Berechnen Sie den Durchschnitt und geben Sie das Resultat am Bildschirm aus.
2.6 Zinseszins mit Schleifen
2.6.1 Einführung
Im vorangegangenen Modul haben Sie eine Aufgabe zur Zinseszins-Berechung gelöst.
Das Schleifen-Konzept erlaubt uns nun eine elegantere Lösung dieses Problems.
2.6.2 Aufgabenstellung und Programmanforderungen
Setzen Sie eine Schleife ein, um die gleiche Aufgabenstellung mit einem kürzeren Programm zu lösen. Gestalten Sie das Programm ausserdem flexibler, indem der Nutzer
zusätzlich die Anzahl der Anlagejahre als Parameter eingeben kann.
2.6.3 Zwischenschritte
• Implementieren Sie das Programm neu unter Anwendung einer for-Schleife, die
über die vorgegebenen 10 Jahre iteriert.
• Lassen Sie den Benutzer zu Beginn die Anzahl Jahre über die Konsole eingeben.
Das Programm soll nun für die angegebene Anzahl Jahre die Zinseszins-Berechnung
durchführen.
40
2.7 Zahlen raten
2.7.1 Aufgabenstellung
Bei dieser Aufgabe ist ein Spiel umzusetzen, bei dem sich der eine Spieler/die eine
Spielerin eine Zahl ausdenkt und der/die andere diese Zahl erraten muss.
2.7.2 Programmanforderungen
Eine Spielerin oder ein Spieler soll wiederholt raten, bis er oder sie eine festgelegte Zahl
erraten hat. Bei jedem Rate-Versuch soll angegeben werden, ob die gesuchte Zahl grösser
oder kleiner ist als die eingegebene Zahl. Zählen sie dabei auch die Anzahl der Versuche
mit und geben Sie diese am Ende des Spiels bekannt.
So könnte Ihre Ausgabe aussehen (zu erratende Zahl: 52):
Gesucht ist eine Zahl zwischen 1 und 100.
raten Sie!
4
zu klein
raten Sie
94
zu gross
raten Sie
52
Erraten! 3 mal geraten.
2.7.3 Zwischenschritte
• Legen Sie eine Zahl fest, die erraten werden soll, oder lassen Sie die Zahl von einer
Person über die Konsole eingeben.
• Setzen Sie eine Boolean-Variable auf den Wert false.
• Schreiben Sie den Schleifenkopf, welcher als Bedingung die Boolean-Variable enthält.
• Schreiben Sie dann den Code für die Eingabe einer Zahl (zwischen 0 und 100).
• Prüfen Sie die eingegebene Zahl und teilen Sie dem Spielenden mit, wenn sie zu
klein oder zu gross ist.
• Schreiben Sie die Anweisungen, die ausgeführt werden sollen, falls die Zahl erraten
wurde.
41
2.7.4 Erweiterungen
• Wenn die eingegebene Zahl grösser 100 oder kleiner 0 ist, dann soll sie nicht verglichen werden. Stattdessen soll eine Fehlermeldung ausgegeben werden, dass diese
Zahlen nicht im Suchbereich liegt.
• Wie könnte das Programm zum Erraten von Buchstaben abgeändert werden?
• Wie können Sie auch das Raten automatisieren?
• Überlegen Sie sich, welche die schnellste Ratestrategie ist. Begründen Sie Ihre
Antwort.
2.8 Pokern
2.8.1 Einführung
Beim Poker-Spiel erhält jede Spielerin oder jeder Spieler fünf Karten, die als Hand
bezeichnet werden (siehe Beispiel in Abbildung 2.1).
Abbildung 2.1: Beispiel einer Hand beim Pokern.
Die vier Farben sind Herz, Karo, Pik und Kreuz. Die 13 Werte sind 2 bis 10, Junge
(J), Dame (Q), König (K) und Ass (A). Eine Hand wird nach der Höhe der KartenKombination bewertet. In Tabelle 2.1 sind die Wertigkeiten verschiedener Hände der
Reihe nach geordnet. Eine Hand mit einer höheren Wertigkeit schlägt jedes Blatt mit
einer niedrigeren Wertigkeit.
2.8.2 Ausgangssituation und Programmanforderungen
Bei dieser Aufgabe müssen Sie nicht den ganzen Code von Grund auf neu schreiben. Sie
erhalten einen Ausgangs-Code pokern.java, den Sie im Folgenden erweitern werden.
Was das Programm schon kann
Beim vorgegebenen Programm können Sie bereits fünf Karten einer Hand eingeben
(absteigend sortiert).
42
Name
Bedeutung
Royal Flush
Strasse vom Ass abwärts
in einer Farbe
Straight Flush
Strasse in einer Farbe
Four of a Kind
Vierling (4 Gleiche)
Full House
ein Drilling (3 Gleiche)
und ein Paar (2 Gleiche)
Flush
fünf Karten von einer Farbe
Straight
Strasse: 5 Karten in einer
Reihe (nicht gleiche Farbe)
Three of a Kind
Drilling (3 Gleiche)
Two Pairs
zwei Paare: 2 mal 2 Karten
mit dem gleichen Wert
One Pairs
ein Paar: 2 Karten mit
dem gleichen Wert
Beispiel
Tabelle 2.1: Wertigkeiten verschiedener Hände beim Pokern.
43
Beispiel:
Sie haben eingegeben:
Karte 1 (Wert|Farbe):
Karte 2 (Wert|Farbe):
Karte 3 (Wert|Farbe):
Karte 4 (Wert|Farbe):
Karte 5 (Wert|Farbe):
12 1
9 3
8 2
7 3
4 4
Diese Eingabe würde der Hand in Abbildung 2.1 entsprechen.
Was das Programm noch nicht kann
Ihre Aufgabe besteht nun darin, das Programm so zu erweitern, dass es aufgrund der
eingegebenen fünf Karten der Hand automatisch ausgibt, welche Karten-Kombination
der Spieler hat.
Beispiel:
Sie haben eingegeben:
Karte 1 (Wert|Farbe):
Karte 2 (Wert|Farbe):
Karte 1 (Wert|Farbe):
Karte 1 (Wert|Farbe):
Karte 1 (Wert|Farbe):
12 2
11 2
10 2
9 2
7 2
Sie haben FLUSH
Programmieren Sie mindestens die Erkennung von fünf Poker-Blättern.
2.8.3 Zwischenschritte
• Laden Sie die Datei poker.java auf Ihren Rechner und öffnen Sie den AusgangsCode in Ihrer Programmierumgebung.
• Studieren Sie den Ausgangs-Code. Geben Sie ein paar Kartenkombinationen ein.
• Programmieren Sie die Erkennung der Kartenkombinationen.
Tipp: Überlegen Sie sich, welche Poker-Hände ähnliche Eigenschaften (z.B.
die gleiche Farbe) aufweisen, um den Programmieraufwand für die Bedingungsprüfungen möglichst klein zu halten.
44
2.8.4 Erweiterungen
• Überprüfen Sie, ob die Spielerin/der Spieler die Karten tatsächlich der Grösse nach
absteigend eingegeben hat.
• Wie könnten die Karten absteigend der Reihe nach sortiert werden?
45
Programmieren mit Java Modul 3
Arrays
Theorieteil
Autoren:
Lukas Fässler, Barbara Scheuner, David Sichau
Begriffe
Datenstruktur
Array-Dimension
Array
Array-Länge
Array-Index
Array-Durchlauf
Array-Element
Zweidimensionales Array
47
Theorieteil
3.1 Modulübersicht
Mit den Standarddatentypen, die Sie bis hierhin kennen gelernt haben, kann fast jede
beliebige Zahl oder jedes beliebige Zeichen dargestellt werden. Oft werden beim Programmieren aber zusammengehörige Daten verwendet (z.B. Lottozahlen, Temperaturen,
Abfahrtszeiten). Eine Möglichkeit, eine zusammengehörige Gruppe von Elementen des
gleichen Typs abzuspeichern, bieten Arrays (Reihe, Felder). Auf diese Weise muss nicht
für jedes Element eine eigene Variable deklariert werden, sondern sie können alle unter
einem Bezeichner gespeichert werden. Die Datenstruktur Array kommt in fast jeder
modernen Programmiersprache vor.
3.2 Eindimensionale Arrays
Eindimensionale Arrays sind die einfachste Form von Arrays. Sie bestehen aus einer
geordneten Menge von n Elementen desselben Datentyps. Die Elemente können über
einen sogenannten Index angesprochen werden. Dieser gibt die Position eines Elements
im Array an. In vielen Programmiersprachen (so auch in Java) hat das erste Element
den Index 0, das zweite den Index 1 und das letzte den Index n − 1 (siehe Beispiel in
Tabelle 3.1).
Index
0
1
2
3
4
5
Wert
12
13
15
17
23
32
Tabelle 3.1: Beispiel für ein eindimensionales Array mit sechs Elementen.
Folgende Operationen werden mit Arrays typischerweise ausgeführt: Array deklarieren,
erzeugen, Werte in ein Array ein- und auslesen.
48
3.2.1 Arrays deklarieren
Arrays müssen wie Variablen zunächst deklariert werden. Das heisst, es werden Name
und Datentyp festgelegt. Um anzuzeigen, dass nicht nur ein Element in der Variablen
gespeichert werden kann, werden in Java eckige Klammern [] verwendet. Zur Zeit
der Deklaration ist die Anzahl Elemente noch nicht festgelegt.
Schreibweise:
Datentyp[] name;
Beispiel: Folgende Anweisung deklariert ein Array mit dem Namen zahlen vom Datentyp Integer:
int[] zahlen;
3.2.2 Arrays erzeugen
Um ein Array zu erzeugen, wird der Operator new verwendet. Die Array-Länge (d.h. die
Anzahl Elemente) wird in eckigen Klammern [] hinter den Datentyp geschrieben. Ist
die Länge einmal festgelegt, kann sie nachher nicht mehr geändert werden. Die Länge des
Arrays muss vom Datentyp Integer sein. Die Länge kann mit einer Zahl, einer Konstanten
oder einem Ausdruck angegeben werden.
Schreibweise:
name = new Datentyp[anzahl];
Beispiel: Folgende Anweisung erzeugt sechs Speicherplätze im Array mit dem Namen
zahlen, in welchem sechs Elemente von Typ int gespeichert werden können:
zahlen = new int[6];
// oder
zahlen = new int[4+2];
Bei der Erzeugung des Arrays werden die Elemente mit Default-Werten belegt. Beim
Datentyp Integer ist dies der Wert 0.
Deklaration und Erzeugen von Arrays kann alternativ auch in einer einzigen Anweisung
durchgeführt werden.
49
Schreibweise:
Datentyp[] name = new Datentyp[anzahl];
Beispiel: Folgende Anweisung erzeugt ein Array mit dem Namen zahlen vom Datentyp Integer mit sechs Elementen:
int[] zahlen = new int[6];
3.2.3 Arrays initialisieren
Einem Array-Element kann unter Angabe des Indexes ein Wert zugewiesen werden. In
Java hat das erste Element den Index 0. Ein Array mit sechs Elementen hat somit die
Indizes 0, 1, 2, 3, 4 und 5.
Schreibweise:
name[Index] = Wert;
Beispiel: So weisen wir dem ersten Element des Arrays den Wert 12 und dem zweiten
den Wert 13 zu:
zahlen[0] = 12;
zahlen[1] = 13;
In Java können bei der Erzeugung des Arrays die Elemente auch direkt initialisiert
werden, indem geschweifte Klammern {} gesetzt und die einzelnen Werte getrennt
mit Kommata (,) eingegeben werden. Die Grösse des Arrays wird durch die Anzahl
der Werte festgelegt. Der Operator new entfällt in diesem Fall.
Schreibweise:
Typ[] name = {wert1, wert2,..., wertN};
Beispiel: Deklaration, Erzeugung und Initialisierung des Arrays zahlen mit den sechs
Elementen 12, 13, 15, 17, 22 und 32:
int[] zahlen = {12, 13, 15, 17, 22, 32};
50
3.2.4 Auf Array-Elemente zugreifen
Auf einzelne Elemente eines Arrays wird über einen Index (z.B. i) zugegriffen. x[i]
liefert somit das Element aus dem Array x an der Position i. Es gilt zu beachten, dass
die Indizes bei 0 beginnen und bei einem weniger als der Anzahl der Elemente des Arrays
enden. Es können einzelne Elemente oder Bereiche von Arrays aufgerufen werden und
es kann mit Elementen von Arrays gerechnet werden.
Beispiel:
//Array mit 3 Elementen.
int[] c = new int[3];
c[0]=1;
c[1]=2;
c[2]=3;
//Aufruf eines Elements (Resultat: 1).
System.out.println(c[0]);
//Addition zweier Elemente (Resultat: 5).
System.out.println(c[1]+c[2]);
3.2.5 Array-Durchlauf mit Schleifen
Es ist üblich, zur Bearbeitung von Arrays for-Schleifen zu verwenden. Der Wert der
Laufvariablen entspricht dabei dem Index-Wert des Arrays. Der Aufwand reduziert sich
dadurch auf wenige Anweisungen, egal wie viele Elemente ein Array besitzt. Dieser
Vorgang wird auch Array-Durchlauf genannt.
Beispiel: Mit folgender Anweisung können die sechs Elemente des Arrays zahlen am
Bildschirm untereinander ausgegeben werden:
for (int i=0; i<6; i++) {
System.out.println(zahlen[i]);
}
Die for-Schleife zählt von 0 bis 5. Bei jedem Schleifendurchlauf wird die Variable i als
Index verwendet, um das Array Element an der entsprechenden Stelle auszugeben.
51
3.2.6 Länge eines Arrays bestimmen
Jedes Array hat in Java eine Eigenschaft length, mit welcher die Länge des Arrays
abgefragt werden kann.
Beispiel:
for (int i=0; i<zahlen.length; i++) {
System.out.println(zahlen[i]);
}
Das ist vor allem beim Durchlaufen des Arrays hilfreich, um die obere Grenze der Schleife
auszurechnen. Dies hat den Vorteil, dass bei einer Änderung der Array-Länge die Schleife
nicht angepasst werden muss.
3.3 Zwei- und mehrdimensionale Arrays
Besteht ein Element eines Arrays selbst wieder aus einem Array, entsteht ein zweidimensionales Array. Man kann es sich als Tabelle mit m mal n Elementen vorstellen,
die jeweils über zwei Indizes angesprochen werden (siehe Beispiel in Tabelle 3.2).
Index
0
1
2
3
4
5
0
12
13
15
17
23
39
1
14
53
45
87
27
62
2
22
33
17
19
83
32
Tabelle 3.2: Beispiel für ein zweidimensionales Array mit drei mal sechs Elementen.
3.3.1 Initialisieren und Erzeugen eines zweidimensionalen Arrays
Schreibweise:
Typ[][] name = new Typ[anzahlZeilen][anzahlSpalten];
52
Beispiel: Folgende Anweisung erzeugt ein zweidimensionales Array mit dem Namen
zahlen vom Datentyp Integer mit 3 mal 5 Elementen:
int[][]zahlen = new int[3][5];
3.3.2 Werte ins zweidimensionale Array ein- und auslesen
Um auf ein einzelnes Element eines zweidimensionalen Arrays zuzugreifen, werden die
zwei Indizes für die Zeilen- und Spaltennummer angegeben:
name[zeilennummer][spaltennummer] = wert;
Beispiel:
zahlen[0][0] = 22;
Um zweidimensionale Arrays iterativ zu bearbeiten, sind geschachtelte Schleifen mit
zwei Indexvariablen notwendig.
Beispiel: Folgende Zeilen geben alle Elemente des zweidimensionalen Arrays zahlen
am Bildschirm aus:
for (int i=0; i<3; i++) {
for (int j=0; j<6; i++) {
System.out.println(zahlen[i][j]);
}
}
3.3.3 Mehrdimensionale Arrays
Ein Array kann auch mehr als zwei Dimensionen haben. Für jede weitere Dimension
wird ein weiterer Index für den Zugriff auf die Elemente benötigt.
3.4 Zeichenketten (Strings) als Arrays
Wie bereits in Modul 1 erwähnt, ist eine Variable des Types String eine Zusammenfassung mehrerer Variablen des Typs Character (char). In Java wird eine Zeichenkette
als Array des Datentyps Character angelegt. Ein String kann somit auch aus einem
53
Character-Array erzeugt werden. Auf die einzelnen Buchstaben im String kann somit
auch wie beim Array über den Index zugegriffen werden.
Beispiel:
char[] meinText = {’d’,’e’,’r’,’ ’,’T’,’e’,’x’,’t’};
String meinString = new String(meinText);
char erstesZeichen= meinString.charAt(0);
Bei diesem Beispiel wird als erstes ein char-Array der Länge 8 erzeugt und direkt mit
acht Zeichen initialisiert. Auf Basis dieses Arrays wird dann ein String erzeugt, der
den Text „der Text“ enthält. Aus diesem String wird anschliessend das erste Zeichen
ausgelesen. Will man alle Zeichen eines Textes auf diese Weise einzeln auslesen, kann
man eine Schleife einsetzen:
for (int i=0; i<meinString.length(); i++){
System.out.print(meinString.charAt(i));
}
54
Selbstständiger Teil
3.5 Bowling
3.5.1 Einführung
Beim Bowling werden die Resultate typischerweise in einer Tabelle aufgeschrieben und
ausgewertet. Aufgeschrieben wird die Anzahl umgeworfener Pins jeder Runde. Es sind
somit Zahlen zwischen 0 (keiner getroffen) und 10 (alle getroffen, ein sogenannter Strike)
möglich.
Spieler
1
2
3
4
6
2
2. Runde
2
8
0
3. Runde
10
2
5
4. Runde
3
4
5
5. Runde
6
8
10
Summe
25
28
22
1. Runde
Tabelle 3.1: Resultate eines Bowlingspieles.
3.5.2 Aufgabenstellung
Ihr Programm soll die Resultate von 3 Spielenden über 5 Runden hinweg aufnehmen und
auswerten (siehe Tabelle 3.1). Zum Speichern der Resultate wird ein zweidimensionales
Array und zur Berechnung der Summen ein eindimensionales Array benötigt.
55
3.5.3 Zwischenschritte
Gehen Sie wie folgt vor:
• Deklarieren der Variablen: Deklarieren Sie die Variable resultate als zweidimensionales Integer-Array (3 Spieler, 5 Runden) und summen als eindimensionales
Integer-Array.
• Einlesen der Resultate: Lesen Sie die Resultate in das Array resultate ein.
Es sollen für jede der 5 Runden die Punkte für jeden der 3 Spieler eingegeben
werden können.
• Berechnen der Resultate: Hier soll im Array summen die Summe der Punkte
jedes einzelnen Spielers gespeichert werden.
• Ausgeben der Resultate: Geben Sie die Punktetabelle (resultate) und die
Summen (summen) in tabellarischer Form auf dem Bildschirm aus.
3.5.4 Erweiterungen
• Überprüfen Sie, ob die eingegebene Zahl erlaubt ist.
• Geben Sie am Ende aus, wer wie viele Strikes geschafft hat, und wie oft jede Person
keinen Pin getroffen hat.
• Passen Sie ihr Programm so an, dass die Anzahl der Runden und die Anzahl der
Spieler am Anfang eingegeben werden können.
• Geben Sie aus, wer die meisten Punkte hat.
• Berechnen Sie, in welcher Runde die jeweiligen Spieler ihren ersten Strike geschafft
haben, und geben Sie das Resultat am Bildschirm aus.
3.6 Tic Tac Toe
3.6.1 Einführung
Beim Tic Tac Toe (auch 3 gewinnt) spielen zwei Spieler gegeneinander. Abwechselnd
setzen die Spieler ihr Zeichen (z.B. x oder o) in eines der leeren Felder. Gewonnen hat
derjenige Spieler, der eine Spalte, Zeile oder Diagonale mit seinem Zeichen vollständig
besetzen kann.
3.6.2 Aufgabenstellung
• Zwei Spieler sind abwechslungsweise an der Reihe.
• Bei jedem Spielzug muss deutlich gemacht werden, welcher der beiden Spieler an
der Reihe ist.
56
• Nach jedem Spielzug soll das aktuelle Spielbrett ausgegeben werden.
• Es soll angezeigt werden, wenn eine Person gewonnen hat.
3.6.3 Zwischenschritte
• Spielen Sie das Spiel zunächst auf Papier. Welche Schritte werden nacheinander
ausgeführt?
• Programmieren Sie dann folgende Schritte:
– Definieren Sie ein 3 × 3-Spielbrett vom Typ Character.
– Fügen Sie eine Variable spieler ein, welche zwei Werte (z.B. 1 und 2)
annehmen kann.
– Setzten Sie alle Werte im Feld auf Leerzeichen (' ').
– Programmieren Sie eine Ausgabe des Spielfeldes.
1 2 3
-------1: | | |
2: | | |
3: | | |
Spieler 1:
• Über eine Benutzereingabe soll der Spieler das Feld eingeben können, in welches
sein Zeichen gesetzt werden soll.
• Setzen Sie die jeweiligen Zeichen (z.B. x oder o) in die vom Spieler gewünschten
Felder.
• Wiederholen Sie die Spielzüge, bis das Spielbrett voll ist oder jemand gewonnen
hat.
3.6.4 Erweiterungen
Überprüfen Sie, bevor ein Spielzug ausgeführt wird, ob an der gewünschten Stelle bereits
ein Zeichen gesetzt worden ist. Steht an dieser Stelle bereits ein Zeichen, soll der Spieler
eine neue Eingabe machen müssen.
Das gleiche soll passieren, wenn ein Spieler eine Eingabe macht, die ausserhalb des
Spielfeldes liegt.
57
3.7 Such- und Sortieralgorithmen
3.7.1 Einführung
Das Suchen in gesammelten Daten und das Sortieren von Daten sind zwei der häufigsten
Aufgaben, mit denen sich ein Programmierer konfrontiert sieht. Zu diesen Themen gibt
es mittlerweile unzählige Bücher, denn da Such- und Sortieralgorithmen so oft verwendet
werden, ist es besonders wichtig, dass sie so effizient wie möglich programmiert werden.
Ferner gibt es eine grosse Anzahl von Strategien, die verfolgt werden können, um einen
Sortieralgorithmus umzusetzen. In den Entwurf und die Analyse dieser Algorithmen
wurde seit Mitte des zwanzigsten Jahrhunderts viel Energie gesteckt. Wir werden hier
nur eine kleine Auswahl kennenlernen.
Vorbereitendes
Laden Sie das Ausgangsprogramm lottozahlen.java auf Ihren Rechner. Studieren Sie das
Programm.
3.7.2 Suchalgorithmen
Es gibt, wie oben erwähnt, verschiedene Suchalgorithmen, die sich in ihrem Aufbau und
ihrer Effizienz unterscheiden. Die bekanntesten sind die lineare und die binäre Suche.
Wir wollen hier die lineare Suche betrachten.
So funktioniert die lineare Suche
Eine Menge von Elementen (z.B. ein Array) wird nach einem bestimmten
Element durchsucht. Die Suche beginnt beim ersten Element, und die Elemente
werden in der Reihenfolge durchlaufen in der sie abgespeichert sind. Entspricht
das betrachtete Element dem gesuchten Element, wird die Suche beendet,
ansonsten wird weiter gesucht.
58
Aufgaben
Durchsuchen Sie das Array nach dem höchsten Wert und geben Sie den Wert und
die Position der Daten in der Konsole aus.
So wird nach dem maximalen Wert gesucht
• Die Position des (momentanen) Maximums wird in der Variable max
gespeichert.
• Zuerst wird das erste Element des Arrays als das Maximum angenommen.
• Es werden nun alle Elemente des Arrays (ausser des ersten) durchlaufen.
• Ist der Wert des Feldes an der momentanen Position grösser als das bisher
angenommene Maximum, dann wird diese Position in max gespeichert.
3.7.3 Erweiterungen
• Suchen Sie im Array auf die gleiche Weise auch das Minimum. Verwenden Sie für
beide Suchen eine gemeinsame Schleife.
• Überlegen Sie sich, was passiert, wenn der gesuchte Wert mehr als einmal vorkommt.
Wie müsste ihr Programm darauf reagieren?
• Wie beurteilen Sie den Suchaufwand? Haben Sie Ideen für eine Optimierung?
3.7.4 Sortieralgorithmen
Das Ziel von Sortieralgorithmen ist es, die Elemente einer Menge nach einem bestimmten Kriterium zu sortieren. Nach dem Sortieren liegen die Elemente in aufsteigender
oder absteigender Reihenfolge vor.
Es gibt verschiedene Sortieralgorithmen, die sich in ihrem Aufbau und ihrer Effizienz
unterschieden. Bekannte Vertreter sind Bubble-Sort, Insertion-Sort, Merge-Sort und
Quick-Sort.
59
So funktioniert Bubble-Sort (für eine aufsteigende Sortierung, siehe Abbildung 3.1)
1. Es werden jeweils zwei benachbarte Elemente eines Arrays verglichen.
Begonnen wird mit dem Element mit dem Index 0 und 1, dann 1 und 2,
dann 2 und 3, etc.
2. Wenn der Wert des linken Elements grösser ist als der Wert des rechten,
werden die beiden Werte vertauscht. Hinweis: Vorsicht swap!
3. Mit einem Arraydurchlauf „wandert“ so das grösste Element ans Ende
des Arrays.
4. Nun werden die Schritte 1 bis 3 wiederholt, um das zweitgrösste Element an die zweitletzte Position zu bringen. Hinweis: Der Vergleich des
zweitletzten mit dem letzten entfällt, da das letzte das grösste ist.
5. Die Schritte 1 bis 4 werden so lange wiederholt, bis die zwei kleinsten
Elemente miteinander verglichen werden.
Aufgabe
Versuchen Sie den Bubble-Sort-Algorithmus zu implementieren!
Erweiterungen
• Wie könnte die Effizienz von Bubble-Sort erhöht werden?
60
Abbildung 3.1: Bubble-Sort. Details siehe Text.
61
Programmieren mit Java Modul 4
Methoden und Funktionen
Theorieteil
Autoren:
Lukas Fässler, Barbara Scheuner, David Sichau
Begriffe
Methode
Sichtbarkeit von Variablen
Subroutine
Überladen
Prozedur
Rekursion
Funktion
Parameter
Exception
Rückgabewert
Zufallszahl
Rückgabetyp
Modularität
63
Theorieteil
4.1 Modulübersicht
Durch das Modularitätsprinzip wird ein Gesamtproblem in getrennte Teilprobleme
zerlegt. In diesem Modul lernen Sie Möglichkeiten kennen, wie Sie Anweisungen in
Unterprogrammen (oder Subroutinen) zusammenfassen können. Unterprogramme
sind funktionale Einheiten, die von mehreren Stellen in einem Programm aufgerufen
werden können. Auf diese Weise muss ein Programmteil nur einmal entwickelt und getestet werden, wodurch sich der Programmieraufwand verringert und der Programmcode
verkürzt. Werden beim Aufrufen des Unterprogramms Daten übergeben, werden diese
als Parameter bezeichnet. In vielen Programmiersprachen werden zwei Varianten von
Unterprogrammen unterschieden: jene mit einem Rückgabewert (Funktionen) und
jene ohne Rückgabewert (Prozeduren). In Java bezeichnet man beide Varianten
generell als Methoden, die Parameter und Rückgabewert haben können.
4.2 Methoden
In Java besteht eine Methode aus einem Kopf (oder Signatur) mit den Modifikatoren
public static1 , dem Rückgabetyp, dem Namen, den Parametern sowie dem Rumpf
in geschweiften Klammern {}. Die Ausführung einer Java-Applikation startet meist
in der Haupt oder main-Methode, die sich oft darauf beschränkt, andere Methoden
aufzurufen.
4.2.1 Methoden ohne Rückgabewert (Prozeduren)
Methoden ohne Rückgabewert haben Sie bereits verwendet: Zum Beispiel die Methode
System.out.println(), welche einen Zeilenumbruch auslöst. Sie können aber auch
eigene Methoden schreiben, welche von Ihnen vorgegebene Aufgaben erfüllen. Methoden
ohne Rückgabewert sehen wie folgt aus:
1 Die
Bedeutung der Modifikationen ergeben sich aus der Objektorientierung von Java und werden in
diesem Buch nicht behandelt.
64
Schreibweise:
void methodenName() { //Signatur der Methode
// Anweisungen
}
Das Wort void gibt dabei an, dass kein Rückgabewert erwartet wird. Die leere Klammer
() bedeutet, dass keine Parameter übergeben werden.
Beispiel: Die folgende Klasse beinhaltet die Haupt-Methode mit dem Namen main
und die Methode ausgabe, welche in der main-Methode aufgerufen wird:
public class ProzedurTest{
public static void main(String[] args){
ausgabe();
}
public static void ausgabe(){
//Signatur der Methode
System.out.println("die Methode wurde ausgeführt");
}
}
4.2.2 Methoden mit Rückgabewert (Funktionen)
Methoden mit Rückgabewert werden verwendet, um ein Resultat aus den Anweisungen in
der Methode zu gewinnen. Der Datentyp des Rückgabewerts steht dabei direkt vor dem
Methodennamen. In der Methode selbst muss sichergestellt werden, dass in jedem Fall
ein Wert vom entsprechenden Typ zurückgegeben wird. Um einen Wert zurückzugeben,
wird das Wort return verwendet.
Schreibweise:
rückgabetyp methodenName() { //Signatur der Methode
// Anweisungen
}
65
Beispiel: Die folgende Klasse beinhaltet eine main-Methode und eine weitere Methode
getAnswer, welche in der main-Methode aufgerufen wird:
public class ProzedurTest{
public static void main(String[] args){
int wert = getAnswer();
}
public static int getAnswer(){ //Signatur der Methode
return 42;
}
}
Der Rückgabewert in obrigen Beispiel ist vom Typ Integer. Bei Methoden mit Rückgabewert muss darauf geachtet werden, dass in jedem Fall, der eintreffen könnte, zwingend
ein Wert zurückgegeben wird.
Beispiel:
boolean hallo(){
int i = 1;
if (i == 1){
return true;
} else {
System.out.println("tritt nie ein");
}
}
Auch wenn der else-Fall in dieser Methode nie eintrifft, muss darauf geachtet werden,
dass auch in diesem Fall etwas zurückgegeben würde. Korrekt wäre somit:
boolean hallo(){
int i=1;
if (i==1){
return true;
} else {
System.out.println("tritt nie ein");
return false;
}
}
66
4.2.3 Methoden mit Parametern
Beide Arten von Methoden (also Prozeduren und Funktionen) können in der Signatur
Parameter verlangen. Parameter sind Variablen, deren Initialisierung beim Aufruf der
Methode geschieht und die zur Erfüllung der Aufgabe der Methode nötig sind.
Beispiel:
void addiereUndGibAus(int x, int y){
int z = x + y;
System.out.println("Summe: "+z);
}
Diese Methode kann nun z.B. mit den Werten 3 und 2 aufgerufen werden mit der
Anweisung:
addiereUndGibAus(3,2);
Methoden mit Rückgabewert können nun auch noch einen Wert zurückgeben.
Beispiel:
int addiere (int x, int y){
int z = x + y;
return z;
}
Diese Methode kann nun z.B. aufgerufen werden mit:
int resultat = addiere(3,2);
Der Rückgabewert wird hier in der Variable resultat gespeichert, deren Datentyp mit
dem Rückgabetyp übereinstimmt.
4.3 Methoden aus der Klasse Math
Die Klasse Math bietet einige Methoden an, welche mathematische Funktionen realisieren. All diese Methoden sind Funktionen, weil sie einen Rückgabewert (das Resultat
der Berechnung) besitzen. Als Übergabeparameter erwarten sie meist eine oder zwei
Zahlen.
67
Beispiel:
public class TestMath{
public static void main(String[] args){
double x= 19.7;
double y= 20.3;
double groessereZahl = Math.max(x,y);
double kleinereZahl = Math.min(x,y);
double abrunden = Math.ceil(x);
}
}
Eine Methode ohne Parameter in der Klasse Math ist die Funktion Math.random().
Diese Funktion gibt eine Zufallszahl zwischen 0 und 1 zurück, wobei die Zahl gleich 0
sein kann, aber immer kleiner als 1 ist. Mit Hilfe dieser Methode kann eine zufällige
ganze Zahl zwischen 1 und x erzeugt werden. Dies geschieht in drei Schritten:
1. Erzeugen einer Zufallszahl zwischen 0 und 1.
2. Multiplikation dieser Zahl mit x. Dies ergibt eine Gleitkommazahl Zahl zwischen
0 und x.
3. Runden dieser Zahl.
Beispiel:
// Generierung ganzer Zahl zwischen 0 und 99 durch abrunden
int zufallsZahl1 = (int)(Math.random()*100);
// Generierung ganzer Zahl zwischen 0 und 100 durch runden
long zufallsZahl2 = Math.round(Math.random()*100);
4.4 Überladen von Methoden
Verschiedene Methoden können denselben Namen haben, wenn sie unterschiedliche Parameter erhalten. Unterschiedliche Rückgabewerte alleine sind nicht ausreichend. Haben
zwei Methoden denselben Namen, aber erhalten unterschiedliche Typen oder Anzahl
von Parameter, nennt man die Methoden überladen. Ein populäres Beispiel, das Sie
schon oft verwendet haben, ist die Methode print() bzw. println(). Dieser Methode
können Werte von Typ String, int, double, etc. übergeben werden. Für Sie als Benutzer
sieht es aus, als würden Sie immer dieselbe Methode aufrufen. Tatsächlich ist es aber so,
dass unterschiedliche Methoden entsprechend dem Datentyp aufgerufen werden.
68
Wir können also die beiden folgenden Methoden mit identischem Namen linie in der
gleichen Klasse schreiben:
// Signatur mit einem Parameter
public static void linie(int x){
for (int i=0; i<x; i++){
System.out.print(’-’);
}
}
// Signatur mit zwei Parametern
public static void linie(int x, char c){
for (int i=0; i<x; i++){
System.out.print(c);
}
}
Wenn Sie nun die Methode mit nur einem Parameter-Wert aufrufen, wird die erste
Methode verwendet, mit zwei entsprechenden Werten die zweite:
linie(8);
linie(19, ’-’);
4.5 Gültigkeitsbereiche von Variablen
Variablen haben eine beschränkte Lebensdauer. Einige Variablen werden erst mit
dem Beenden des Programms gelöscht, andere schon früher. Eine Variable ist immer
für den Anweisungsblock (siehe Modul 2) oder eine Klasse gültig, in dem sie deklariert
wurde. Eine Variable, welche am Anfang einer Methode deklariert wird, wird auch wieder
gelöscht, wenn die Methode beendet wird. Wenn man den Wert dieser Variablen später
noch benötigt, muss er an die aufrufende Methode zurückgegeben werden.
69
Beispiel:
public class VariablenSichtbarkeit{
public static int global = 20;
public static void main(String[] args){
System.out.println("Werte zwischen 1 und "+ global);
ausgabe();
}
public static void ausgabe(){
int zufall = 0;
for (int i=0; i<30; i++){
zufall = (int) (Math.random() * global) + 1;
}
}
}
Die Variable global ist dabei für die ganze Klasse gültig. Die Variable zufall ist
hingegen nur innerhalb der Methode ausgabe gültig und die Variable i nur innerhalb
der Schleife.
70
Beispiel: Folgender Code würde, wenn die kommentierte Zeile verwendet würde, zu
einer Fehlermeldung führen, da die Variable zufall in der main-Methode nicht gültig
ist:
public class VariablenSichtbarkeit2{
public static void ausgabe(){
int zufall = (int) (Math.random() * global) + 1;
}
public static void main(String[] args){
ausgabe();
// System.out.println("Werte von 1 bis "+ zufall);
}
}
4.6 Rekursion
Bei der Rekursion ruft eine Methode sich selber wieder auf. Damit sich die Methode nicht endlos immer wieder selbst aufruft, was die gleichen Konsequenzen wie eine
Endlosschleife hätte, benötigt sie eine Abbruchbedingung, welche diese Folge von
Selbst-Aufrufen stoppt.
Um eine Rekursion zu programmieren, müssen Sie zwei Elemente bestimmen:
• Basisfall: in diesem Fall ist das Resultat der Berechnung schon bekannt. Dieser
Fall ist die Abbruchbedingung der Rekursion.
• Rekursiver Aufruf: es muss bestimmt werden, wie der rekursive Aufruf geschehen
soll.
4.6.1 Beispiel 1: Fakultät
Die Berechnung der Fakultät f (x) = x! von x kann mit einer rekursiven Methode
realisiert werden.
• Basisfall: für die Werte 0 und 1 ist die Fakultät 1.
• Rekursion: x! = x · (x − 1)! für x > 1.
71
int fakultaet(int x){
if ((x == 0) || (x == 1){ // Basisfall
return 1;
} else {
return x * fakultaet(x-1); // Rekursiver Aufruf
}
}
4.6.2 Beispiel 2: Fibonacci
Ein weiteres beliebtes Beispiel für Rekursionen ist die Fibonacci-Folge. Diese unendliche Folge von natürlichen Zahlen beginnt mit 0 und 1. Die danach folgende Zahl ergibt
sich jeweils aus der Summe der zwei vorangegangenen Zahlen: Die Folge lautet also
0, 1, 1, 2, 3, 5, 8, . . .
Bei der Fibonacci-Folge sind bei jedem Schritt zwei rekursive Aufrufe nötig:
f (n) = f (n − 1) + f (n − 2) für n ≥ 2 mit den Anfangswerten f (1) = 1 und f (0) = 0.
• Basisfall: Für den Fall, dass n gleich 0 oder 1 ist, wissen wir, dass 0 bzw. 1 zurückgegeben werden muss.
• Rekursion: Für alle anderen Fälle rufen wir die Funktion wieder auf, wobei wir den
übergebenen Wert um jeweils 1 und 2 verringern.
int fibonacci(int n) {
if (n == 0){ // Basisfall 1
return 0;
} else if (n == 1){ // Basisfall 1
return 1;
} else { // zwei Mal rekursiver Aufruf
return (fibonacci(n-1) + fibonacci(n-2));
}
}
Beachten Sie, dass Funktion fibonacci in Beispiel 2 sich selbst gleich zweimal aufruft.
Man spricht auch von kaskadenförmiger Rekursion. In Beispiel 1 erfolgt nur ein einzelner
Selbstaufruf, was man als lineare Rekursion bezeichnet.
72
4.7 Fehlerbehandlung mit Exceptions
Exceptions (Ausnahmen) werden durch Ausnahmesituationen bei der Programmausführung ausgelöst. Dadurch sollen Programmabbrüche verhindert werden. In Java ermöglicht die try-catch-Anweisung das Auffangen und Behandeln von Exceptions innerhalb
einer Methode.
Beispiel: Vielleicht wollten Sie schon einmal aus Versehen einen Text „jk“ in eine Zahl
umwandeln oder in einem Array auf einen Index zugreifen, der ausserhalb des Arrays
liegt. Exceptions müssen nicht zwingend bis zum Benutzer durchdringen (d.h. auf der
Konsole erscheinen). Man kann sie auch abfangen (catch) und eine Lösung für das
Problem suchen. Abgefangen können die Exceptions mit:
try {
// Irgendetwas, dass einen Fehler auslösen könnte
} catch (Exception c) {
// Lösung des Problems
}
Beispiel: Hier könnte der Benutzer anstelle einer ganzen Zahl zum Beispiel ein Zeichen
eingeben. Diese Fehlereingabe kann z.B. wie folgt behandelt werden:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int zahl = 0;
System.out.println("Bitte eine ganze Zahl eingeben");
String wert = scan.nextLine();
try {
zahl = Integer.parseInt(wert);
} catch (Exception e){
System.out.println("Das ist keine ganze Zahl");
Zahl = 0;
}
}
4.7.1 Werfen einer Exception
Sie können das Konstrukt der Exception auch selber verwenden. Wenn Sie in einer eigenen
Methode einen Fehler kommunizieren wollen, dann können Sie dort eine Exception werfen
73
(throw). Mit der Anweisung throw new Exception() lösen Sie einen Fehler aus. Die
Signatur einer Methode, welche eine Exception auslösen kann, muss noch durch den
Zusatz throws Exception (heisst so viel wie wirft Fehlermeldungen) ergänzt werden.
Beispiel:
public class ExceptionTester{
public static void main(String[] args) {
try {
tester(-3);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void tester(int x) throws Exception{
if (x < 0){
throw new Exception();
}
}
}
74
Selbstständiger Teil
4.8 Erweiterungen Pandemie-Simulation
4.8.1 Einführung
Erweitern Sie Ihre Pandemie-Simulation aus dem E.Tutorial® wie folgt:
• Setzen der Startbedingungen: Dauer der Simulation, Ansteckungswahrscheinlichkeit, etz.
• Die Person, welche am Anfang krank ist, könnte zufällig ausgewählt werden.
• Die Ansteckungswahrscheinlichkeit könnte auch zufällig sein.
4.8.2 Setzen der Startbedingungen
Lassen Sie vor dem Start der Simulation den User die Startbedingungen setzen:
• Wie lange soll die Simulation dauern?
• Wie ansteckend ist die Krankheit? Die Ansteckungswahrscheinlichkeit x = 1/n
soll mit einer ganzen Zahl n angegeben werden können.
Beachten Sie bei jedem Punkt, ob die Variable global oder lokal definiert werden soll.
Die Benutzereingabe kann wie gewohnt mit dem Scanner über die Konsole vorgenommen
werden.
4.8.3 Erweiterungen
Implementieren Sie eine der folgenden Ideen:
•
•
•
•
Vergrössern Sie die Simulation (z.B. 100 × 100).
Lassen Sie den Nutzer die Grösse der Simulation auswählen.
Die Zahlen könnten noch farbig gestaltet werden (siehe www.processing.org).
Viele Krankheiten sind zu Beginn ansteckender als am Ende. Machen Sie die
Ansteckungswahrscheinlichkeit abhängig von der Dauer der Krankheit der bereits
Erkrankten.
75
• Geben Sie eine Tabelle aus, in welcher die wichtigsten Kennzahlen ersichtlich sind,
z.B.:
Simulationsschritt: 20
Noch nicht erkrankte Personen: 40
Kranke Personen: 64
Geheilte Personen: 36
• Wenn viele Nachbarn krank sind, soll die Wahrscheinlichkeit grösser sein, dass eine
gesunde Person angesteckt wird.
• Geheilte Personen sind nur eine gewisse Zeit immun gegen die Krankheit. Passen
Sie Ihre Simulation so an, dass geheilte Personen nach einer gewissen Zeit (z.B. 4
Tagen) wieder angesteckt werden können.
76
Programmieren mit Java Modul 5
Objekte
Theorieteil
Autoren:
Lukas Fässler, Barbara Scheuner, David Sichau
Begriffe
Klassen
Attribut
Objekte
Objekt-Methode
Objekt-Eigenschaft
Referenztypen
77
Theorieteil
5.1 Modulübersicht
Ziel der objektorientierten Programmierung ist es, analog zur „realen Welt“, Daten mit
ihrer zugehörigen Funktionalitäten in Form von Objekten abzubilden. Während bei
der prozeduralen Programmierung Daten und die auf ihnen durchgeführten Operationen
voneinander getrennt werden, sind bei der objektorientierten Programmierung Daten
und Operationen in einer einzigen Struktur, der Klasse, vereinigt. Eine Klasse stellt
eine Beschreibung („Schablone“ oder „Bauplan“) für Objekte dar, die durch gleiche
oder ähnliche Eigenschaften und Verhaltensweisen charakterisiert sind. Von einer Klasse
können mehrere Objekte (Exemplare oder Instanzen) erzeugt werden.
5.2 Klassen und Objekte
Objekte dienen dazu, Daten (Variablen) und ihre dazugehörigen Funktionalität
(Methoden) zu verwalten. Aus welchen Variablen und Methoden ein Objekt aufgebaut
ist, wird in der zugehörigen Klasse festgelegt. Man kann sich die Variablen einer Klasse
auch als Elemente einer Liste vorstellen, wie zum Beispiel:
Name
Vorname
Jahrgang
Beruf
p1
Mueller
Hans
1942
Maurer
p2
Meier
Maria
1954
Elektrikerin
p3
Koller
Andreas
1991
Student
Die Klasse (analog zur Tabellenüberschrift) gibt an, dass in den Objekten (hier die einzelnen Zeilen) die Variablen name, vorname, jahrgang und beruf abgespeichert
werden sollen. Die zugehörigen Objekte p1, p2 und p3 sehen wie folgt aus:
78
p1: Person
p2: Person
p3: Person
name: Mueller
name: Meier
name: Koller
vorname: Hans
vorname: Maria
vorname: Andreas
jahrgang: 1942
jahrgang: 1954
jahrgang: 1991
beruf: Maurer
beruf: Elektrikerin
beruf: Student
Objektmethoden arbeiten mit diesen Informationen. Über eine Methode kann man zum
Beispiel die Informationen über eine Person abfragen oder die Informationen updaten.
Dabei gilt, dass die Methoden für jedes Objekt existieren und deshalb mit den Variablenwerten (Zustände) des zugehörigen Objekts arbeiten.
5.2.1 Klassen
Eine Klasse enthält die Vorschrift, was alles zu einem Objekt gehört. In unserem Fall
sind dies Name, Vorname, Jahrgang und Beruf. Eine Klasse wird mit dem Befehl class
definiert.
Schreibweise:
public class Person {
// Eigenschaften des Objekts (Objektvariablen)
// Funktionalität des Objekts (Objektmethoden)
}
5.2.2 Objektvariablen und Methoden
Objektvariablen und Methoden definieren alle Elemente, welche in jedem Objekt vorkommen. Diese werden alle nicht static deklariert und dadurch an ein Objekt und nicht
an die Klasse gebunden. Die Objektmethoden, meist einfach als Methoden bezeichnet,
arbeiten mit diesen Variablen. Meistens sind die Methoden dazu da, die Variablen zu
verändern, ihren Wert bekannt zu geben, oder aufgrund von mehreren Variablen einen
Zustand zu berechnen.
Objektvariablen (Attribute)
Die Attribute sind die Eigenschaften, welche in einem Objekt gespeichert werden. In
diesen Variablen kann der Zustand eines Objekts gespeichert werden. Unsere Klasse
Person, welche die Vorschrift für ein Personenobjekt enthält, sieht dann wie folgt aus:
79
public class Person {
String name;
String vorname;
int jahrgang;
String beruf;
}
Objektmethoden
Klassen können nicht nur Daten in Form von Variablen speichern, sondern auch Funktionalitäten anbieten. Diese Funktionalität ermöglicht die Verarbeitung der Daten.
Für die Klasse Person kann z.B. eine Methode angeboten werden, welche die Informationen zu einer Person ausgibt (print). Eine weitere Methode gibt das Alter der Person
zurück, wenn das aktuelle Jahr übergeben wird (altersAusgabe):
public class Person {
String name;
String vorname;
int jahrgang;
String beruf;
void print(){
System.out.println(name +"/"+ vorname);
System.out.println(jahrgang +"/"+ beruf);
}
int altersAusgabe(int jahr){
int alter= jahr-jahrgang;
System.out.println(alter);
}
}
Einer Objektmethode stehen ausser den Parametern, welche der Methode übergeben
werden, auch noch die Objektvariablen (Attribute) zur Verfügung.
5.2.3 Erstellen von Objekten unter Verwendung einer Klasse
Damit man eine Person verwenden kann, muss als erstes ein Objekt dieses Typs erzeugt
werden. So deklariert und erzeugt man beispielsweise das Objekt p1 vom Typ Person:
80
1. Deklaration: Referenz auf die Klasse Person setzen und mit p1 benennen:
Person p1;
Im Unterschied zu primitiven Typen ist der Standardwert null anstelle von 0.
2. Erzeugung: Mit new eine Instanz der Klasse Person erzeugen und in der Referenz
p1 speichern:
p1 = new Person();
Meistens werden die beiden Schritte in einer Anweisung geschrieben:
Person p1 = new Person();
Das Erzeugen von Objekten geschieht meist in einer weiteren Klasse, welche ihre Daten in
der angebotenen Klasse Person speichern möchte. Die Klasse Personalverwaltung
möchte zum Beispiel neue Personen-Objekte erzeugen können. Angenommen, diese Personalverwaltung sei der Startpunkt unseres Programms, dann könnte diese z.B. so aussehen:
public class Personalverwaltung {
public static void main(String[] args){
//Deklaration
Person p1;
//Erzeugung eines neuen Objektstion
p1 = new Person();
//Zuweisung von Werten für die Attribute
p1.name = "Müller";
p1.vorname = "Andreas";
p1.jahrgang = 1960;
p1.beruf = "Maurer";
}
}
Unterschiede zwischen primitiven Datentypen und Referenztypen
Wenn eine Variable ein Objekt verwalten soll, dann nennt man diese Variable eine Referenzvariable. Bei der Deklaration gibt es zwischen Referenztypen und primitiven
Datentypen (int, char, double, etc.) keine Unterschiede. Bei der Initialisierung hingegen gibt es Unterschiede. Referenztypen halten Referenzen auf Objekte und bieten ein
Mittel, um auf die Objekte zuzugreifen, die irgendwo im Speicher abgelegt sind, ähnlich
einem Link oder einer Verknüpfung. Die Speicherorte selbst sind für das Programmieren
irrelevant.
81
Beispiel: Angenommen, wir möchten bei unserem Beispiel eine neue Person p2 erzeugen
(dies würde dem Einfügen einer neuen Zeile in der Tabelle entsprechen), reicht es nicht,
die Referenz zu kopieren. Folgendes Beispiel demonstriert, weshalb wir zunächst per
new-Operator ein neues Objekt erzeugen müssen, bevor wir die Werte der Variablen neu
setzen können.
Gegeben seien:
int wert = 8;
Person p1 = new Person();
Der aktuelle Speicher präsentiert sich wie in Abbildung 5.1:
wert
8
p1
Referenz
name
null
vorname
null
jahrgang
0
beruf
null
Abbildung 5.1: Speicher nach Erzeugung eines neuen Objektes.
Im Speicher des primitiven Datentyps befindet sich eine 8, die zum Variablennamen wert
gehört. Beim Referenztyp befindet sich eine Referenz auf ein Personenobjekt, welche
unter dem Variablennamen p1 erreichbar ist. Im Speicherbereich der Person ist zu sehen,
dass nur beim Jahrgang ein Wert gespeichert ist. Dies ist so, weil String ebenfalls eine
Klasse bezeichnet (beachten Sie die Grossschreibung). Ist noch nicht bestimmt, auf
welchen Speicherbereich sich eine Referenzvariable bezieht, wird null initialisiert.
Mit folgenden Zeilen werden die Attribut-Werte zugewiesen:
p1.name = "Meier";
p1.vorname = "Hans";
p1.jahrgang = 1960;
p1.beruf = "Maler";
Der Speicher ändert sich wie in Abbildung 5.2 dargestellt.
Nun führen wir folgende Zeilen aus:
int wert2 = wert;
Person p2 = p1;
Der Speicher präsentiert sich nun wie in Abbildung 5.3 dargestellt.
82
wert
8
Referenz
p1
Referenz
name
Referenz
vorname
jahrgang
Meier
Hans
1960
Referenz
beruf
Maler
Abbildung 5.2: Speicher nach Zuweisung der Attributswerte.
wert
8
Referenz
p1
nz
wert2
8
Referenz
name
re
fe
Re
Referenz
vorname
jahrgang
Meier
Hans
1960
Referenz
beruf
Maler
p2
Abbildung 5.3: Speicher nachdem p2 mit p1 initalisiert wurde.
Beim primitiven Datentyp wird neuer Speicher bereitgestellt, der Wert wird kopiert. Bei
der Referenzvariablen wird die Referenz kopiert, nicht aber das ganze Objekt. Werden
nun die folgenden Zeilen ausgeführt, sieht der Speicher anschliessend wie in Abbildung
5.4 aus.
wert2 = 10;
p2.jahrgang = 1967;
wert
8
Referenz
p1
wert2
10
Referenz
name
f
Re
z
en
er
Referenz
vorname
jahrgang
beruf
Meier
Hans
1967
Referenz
Maler
p2
Abbildung 5.4: Speicher nachdem das Attribut p2 verändert wurde.
Folgende Tabelle fasst die Unterschiede zwischen Referenztypen und primitive Typen
83
zusammen.
Primitive Datentypen
Referenztypen
Anzahl
Umfasst die Typen boolean,
char, byte, short, long, float und
double
Die Anzahl von Referenztypen
ist unbegrenzt, da diese vom
User definiert werden.
Default-Wert
0
null
Speicherort
Der Speicherort speichert die
tatsächlichen Daten, die der
primitive Typ enthält.
Der Speicherort speichert eine
Referenz auf die Daten.
Zuweisung an eine an- Wird der Wert eines primitiven
dere Variable
Typs einer anderen Variablen
zugewiesen, wird eine Kopie erstellt.
Wird einem Referenztyp ein anderer Referenztyp zugewiesen,
zeigen beide auf das gleiche Objekt.
Übergabe an Methode
84
Wird einer Methode ein pri- Wird eine Methode ein Objekt
mitiver Typ übergeben, wird übergeben, kann die aufgerufenur eine Kopie des primitiven ne Methode den Inhalt des ObWerts übergeben. Die aufgeru- jekts ändern, nicht aber seine
fene Methode hat keinerlei Zu- Adresse
griff auf den ursprünglichen primitiven Wert und kann ihn deswegen nicht ändern. Die aufgerufene Methode kann den kopierten Wert ändern.
Selbstständiger Teil
5.3 Hotel-Verwaltung
5.3.1 Aufgabenstellung
In dieser Aufgabe sollen Sie Hotel-Objekte in einem Ort inklusiv Buchungsmöglichkeit
erstellen.
Die Klasse Hotel soll aus folgenden Attributen und Methoden bestehen:
Hotel
int stockwerke
int zimmerProStockwerk
int belegung
int getZimmer()
void einchecken()
void auschecken()
void printInfo()
Eigenschaften (Attribute):
• stockwerke: Hier wird angegeben, wie viele Stockwerke das Hotel hat.
• zimmerProStockwerk: Hier wird angegeben, wie viele Zimmer sich auf einem
Stockwerk befinden.
• belegung: In diesem Attribut wird gespeichert, wie viele Zimmer aktuell belegt
sind.
85
Methoden:
• int getZimmer(): In dieser Methode wird zurückgegeben, wie viele Zimmer im
Hotel zur Verfügung stehen.
• void einchecken(): In dieser Methode wird der Wert der Belegung um eins
erhöht.
• void auschecken(): In dieser Methode wird der Wert der Belegung um eins
dekrementiert.
• void printInfo(): Mit dieser Methode wird auf der Konsole ausgegeben, wie
viele Zimmer das Hotel hat, und wie viele davon aktuell belegt sind. Verwenden
Sie dazu die Methode getZimmer().
5.3.2 Zwischenschritte
• Erstellen Sie die Klasse Hotel mit den angegebenen Eigenschaften.
• Erstellen Sie eine Klasse Ferienort mit main-Methode sowie mindestens 3 Hotels.
Setzen sie die Eigenschaften der Hotels.
• Checken Sie einige Personen ein und wieder aus, und geben Sie die Informationen
zu den Hotels aus. Die Ausgabe könnte z.B. wie folgt aussehen:
Hotel Edelweiss
5 von 40 belegt
Hotel Astoria
4 von 200 belegt
Hotel Alpenblick
10 von 30 belegt
5.3.3 Erweiterungen
• Ändern Sie die Methode einchecken so, dass zurückgegeben wird, ob im Hotel
noch Platz ist. Geben Sie zurück, ob die Person einchecken konnte oder nicht (ja
= true, nein = false).
• Ändern Sie die Methode auschecken analog, dass keine Personen mehr auschecken können, sobald keine Personen mehr im Hotel sind.
86
Herunterladen