Folien ohne Skriptkommentare

Transcription

Folien ohne Skriptkommentare
Grundlagen
Programmierung
Prof. Dr. Stephan Kleuker
Hochschule Osnabrück
Grundlagen Programmierung
Stephan Kleuker
1
Ich
• Prof. Dr. Stephan Kleuker, geboren 1967, verheiratet, 2
Kinder
• seit 1.9.09 an der HS, Professur für Software-Entwicklung
• vorher 4 Jahre FH Wiesbaden
• davor 3 Jahre an der privaten FH Nordakademie in Elmshorn
• davor 4 ½ Jahre tätig als Systemanalytiker und
Systemberater in Wilhelmshaven
• [email protected], Raum SI 0109
Grundlagen Programmierung
Stephan Kleuker
2
Studium (meine Sicht) (1/2)
• Sie haben ersten wichtigen Schritt geschafft, sich für ein
praxisnahes, qualitativ hochwertiges Studium entschieden
• Sie haben sich für einen recht schweren, sehr interessanten,
sehr abwechslungsreichen und prägenden Bildungsweg
entschieden
• Studium an der Hochschule: Konzepte, Vorgehensweisen,
weniger Visionen, mehr Zusammenhang zur Praxis
• Versuchen, frühzeitig mit der Praxis in Kontakt zu kommen
Grundlagen Programmierung
Stephan Kleuker
3
Studium (meine Sicht) (2/2)
• Die nächsten drei+x Jahre werden prägend sein, nicht so wie
die vorherigen Jahre, aber mehr als alle folgenden
• Sie werden viele Hochs und einige Tiefs erleben
• Lernen Sie, in Gruppen zu arbeiten
• Machen Sie sich nichts vor, seien aber nicht zu selbstkritisch
• Menschen verändern sich
• Versuchen sie, Ratschläge anzunehmen und zu suchen
Grundlagen Programmierung
Stephan Kleuker
4
Ablauf
• 4h Vorlesung + 4h Praktikum = 10 CP d. h. etwa 300
Arbeitsstunden
• Praktikum :
– Anwesenheit = (Übungsblatt vorliegen + Lösungsversuche
zum vorherigen Aufgabenblatt)
– Übungsblätter mit Punkten (  200), zwei Studis als Team
– Praktikumsteil mit 160 oder mehr Punkten bestanden
• Prüfung: Klausur recht kurz nach der Vorlesungszeit
• Folienveranstaltungen sind schnell, bremsen Sie mit Fragen
• von Studierenden wird hoher Anteil an Eigenarbeit erwartet
Grundlagen Programmierung
Stephan Kleuker
5
Vorlesung
• Interaktiver Unterricht
• vorbereite Folien und Beispielvorführungen am Rechner
• Sie können, sollen und müssen Fragen stellen und Fragen
beantworten
• Vorlesungsteilnahme ist freiwillig; hilft auch, Lernen zu
strukturieren
• falls man nicht zur Vorlesung kommt:
– unbedingt Folien nacharbeiten und Fragen im Praktikum
oder am Anfang der nächsten Vorlesung stellen
– Folien reichen nicht! Vertiefende Literatur parallel lesen
(soll das ersetzen, was Dozent zu den Folien erzählt)
Grundlagen Programmierung
Stephan Kleuker
6
Praktikum
• vorgegebene Aufgaben in einem vorgegebenen Zeitraum
bearbeiten
• Aufgaben bereiten Vorlesungsstoff nach, vertiefen ihn,
ergänzen ihn und fordern selbstständige Einarbeitung
• im Praktikum werden neue Aufgaben vorgestellt
• im Praktikum werden Lösungen der Aufgaben
abgenommen (oder Verbesserungen gefordert)
• im Praktikum sind immer zwei betreuende Personen
anwesend, die man befragen kann
• im Praktikum herrscht Anwesenheits- und Aktivitätspflicht
(Bearbeitung der Aufgaben, daddeln im Netz ist keine
Anwesenheit)
• Gesamtaufwand für Praktikumsaufgaben für
durchschnittlich guten Studierende: 8+x h pro Woche !!
Grundlagen Programmierung
Stephan Kleuker
7
Praktikumsorganisation
• Anmeldung über Stud.IP für Vorlesung und die Praktika (nur
Vorlesungsordner relevant)
• Informationen auch auf (Stud.IP ist Hauptquelle):
http://home.edvsz.hs-osnabrueck.de/skleuker/WS11_GP/index.html
• Aufgabenblätter online bis Freitag KW x
• Vorstellung und betreute Bearbeitung in KW x+1
• Abnahme im ersten Praktikum KW x+2 (zweites Praktikum
für restliche Abnahmen und geforderte Nacharbeiten)
Grundlagen Programmierung
Stephan Kleuker
8
Hardware / Software
Software
• Java SE in der Version 6
(http://www.oracle.com/technetwork/java/javase/downloa
ds/jdk-6u27-download-440405.html)
• Entwicklungsumgebung BlueJ 3.0.5
(http://www.bluej.org/download/download.html)
• Programm für Screenshots, z. B. FastStone Capture 5.3
Hardware
• im EDVSZ stehen Rechner zur Verfügung, im Praktikum
"virtuelle Rechner", großer Vorteil; Rechner immer mit
Internet-Verbindung nutzbar (https://sgd-02.edvsz.hsosnabrueck.de/)
• es dürfen eigene Rechner genutzt werden
Grundlagen Programmierung
Stephan Kleuker
9
Klausur
• ausgewählte vergleichbare Aufgaben in Praktika behandelt
• Orientierung an Beispielklausur möglich
• selbständiges Erklären von Fachbegriffen
• was passiert in gegebenen Programmfragmenten
• programmieren auf dem Papier
Grundlagen Programmierung
Stephan Kleuker
10
Verhaltenscodex
•
•
•
•
Rechner sind zu Beginn der Veranstaltung aus
Handys sind aus
Wir sind pünktlich
Es redet nur eine Person zur Zeit
• Sie haben die Folien zur Kommentierung in der Vorlesung
vorliegen, zwei Tage vor VL abends mit Aufgaben im Netz,
Aufgabenzettel liegen in der Übung vor (Ihre Aufgabe)
http://www.edvsz.hs-osnabrueck.de/skleuker/index.html
• Probleme sofort melden
• Wer aussteigt, teilt mit, warum
Grundlagen Programmierung
Stephan Kleuker
11
Voraussetzungen
• außer Hochschulreife, keine
beinhaltet
• Fähigkeit, selbständig den Lernprozess zu organisieren
• Fähigkeit zur Gruppenarbeit
• Fähigkeit, Zeiten von konzentrierten Arbeiten und freier
Zeitgestaltung zu trennen und zu koordinieren
• Fähigkeit zur kritischen Selbstreflexion zum erreichten
Lernstand
• Kopieren ist nicht Kapieren
• Vorlesungen und Praktika als Lernunterstützung zu sehen
(Sie sind für Lernerfolg allein verantwortlich)
• Umgang mit Windows-PC
Grundlagen Programmierung
Stephan Kleuker
12
Ziele
• Konzepte der objektorientierten Programmierung verstehen
und selbstständig nutzen
• Eigenständig einfache OO-Programme entwickeln, Fehler
beseitigen und längerfristig wartbar machen
• Erlernen eines systematischen inkrementellen Prozesses zur
Entwicklung größerer Programme
• Erlernen und Anwenden der Fachbegriffe rund um die
Programmierung
• Verständnis für die grundsätzlichen Schritte vom
Programmcode zur Ausführung auf dem Rechner
Grundlagen Programmierung
Stephan Kleuker
13
Literatur
• Vorlesung orientiert sich nicht genau an einem Buch
sicherlich sehr hilfreich:
• David J. Barnes , Michael Kölling, Java lernen mit BlueJ: Eine
Einführung in die objektorientierte Programmierung, 4.
Auflage, Pearson Studium, 2009
ab Mitte des Semesters hilfreich:
• Cornelia Heinisch, Frank Müller-Hofmann, Joachim Goll, Java als erste
Programmiersprache, 6. Auflage, Vieweg+Teubner, 2011
• Sven Eric Panitz, Java will nur spielen, 2. Auflage, Vieweg+Teubner, 2011
• Christian Ullenboom, Java ist auch eine Insel, 9. Auflage, Galileo
Computing, 2011 (auch: http://openbook.galileocomputing.de/javainsel/)
• Guido Krüger, Thomas Stark, Handbuch der Java-Programmierung, 6.
Auflage, Addison-Wesley, 2009 (5. Auflage auch unter
http://www.javabuch.de/download.html)
• Dietmar Abts, Grundkurs JAVA: Von den Grundlagen bis zu Datenbank
und Netzanwendungen, Vieweg+Teubner, 2010
Grundlagen Programmierung
Stephan Kleuker
14
Programmiersprache
• Programmiersprache ist Hilfsmittel beim programmieren
lernen
• hier kein Java-Kurs, sondern Programmierkurs mit Java
• keine auch nur annähernd vollständige Einführung in Java
(für Expertise wichtige Programmkonstrukte fehlen)
• Konzept:
– erstes Semester grundlegende Ideen
– zweites Semester, weitere Ideen mit neuen
Programmiersprachen (C und C++)
• Ziel: ab ende des zweiten Semesters grundsätzlich in der
Lage sich in fehlende Sprachkonstrukte und andere ähnlich
strukturierte Programmiersprachen einzuarbeiten (5. + 6.
Semester: Projekte und Bachelor-Arbeiten auch in C#)
Grundlagen Programmierung
Stephan Kleuker
15
Hintergrund von Programmiersprachen (Ausschnitt)
Sprache
Fortran
Cobol
Smalltalk
C
seit
basiert auf
1954
1959
1972 Simula
1972 Algol
Anwendungsgebiet
math. Berechnungen
Banken, Versicherungen
Einführung Objektorientierung
Betriebssysteme, HW-nahe
Programmierung
Objective C 1981 C, Smalltalk jetzt: Apple-Apps
C++
1983 C
C mit OO, Graphik,
Bildverarbeitung, …
PHP
1995 C, Pascal,
einfache kleine Webgehacke
Applikationen
Java
1995 Smalltalk,
große sklalierbare WebC++
Applikationen (ERP),
Standardprogramme
C#
2001 Java, C
Java von Microsoft
Grundlagen Programmierung
Stephan Kleuker
16
Inhalt (Planung) (1/2)
Programmierung
Objekt
Klasse
Klassen in Java
Konstruktor
Objektmethoden
Debugger
Objektweitergabe
Alternative
equals
Strings
Schleife
switch
Schleife 2
Algorithmus
geschachtelte Schleifen
Grundlagen Programmierung
Iterator
for
Unit Test
iterativ inkrementelle
Entwicklung
Vererbung
Überschreiben
dynamische Polymorphie
casten
abstrakte Klasse
Interface
Kommentare
Mehrfachvererbung
Klasse Object
Collection Framework
Array
Stephan Kleuker
17
Inhalt (Planung) (2/2)
Exception
Klassenvariablen und Klassenmethoden
Start von Java-Programmen
Entwicklungsumgebungen
Pakete
Einige Realitätsbeichten
Programmieren ohne echte Klassen
Laden und Speichern
Aufzählungen
Frames, Knöpfe und Ereignisbehandlung
Layout, hierarchischer GUI-Aufbau
Rundflug über GUI-Bausteine
Grundlagen Programmierung
Stephan Kleuker
18
Programmierung
Grundlagen Programmierung
Stephan Kleuker
19
Worum geht es bei der Programmierung
• Menschen haben Maschinen erfunden, um sich das Leben
leichter zu machen und Geld zu verdienen
• Computer wurden entwickelt als flexible Maschinen, die
Rechenaufgaben lösen und andere Maschinen steuern
können
• Computer sind dumm, ihnen muss beigebracht werden, was
sie wann zu tun haben
• Dieses „was wann“ heißt Computer-Programm
• Computer-Programme müssen entwickelt werden, dies ist
ein Ziel dieser Veranstaltung
• Zentral für die Programmierung ist das Vorgehen zur
Entwicklung einer Lösung, eines Algorithmus
Grundlagen Programmierung
Stephan Kleuker
20
Worum geht es in Programmen
• Es werden Informationen verwaltet, d. h. angelegt, gesucht
und gelesen, verändert und gelöscht
• Es werden neue Ergebnisse berechnet, indem vorhandene
Informationen genutzt werden
• Beispiel: Studierende in einer Studierendenverwaltung,
Prognose der Studienbeiträge der nächsten Semester
• Informationen müssen in das System, z. B. Studierende in den
Rechner
• gesucht ist ein Modell der Realität, so dass gewünschte
Berechnungen möglich werden
• man kann relevante Daten des Studierenden-Modells
festlegen (Vorname, Nachname, Geburtstag, Studiengang, …)
• man kann Hilfsdaten einführen: Matrikelnummer
Grundlagen Programmierung
Stephan Kleuker
21
Wie finde ich die Programmieraufgabe
Anforderungsanalyse
• systematische Analyse der Kundenherausforderungen
• Strukturierung der gewünschten Funktionalität in
Hauptaufgaben
• Klärung der relevanten Informationen zur Modellierung
• Klärung vieler Randbedingungen
• genauer: siehe Vorlesung Objektorientierte Analyse und
Design
• für diese Veranstaltung werden die Aufgabenstellungen als
klar gegeben angenommen (große Vereinfachung)
Grundlagen Programmierung
Stephan Kleuker
22
Wie fange ich die Programmierung an
• zunächst klären, ob Aufgabenstellung verstanden
• dann Entwicklungsplanung; typisch inkrementell
– Aufteilung in Teilaufgaben
– Für jede Teilaufgabe das erwünschte typische Verhalten
realisieren (z. B. Daten eines neuen Studierenden
eintragen und speichern)
– Über alle möglichen Alternativen beim Verhalten
nachdenken und diese schrittweise einbauen (z. B.
Abbruch der Dateneintragung, Fehler beim Speichern)
• Grundlage ist dabei ein Modell der gewünschten Daten, die
für die Teilaufgabe benötigt werden
• Bei Datenmodellen spricht man oft von Objekten
(Individuen mit konkreten Eigenschaften)
Grundlagen Programmierung
Stephan Kleuker
23
Objekt
Grundlagen Programmierung
Stephan Kleuker
24
Was heißt Objektorientierung
• in Programmen werden Daten verarbeitet und neue
berechnet
• Daten gehören zu Objekten
• Objekte sind damit eine Grundstruktur von Programmen
Objekt:
• eindeutig einzeln identifizierbar
• besitzt konkrete Eigenschaften, die es charakterisieren
• !!! Objekte können die gleichen Eigenschaften haben und
trotzdem unterschiedlich sein (dasselbe oder das Gleiche,
Sie besuchen dieselbe Veranstaltung, Sie sitzen auf gleichen
Stühlen)
Grundlagen Programmierung
Stephan Kleuker
25
Objekt Adresse
• jedes Haus hat eine eindeutige Adresse
Eigenschaften:
zwei Beispielobjekte:
• Straße
Barbarastr.
• Hausnummer
16
• Postleitzahl
49076
• Stadt
Osnabrück
• Bundesland
Niedersachsen
Barbarastr.
16
79106
Freiburg
Baden-Württemberg
• es kann optionale Eigenschaften geben, bzw. Eigenschaften,
die nur im bestimmten Kontext interessieren
• (Stockwerk)
• (Grundstücksgröße)
Grundlagen Programmierung
Stephan Kleuker
26
Objekt Datum
•
•
•
•
•
Identifiziert einen eindeutigen Tag
Eigenschaften:
zwei Beispielobjekte:
Tag
31
29
Monat
12
2
Jahr
1999
2100
• Man spürt den Wunsch, die Gültigkeit von Objekten zu
prüfen (-> später)
Grundlagen Programmierung
Stephan Kleuker
27
Objekt Person
• jede(r) ein Individuum
Eigenschaften:
zwei Beispielobjekte:
• Vorname
Stephan
• Nachname
Dr. Kleuker
• Geburtsort
Wilhelmshaven
• Geburtsland
Deutschland
• Adresse
Grundlagen Programmierung
Stephan Kleuker
Eva
Mustermann
Wladiwostok
Russland
28
Objekt Student
• jede(r) ein Individuum
Eigenschaften:
zwei Beispielobjekte:
• Vorname
Stephan
• Nachname
Kleuker
• Geburtsort
Wilhelmshaven
• Geburtsland
Deutschland
• Adresse
…
• eingeschrieben am 14.9.1986
• Studiengang
Informatik
• Matrikelnummer 368849
Grundlagen Programmierung
Stephan Kleuker
Eva
Mustermann
Wladiwostok
Russland
…
29.7.2011
Informatik
424142
29
Objekt Praktikum
• individuell durch seine Eigenschaften
Eigenschaften:
Beispielobjekt:
• Modul
Grundlagen Programmierung
• Semester
Wintersemester 2011
• Veranstalter
Stephan Kleuker
• Mitarbeiter
Friedhelm Tappe
• Termine
[Mo 6:30-8:00, Fr 18:30-20:00]
• Teilnehmer
[Eva Mustermann (424142), Kevin Meier
(424345), Jaqueline Schmidt (422323)]
• man erkennt, dass Eigenschaften mehrwertig sein können
Grundlagen Programmierung
Stephan Kleuker
30
Erkenntnisse über Objekte
• können große Anzahl von Eigenschaften haben
• relevante Eigenschaften hängen vom Anwendungsbereich
ab (Erkennung durch Haarfarbe für Studierende irrelevant)
• Eigenschaften können optional sein
• Eigenschaften können wieder selbst Objekte sein
• kann unterschiedliche Objektarten mit vielen
Gemeinsamkeiten geben
• Eigenschaft kann eine Sammlung von Werten sein, die leer
sein kann
Person
Student
Praktikum
Grundlagen Programmierung
Adresse
Stephan Kleuker
31
Klasse
Grundlagen Programmierung
Stephan Kleuker
32
Der Begriff der Klasse
• Objekte haben durch ihre Eigenschaften gleichartige Struktur
• eine Klasse fasst diese Struktur zusammen und benennt die
Eigenschaften
Adresse
strasse
hausnummer
postleitzahl
stadt
bundesland
Praktikum
modul
semester
veranstalter
mitarbeiter
termine
teilnehmer
• strasse ist eine Objektvariable (Name einer Eigenschaft, die
für ein konkretes Objekt eine konkreten Wert annimmt)
• Objektvariable = Instanzvariable = Attribut
Grundlagen Programmierung
Stephan Kleuker
33
Wie finde ich die Objektvariablen
• Zentrale Teilaufgabe ist das Verstehen der Kundenwünsche
• Das Verfahren zum Finden der Wünsche heißt
Anforderungsanalyse (Regel: garbage in, garbage out)
• Ansätze zur Anforderungsanalyse werden in der Vorlesung
"Objektorientierte Analyse und Design" studiert
• Basierend auf Gesprächen, Texten, Erfahrungen, … werden
u.a. die projektrelevanten Objekte und ihre Objektvariablen
als ein Analyseergebnis bestimmt
Grundlagen Programmierung
Stephan Kleuker
34
Zusammenhang zwischen Klasse und Objekten
• Objekte haben eine Klasse als Grundlage
• Klassen sind der Rahmen (das Formular), das durch Objekte
individuell gefüllt wird
• Objekte weisen den Objektvariablen konkrete Werte zu
• Darstellung <Objektname>:<Klasse>
ich:Adresse
strasse= „Barabarastr.“
hausnummer= 16
postleitzahl= 49076
stadt= „Osnabrück“
bundesland=„Nds“
Grundlagen Programmierung
nichtIch:Adresse
strasse= „Barabarastr.“
hausnummer= 16
postleitzahl= 79106
stadt= „Freiburg“
bundesland=„B-W“
Stephan Kleuker
35
Typen : Integer
• Variablen werden in Programmiersprachen oft Typen
zugeordnet
• Ein Typ definiert, welche Werte erlaubt sind und wie diese
Werte dargestellt werden (korrekte Syntax)
• Beispieltyp: Integer für ganze Zahlen
– genauer: Wertebereich -231 bis 231-1
– Folge von einzelnen Ziffern, beginnend mit einer Zahl
ungleich 0 [stimmt nicht ganz, siehe später]
• Man kann Variablen vom Typ deklarieren
Integer tag
• Man kann Variablen erlaubte Werte zuweisen
tag = 30
• Hinweis: Gibt auch Programmiersprachen, die ohne Typen
auskommen
Grundlagen Programmierung
Stephan Kleuker
36
Nutzung von Typen
• JEDER Objektvariablen wird ein Typ zugeordnet
• Typen werden in der Klassendefinition festgehalten
class Datum
Integer
Integer
Integer
}
{
tag;
monat;
jahr;
• Typ kann diskutabel sein (möchte man den Monatsnamen?)
• Für später: Jede Klasse definiert wieder einen Typen
Grundlagen Programmierung
Stephan Kleuker
37
Klassen in Java
Grundlagen Programmierung
Stephan Kleuker
38
Klassen in Java (Syntax) (1/3)
class Datum
Integer
Integer
Integer
}
{
tag;
monat;
jahr;
• Java hat Schlüsselworte (z. B. class), diese dürfen z. B. nicht
als Variablennamen genutzt werden
• viele Programmfragmente stehen in geschweiften oder
runden Klammern (immer beide Klammern eintippen, dann
füllen)
• geschweifte Klammer am Anfang und am Ende der
Klassendefinition
• Befehle enden mit einem Semikolon
• Objektvariable: <Typ> <Name>;
Grundlagen Programmierung
Stephan Kleuker
39
Klassen in Java (Syntax) (2/3)
Variablen- und Klassennamen
• beginnen mit einem Groß- oder Kleinbuchstaben (keine
Umlaute oder Sonderzeichen)
• werden gefolgt von beliebig vielen Groß- und
Kleinbuchstaben, Ziffern oder _
keine Syntax, aber Konvention
• Klassennamen groß, typisch Einzahl (Student nicht Studenten)
• Objektvariablen klein, vollständige Worte, "sprechend"
• bei zusammengesetzten Namen werden zweite Worte direkt
hinten an gefügt und erster Buchstabe großgeschrieben, z. B.
eingeschriebenAm, richtig: starttermin falsch: startTermin
• eine Objektvariable pro Zeile deklarieren
Grundlagen Programmierung
Stephan Kleuker
40
Klassen in Java (Syntax) (3/3)
• Platzierung von Klammern
class Datum
Integer
Integer
Integer
}
{
tag;
monat;
jahr;
• oder
class Datum
{
Integer tag;
Integer monat;
Integer jahr;
}
• auf Folien obige Variante (spart eine Zeile)
• Einrückungen haben keine semantische Bedeutung
Grundlagen Programmierung
Stephan Kleuker
41
Syntaxprüfung durch Compiler (genauer Parser)
• Programmcode muss so übersetzt werden, dass der
Computer Befehle verarbeiten kann (-> genauer später),
Prozess heißt kompilieren (übersetzen)
• Vor dem Kompilieren (genauer: erster Schritt dabei), wird
die Syntax des Programms geprüft (geparst)
• Bei fehlerhafter Syntax wird mehr oder minder genaue
Fehlermeldung ausgegeben
• Kompilierung findet typischerweise in einer
Entwicklungsumgebung statt (wir nutzen zunächst BlueJ)
Grundlagen Programmierung
Stephan Kleuker
42
Erfolgreiche Kompilierung in BlueJ
Grundlagen Programmierung
Stephan Kleuker
43
Fehlerhafte Kompilierung in BlueJ
Grundlagen Programmierung
Stephan Kleuker
44
Woher kommen die Klassen
• Java bietet bereits viele Klassen als Typen an, in der
sogenannten Klassenbibliothek
• Das Wissen über existierende Klassen ist Teil der
Programmiererfahrung
• In der Programmierausbildung werden teilweise
existierende Klassen neu programmiert um Erfahrungen zu
sammeln
• Übersicht bietet u. a. Java Dokumentation (lokal
herunterladbar) oder auch
http://download.oracle.com/javase/6/docs/api/index.html
• Woher die Objekte kommen bleibt noch unklar
Grundlagen Programmierung
Stephan Kleuker
45
Wichtige Klassen (Ausschnitt)
Klasse
Integer
Double
String
Boolean
Long
ArrayList< Typ >
ArrayList<String>
Grundlagen Programmierung
Nutzung
ganze Zahlen
Fließkommazahlen
Texte, Werte stehen in Hochkommata
Wahrheitswerte, false, true
ganze Zahlen, größerer Zahlenbereich (mehr
Speicher)
Sammlung von beliebig vielen Objekten eines
Typs; nicht einfach hinschreibbar;
merkt sich die Reihenfolge
beliebig viele Texte, z. B. ["Hai", "Wo", "Da"]
Stephan Kleuker
46
Ordnung in der Klassenbibliothek
• ähnlich wie große Dateimengen in Ordnern und
Unterordnern strukturiert werden, werden auch Klassen in
Ordnerstrukturen thematisch abgelegt
• Ordner heißen in Java Pakete
• Beispiel: Die Klasse ArrayList liegt im Paket java.util
• Damit Klasse aus Paket genutzt werden kann, muss die
Klasse im Quellcode bekannt gemacht werden, vor der
Klasse steht dann
import java.util.ArrayList
• andere Basisklassen wie Integer und String liegen in
java.lang (da häufig genutzt, müssen die Klassen nicht
importiert werden)
Grundlagen Programmierung
Stephan Kleuker
47
Erstellung der Klasse Adresse (1/2)
ich:Adresse
strasse= „Barabarastr.“
hausnummer= 16
postleitzahl= 49076
stadt= „Osnabrück“
bundesland=„Nds“
Grundlagen Programmierung
• jeweils genau einen Typ
überlegen
• Ist hausnummer vom Typ
Integer?
Nein, Nummern wie 16a
wären syntaktisch nicht
korrekt
• Ist Postleitzahl vom Typ
Integer?
Nein, führende Nullen nicht
möglich
04356 Leipzig
• Fazit: Bild links ist falsch
Stephan Kleuker
48
Erstellung der Klasse Adresse (2/2)
Grundlagen Programmierung
Stephan Kleuker
49
Klasse Student
Grundlagen Programmierung
Stephan Kleuker
50
fehlerhafte Klasse Praktikum
Grundlagen Programmierung
Stephan Kleuker
51
korrigierte Klasse Praktikum
Grundlagen Programmierung
Stephan Kleuker
52
Seltener genutzte Variante ohne import
class Praktikum {
String modul;
String semester;
String veranstalter;
String mitarbeiter;
java.util.ArrayList<String> termine;
java.util.ArrayList<Student> teilnehmer;
}
Grundlagen Programmierung
Stephan Kleuker
53
Projektübersicht in BlueJ
Grundlagen Programmierung
Stephan Kleuker
54
Konstruktor
Grundlagen Programmierung
Stephan Kleuker
55
Wie erstellt man Objekte
• mit den bisher erstellten Code kann man genau genommen
nichts anfangen, da Klassen nur Rahmen sind
• zur Erzeugung eines Objektes muss es die Möglichkeit
geben zu sagen: "Erzeuge mir ein Objekt dieser Klasse"
• gut wäre: zusätzlich mitteilen, welche Werte die
Objektvariablen annehmen sollen
• Lösung heißt Konstruktor
Grundlagen Programmierung
Stephan Kleuker
56
Beispiel eines Konstruktors
class Datum{
Integer tag;
Integer monat;
Integer jahr;
Datum (Integer anInt1, Integer anInt2, Integer anInt3){
this.tag = anInt1;
this.monat = anInt2;
this.jahr = anInt3;
}
}
Grundlagen Programmierung
Stephan Kleuker
57
Aufbau eines Konstruktors
• hat exakt gleichen Namen wie Klasse
• hat immer Parameterliste in runden Klammern
• Parameterliste besteht aus mit Komma separierten
Parametern
• Parameter hat Aufbau: <Typ> <Parametername>
• im Konstruktorrumpf steht ein kleines Programm mit
Zuweisungen
• Zuweisung: <Variable> = <Ausdruck>
• Der Variablen auf der linken Seite wird der Wert der
Berechnung des Ausdrucks der rechten Seite zugewiesen
• Zugriff auf Objektvariablen über this.<Variablenname>
• this ist "dieses Objekt", aus Objektsicht "ich"
Grundlagen Programmierung
Stephan Kleuker
58
Parameter können beliebige Namen haben
Datum (Integer tag, Integer monat, Integer jahr){
this.tag = tag;
this.monat = monat;
this.jahr = jahr;
}
• wenn Parameter gleiche Namen wie Objektvariablen haben,
ist ihr Sinn aus der Signatur (erste Zeile des Konstruktors)
ablesbar
• mit this wird der Bezug auf das gerade betrachtete Objekt
deutlich
• Syntaxregeln für Variablennamen wieder beachten
Grundlagen Programmierung
Stephan Kleuker
59
Nutzung eines Konstruktors direkt in BlueJ
Grundlagen Programmierung
Stephan Kleuker
60
Analyse eines Objekts in BlueJ
Grundlagen Programmierung
Stephan Kleuker
61
Erstellung eines Objekts im Code Pad – Variante 1/3
<Return gedrückt>
kleines Objekt am Rand
kleines rotes Objekt am
Rand auf Objektleiste
ziehen
Objekt benennen und wie
vorher analysieren
Grundlagen Programmierung
Stephan Kleuker
62
Erstellung eines Objekts im Code Pad – Variante 2/3
• Anlegen einer lokalen Variable namens rente (wieder mit Typ)
• Zeilenende mit Semikolon, mit Return in nächste Zeile
• Objektname ohne Semikolon eintippen (Return)
• gefordertes Objekt wird rechts am Rand angezeigt
• Bearbeitung wie vorher
Grundlagen Programmierung
Stephan Kleuker
63
Klasse kann mehrere Konstruktoren haben
Datum (Integer tag, Integer monat, Integer jahr){
this.tag = tag;
this.monat = monat;
this.jahr = jahr;
}
Datum (Integer jahr){
this.tag = 1;
this.monat = 1;
this.jahr = jahr;
}
• Konstruktoren müssen nur andere Parameterlisten (Typen,
Variablennamen reichen nicht) haben
Grundlagen Programmierung
Stephan Kleuker
64
Konstruktoren nutzen Konstruktoren
• nulltes Informatikgebot: Schreibe niemals Code doppelt
• Konstruktor kann anderen Konstruktor nur in erster Zeile
aufrufen, Variante der letzten Folie:
Datum (Integer tag, Integer monat, Integer jahr){
this.tag = tag;
this.monat = monat;
this.jahr = jahr;
}
Datum (Integer jahr){
this(1, 1, jahr);
}
Grundlagen Programmierung
Stephan Kleuker
65
gleiche Parameter(typ)liste ist Fehler
Grundlagen Programmierung
Stephan Kleuker
66
Objekte in Konstruktoren nutzen (1/2)
• Erzeugung von Integer-Objekten in Code Pad (bei
Übertragung nach links werden gleiche Namen verwendet)
Grundlagen Programmierung
Stephan Kleuker
67
Objekte in Konstruktoren nutzen (2/2)
Grundlagen Programmierung
Stephan Kleuker
68
Unvollständige Initialisierung
• Was passiert, wenn Objektvariable keinen Wert bekommt
• Variable hat keinen, genauer undefinierten Wert, nullReferenz oder null-Pointer genannt (auch null-Wert)
Datum(){
this.tag = 1;
}
Grundlagen Programmierung
Stephan Kleuker
69
Null-Wert selbst zuweisen
• statt impliziter Zuweisungen (Ausnutzen, was standardmäßig
passiert), besser immer explizit zuweisen
Datum(){
this.tag = 1;
this.monat = null;
this.jahr = null;
}
Grundlagen Programmierung
Stephan Kleuker
70
Variante: Startwerte bei Deklaration zuweisen (1/2)
class Adresse{
String strasse;
String hausnummer;
String postleitzahl = "49076";
String stadt = "Osnabrueck";
String bundesland = "Nds";
Adresse(String strasse, String hausnummer){
this.strasse = strasse;
this.hausnummer = hausnummer;
}
}
Grundlagen Programmierung
Stephan Kleuker
71
Variante: Startwerte bei Deklaration zuweisen (2/2)
Grundlagen Programmierung
Stephan Kleuker
72
Klasse ohne Konstruktor (gibt es nicht)
• Wird kein Konstruktor für eine Klasse X angegeben, existiert
automatisch (nicht sichtbar) der Default-Konstruktor
X() {
}
• Alle Objektvariablen haben Standardwert oder Wert aus
sofortiger Zuweisung bei der Deklaration
• Grundregel der sauberen Programmierung: geben Sie
mindestens einen Konstruktor an (schreiben Sie zumindest
den Default-Konstruktor hin)
• Wenn man Konstruktor hinschreibt, gibt es den
automatischen Default-Konstruktor nicht!
Grundlagen Programmierung
Stephan Kleuker
73
ein sehr langer Konstruktor (unüblich)
Student(String vorname, String nachname, String geburtsort,
String geburtsland,
String strasse, String hausnummer,
Integer tag, Integer monat, Integer jahr,
String studiengang, Integer matrikelnummer) {
this.vorname = vorname;
this.nachname = nachname;
this.geburtsort = geburtsort;
this.geburtsland = geburtsland;
this.adresse = new Adresse(strasse, hausnummer);
this.eingeschriebenAm = new Datum(tag, monat, jahr);
this.studiengang = studiengang;
this.matrikelnummer = matrikelnummer;
}
Grundlagen Programmierung
Stephan Kleuker
74
sinnvoll: alle Objektvariablen initialisieren
Praktikum(String modul, String semester,
String veranstalter, String mitarbeiter){
super();
this.modul = modul;
this.semester = semester;
this.veranstalter = veranstalter;
this.mitarbeiter = mitarbeiter;
this.termine = new ArrayList<String>();
this.teilnehmer = new ArrayList<Student>();
}
• Welche Alternative gibt es?
Grundlagen Programmierung
Stephan Kleuker
75
bisherige Konstruktoren kritisch betrachtet
üblich ist der Aufruf mit Parameterliste
this.eingeschriebenAm = new Datum(tag, monat, jahr);
gibt Klassen mit Ausnahmen, bei denen das Objekt direkt
hingeschrieben werden kann, dies sind
• String stadt = "Osnabrueck";
geht aber auch: String stadt = new String("Osnabrueck");
• Integer jahr = 2023;
geht aber auch: Integer jahr = new Integer(2023);
• Double wert = 42.41;
geht aber auch: Double wert = new Double(42.41);
• Boolean allesToll = true;
geht aber auch: Boolean allesToll = new Boolean(true);
Grundlagen Programmierung
Stephan Kleuker
76
Erstellung eines Objekts im Code Pad – Variante 3/3
• Nutzung lokaler Variablen
Grundlagen Programmierung
Stephan Kleuker
77
Variablen ? was passiert denn da (1/5)
• Variablen referenzieren Werte im Speicher
Integer day = 6;
Integer month = 5;
Integer year = 1989;
Variablen
day
month
year
Speicher
6
5
1989
Datum aha = new Datum(day,month,year);
in der Klasse steht
Datum (Integer anInt1, Integer anInt2, Integer anInt3){
...
Ansatz: anInt1 wird lokale Variable in der Ausführung des
Konstruktors, erhält Referenz auf das Objekt, auf das day
zeigt
Grundlagen Programmierung
Stephan Kleuker
78
Variablen ? was passiert denn da (2/5)
Variablen
day
month
year
Speicher
6
5
1989
anInt1
lokale Variablen,
leben und sterben
mit Konstruktorausführung
anInt2
anInt3
• weiter im Konstruktor
this.tag = anInt1;
this.monat = anInt2;
this.jahr = anInt3;
Grundlagen Programmierung
Stephan Kleuker
79
Variablen ? was passiert denn da (3/5)
• Situation kurz vor Ende des Konstruktors
Speicher
Variablen
day
6
month
5
year
1989
anInt1
anInt2
anInt3
Variablen, die zum
gerade in Konstruktion
befindlichen Objekt
gehören
Grundlagen Programmierung
this.tag
this.monat
this.jahr
Stephan Kleuker
80
Variablen ? was passiert denn da (4/5)
• Situation nach
Integer day = 6;
Integer month = 5;
Integer year = 1989;
Datum aha = new Datum(day,month,year);
Speicher
Variablen
day
6
month
5
year
1989
this.tag
aha
this.monat
this.jahr
Grundlagen Programmierung
Stephan Kleuker
81
Variablen ? was passiert denn da (5/5)
• neue nächste Anweisung:
day = 32;
Variablen
Speicher
day
6
month
5
year
1989
this.tag
aha
32
this.monat
this.jahr
• Hinweis: Thema wird später noch vertieft
Grundlagen Programmierung
Stephan Kleuker
82
Erreichter Stand
•
•
•
•
Klassen beschreiben Schablonen zur Objektbeschreibung
Objektbeschreibung besteht aus Objektvariablen
jede Objektvariable hat einen eindeutigen Typ
Objekte werden durch Aufruf eines Konstruktors der Klasse
erzeugt, Konstruktor kann Parameterliste zur Übergabe von
Werten für die Objektvariablen (Belegung) enthalten
• Objektvariablen ohne Wert enthalten null-Referenz
• jede Klasse hat mindestens einen Konstruktor, wenn keiner
geschrieben, dann der Default-Konstruktor
• es ist sehr sinnvoll, alle Konstruktoren explizit hinzuschreiben
• wir können aber Werte von Objektvariablen nicht verändern
Grundlagen Programmierung
Stephan Kleuker
83
Objektmethoden
Grundlagen Programmierung
Stephan Kleuker
84
Reden mit Objekten
• Objekten können Methodenaufrufe geschickt werden
• aufgerufene Methoden können Werte der Objektvariablen
verändern
• aufgerufene Methoden können Berechnungen ausführen
• aufgerufene Methoden können ein Ergebnisobjekt als
Antwort des Aufrufs liefern
• Syntax
<TypDesErgebnisses> <Methodenname> (<Parameterliste>){
<Programm>
}
wenn kein Ergebnisobjekt, dann Ergebnistyp void
Grundlagen Programmierung
Stephan Kleuker
85
Einfache Methoden (1/2)
class Datum{
Integer tag;
Integer monat;
Integer jahr;
Datum (Integer tag, Integer monat, Integer jahr){
this.tag = tag;
this.monat = monat;
this.jahr = jahr;
}
Integer getTag() {
return this.tag;
}
void setTag(Integer tag) {
this.tag = tag;
}
Grundlagen Programmierung
Stephan Kleuker
86
Einfache Methoden (2/2)
Integer getMonat() {
return this.monat;
}
void setMonat(Integer monat) {
this.monat = monat;
}
Integer getJahr() {
return this.jahr;
}
void setJahr(Integer jahr) {
this.jahr = jahr;
}
}
Grundlagen Programmierung
Stephan Kleuker
87
Analyse der Methoden (1/2)
• Methode zum Lesen (Herausgeben) einer Variable var heißt
typischerweise getVar (großen Buchstaben beachten)
• Rückgabergebnis mit return <Ergebnis>;
Integer getTag() {
return this.tag;
}
Grundlagen Programmierung
Stephan Kleuker
88
Analyse der Methoden (2/2)
• Methode zum Schreiben (Verändern) einer Variable var
heißt typischerweise setVar (großen Buchstaben beachten)
void setTag(Integer tag) {
this.tag = tag;
}
Grundlagen Programmierung
Stephan Kleuker
89
Objekte nutzen Methoden anderer Objekte
• Code Pad sehr sehr hilfreich beim Ausprobieren
• Bei Code-Änderungen oder Schließen von BlueJ sind alle
Experimente gelöscht
Datum d = new Datum(29,2,2100);
d.setTag(1);
d.setTag(2);
• Idee: Schreibe neue Klasse, die obiges Programmstück in
einer Methode enthält, führe dann Methode in BlueJ aus
Grundlagen Programmierung
Stephan Kleuker
90
Experimentierklasse
class Datumsspielerei{
Datum datum;
Datumsspielerei(){
this.datum = new Datum(29,2,2100);
}
Datum einigeAenderungen(){
this.datum.setTag(1);
this.datum.setMonat(3);
return this.datum;
}
Datum neuerTagNeuerMonat(Integer tag, Integer monat){
this.datum.setTag(tag);
this.datum.setMonat(monat);
return this.datum;
}
}
Grundlagen Programmierung
Stephan Kleuker
91
Experiment in BlueJ (1/2)
Grundlagen Programmierung
Stephan Kleuker
92
Experiment in BlueJ (2/2)
resultierendes
Ergebnisobjekt wird
zurückgegeben
Grundlagen Programmierung
Stephan Kleuker
93
Spielen mit Objekten in BlueJ (1/2)
• Generell kann man bei direkten Aufrufen von Konstruktoren
und Methoden direkt auf Objekte zugreifen, die in der
Objektleiste liegen oder Objekte direkt erstellen
Objekterzeugung
Grundlagen Programmierung
Stephan Kleuker
94
Spielen mit Objekten in BlueJ (2/2)
Grundlagen Programmierung
Stephan Kleuker
95
Visualisierung mit Sequenzdiagrammen
Grundlagen Programmierung
Stephan Kleuker
96
Aufbau von Sequenzdiagrammen
new Datum()
datum:
Datum
• Objekt der Klasse Datum mit
dem Namen d
datum:
Datum
• Objekterzeugung mit
Konstruktoraufruf und Rückgabe
des Objekts (gestrichelt)
datum:
Datum
methode(42)
23
Grundlagen Programmierung
• Methodenaufruf mit
Parametern (Namen oder
konkrete Werte) und
Rückgabepfeil mit Ergebnis
(oder ohne Beschriftung bei
void)
Stephan Kleuker
97
Methoden mit lokalen Variablen
• innerhalb von Methoden können an beliebigen Stellen
lokale Variablen deklariert und innerhalb der Methode
genutzt werden
• Syntax und Möglichkeit zur Setzung des Startwerts wie bei
Objektvariablen
• genauer: lokale Variablen können in Blöcken
(Programmfragmente in geschweiften Klammern) deklariert
werden; nach dem Verlassen des Blocks ist Variable selbst
verloren (ihr Objekt kann z. B. als Rückgabewert weiter
existieren)
Grundlagen Programmierung
Stephan Kleuker
98
Beispiel: Nutzung einer lokalen Variable
class Datumsspielerei{
Datumsspielerei(){
}
Datum heiraten(Integer wert){
Datum ergebnis = new Datum();
ergebnis.setTag(wert);
ergebnis.setMonat(wert);
ergebnis.setJahr(wert);
return ergebnis;
}
}
Grundlagen Programmierung
Stephan Kleuker
99
Namensregeln und Sichtbarkeitsbereiche
• In demselben Block darf es nicht zwei Variablen mit
gleichem Namen geben (Syntaxfehler)
• Beispiel: Kann nicht eine Objektvariable monat vom Typ
Integer und eine Variable monat vom Typ String geben
• Lokale Variablen können die gleichen Namen wie
Objektvariablen haben, verdecken diese aber
• Objektvariablen immer durch this. zugreifbar
• Grundregel der guten Programmierung: Schaffen Sie
niemals Situationen, in denen Sie über verdeckte Variablen
nachdenken müssen
Grundlagen Programmierung
Stephan Kleuker
100
Verdecken einer Objektvariablen (1/3)
class Datumsspielerei{
Datum datum;
Datumsspielerei(){
this.datum = new Datum(29,2,2100);
}
Datum getDatum(){
return this.datum;
}
Datum heiraten(Integer wert){
Datum datum = new Datum();
datum.setTag(wert);
datum.setMonat(wert);
datum.setJahr(wert);
return datum;
}
}Grundlagen Programmierung
Stephan Kleuker
101
Verdecken einer Objektvariablen (2/3)
Grundlagen Programmierung
Stephan Kleuker
102
Verdecken einer Objektvariablen (3/3)
Grundlagen Programmierung
Stephan Kleuker
103
Methodennutzung
• Neben dem Wissen über existierende Klassen ist das Wissen
über die angebotenen Methoden Grundlage der
Programmiererfahrung
• In dieser Vorlesung sehen die objektorientierten
Programmiergrundlagen im Vordergrund, deshalb Wissen
über konkrete Java-Klassen im Hintergrund
• Wichtig: Man muss wissen, wo Informationen über
Klassen/Methoden stehen (z. B. Java-Dokumentation) und
wie man mit ihnen experimentieren kann (z. B. in BlueJ)
Grundlagen Programmierung
Stephan Kleuker
104
Möglichkeiten mit Integer-Objekten
• Erstellung mit Code
Pad und Objekt in
Objektleiste ziehen
• Rechtsklick auf dem
Objekt zeigt nutzbare
Methoden (zur Zeit
nur letzte Methode
halbwegs
verständlich)
Grundlagen Programmierung
Stephan Kleuker
105
Zusammenfassung
• Objekte sind Grundlagen der objektorientierten
Programmierung
• Programme bestehen aus dem
– Erstellen von Objekten
– Bearbeiten von Objekten über Methodenaufrufe
– Weitergeben von Objekten an Methoden über
Parameter
• Durch die systematische Bearbeitung aller Objekte entsteht
ein Programm
• Es ist Teil der Anforderungsanalyse festzustellen, welche
Klassen und Methoden zur Lösung der Aufgabenstellung
benötigt werden
Grundlagen Programmierung
Stephan Kleuker
106
Vereinfachte Klasse Student (1/3)
class Student{
String vorname ="Eva";
String nachname ="Mustermann";
Integer geburtsjahr = 1990;
String studiengang = "IMI";
Integer matrikelnummer = 232323;
Student(String vorname, String nachname,
Integer geburtsjahr, String studiengang,
Integer matrikelnummer) {
this.vorname = vorname;
this.nachname = nachname;
this.geburtsjahr = geburtsjahr;
this.studiengang = studiengang;
this.matrikelnummer = matrikelnummer;
}
Student(){
}
Grundlagen Programmierung
Stephan Kleuker
107
Vereinfachte Klasse Student (2/3)
String getVorname() {
return this.vorname;
}
void setVorname(String vorname) {
this.vorname = vorname;
}
String getNachname() {
return this.nachname;
}
void setNachname(String nachname) {
this.nachname = nachname;
}
Integer getGeburtsjahr() {
return this.geburtsjahr;
}
Grundlagen Programmierung
Stephan Kleuker
108
Vereinfachte Klasse Student (3/3)
void setGeburtsjahr(Integer geburtsjahr) {
this.geburtsjahr = geburtsjahr;
}
String getStudiengang() {
return this.studiengang;
}
void setStudiengang(String studiengang) {
this.studiengang = studiengang;
}
Integer getMatrikelnummer() {
return this.matrikelnummer;
}
void setMatrikelnummer(Integer matrikelnummer) {
this.matrikelnummer = matrikelnummer;
}
}
Grundlagen Programmierung
Stephan Kleuker
109
Debugger
Grundlagen Programmierung
Stephan Kleuker
110
Bayrisches Problem
• Student hat sich bei
Einschreibung mit
„Jo mei, I bian der
Huber Xaver“
vorgestellt
• Wunsch: Methode
zum Vertauschen
von Vor- und
Nachnamen
Grundlagen Programmierung
Stephan Kleuker
111
(schlechter) Versuch 1 (1/3)
• neue Methode
void vertauscheNamen(){
this.vorname = this.nachname;
this.nachname = this.vorname;
}
• neue Klasse zum Ausprobieren
class Studentspielerei{
Student namenstausch(){
Student xaver= new Student("Huber", "Xaver", 1988
,"MID", 424223);
xaver.vertauscheNamen();
return xaver;
}
}
Grundlagen Programmierung
Stephan Kleuker
112
(schlechter) Versuch 1 (2/3)
• Ausführung von namenstausch() liefert
Grundlagen Programmierung
Stephan Kleuker
113
(schlechter) Versuch 1 (3/3)
• Analyse, was ist passiert:
Student xaver= new Student("Huber", "Xaver", 1988
,"MID", 424223);
• vorname = "Huber" nachname = "Xaver"
xaver.vertauscheNamen();
this.vorname = this.nachname;
– vorname = "Xaver" nachname = "Xaver"
this.nachname = this.vorname;
– vorname = "Xaver" nachname = "Xaver"
• vorname = "Xaver" nachname = "Xaver"
Grundlagen Programmierung
Stephan Kleuker
114
(guter) Versuch 2 (1/3)
• Nutzung einer lokalen Variablen
void vertauscheNamen(){
String tmp = this.vorname;
this.vorname = this.nachname;
this.nachname = tmp;
}
Grundlagen Programmierung
Stephan Kleuker
115
(guter) Versuch 2 (2/3)
• Ausführung von namenstausch() liefert
Grundlagen Programmierung
Stephan Kleuker
116
(guter) Versuch 2 (3/3)
• Analyse, was ist passiert:
Student xaver= new Student("Huber", "Xaver", 1988
,"MID", 424223);
• vorname = "Huber" nachname = "Xaver"
xaver.vertauscheNamen();
String tmp = this.vorname;
– vorname = "Huber" nachname = "Xaver" tmp = "Huber"
this.vorname = this.nachname;
– vorname = "Xaver" nachname = "Xaver" tmp = "Huber"
this.nachname = tmp;
– vorname = "Xaver" nachname = "Huber" tmp = "Huber"
• vorname = "Xaver" nachname = "Huber"
Grundlagen Programmierung
Stephan Kleuker
117
Nutzung des Debuggers (1/6) - Vorbereitung
• letzte Folie zeigt, dass genaue Verfolgung der
Variablenwerte wichtiges Hilfsmittel sein kann
• Ansatz ist, über Debugger (direkt übersetzt: Entwanzer) die
Abarbeitung zu verfolgen
• genauer: Zeilen, ab denen der Debugger die genaue
Situation zeigen soll, werden markiert (Break Point, Klick am
linken Rand des Editors, nur nach "Compile" sichtbar)
Grundlagen Programmierung
Stephan Kleuker
118
Nutzung des Debuggers (2/6) – Start der Nutzung
• Methode wird für gegebenes Objekt gestartet
• markierte Zeile
wird erreicht;
es öffnet sich
Debugger und
Editor (zeigt
immer aktuelle
Zeile an)
Grundlagen Programmierung
Stephan Kleuker
119
Nutzung des Debuggers (3/6) – mögliche Aktionen
Typische Bedienmöglichkeiten
eines Debuggers:
Step: nächste Anweisung
ausführen
Step Into: bei anstehenden
Methodenaufrufen kann man
in die Methode
hineinspringen
Continue: verlasse DebugModus und lasse Programm
"normal" weiterlaufen, bis
nächster Break Point erreicht
wird
Grundlagen Programmierung
Stephan Kleuker
120
Nutzung des Debuggers (4/6) - Anzeige
welche Klassenvariablen
(später!) gibt es
welche Methoden
laufen zur Zeit
(Methoden können ja
Methoden aufrufen)
welche Objektvariablen
gibt es (detailliertere
Inhalte) durch Anklicken
welche lokalen
Variablen gibt es
Grundlagen Programmierung
Stephan Kleuker
121
Nutzung des Debuggers (5/6) – Ausführung 1/2
Grundlagen Programmierung
Stephan Kleuker
122
Nutzung des Debuggers (6/6) – Ausführung 2/2
Grundlagen Programmierung
Stephan Kleuker
123
Visualisierung im Aktivitätsdiagramm - Sequenz
Startknoten (es kann nur
einen geben)
gerichtete Kanten zeigen
Ablauf
abgerundete Rechtecke
enthalten Anweisungen
(Aktionen)
Endknoten zur
Terminierung (es kann
mehrere geben)
Grundlagen Programmierung
String tmp = this.vorname
this.vorname = this.nachname
this.nachname = tmp
Stephan Kleuker
124
Objektweitergabe
Grundlagen Programmierung
Stephan Kleuker
125
Erinnerung Klasse Student
• Anfang
class Student{
String vorname ="Eva";
String nachname ="Mustermann";
Integer geburtsjahr = 1990;
String studiengang = "IMI";
Integer matrikelnummer = 232323;
Student(String vorname, String nachname,
Integer geburtsjahr, String studiengang,
Integer matrikelnummer) {...
Student(){
}...
• weiter mit get- und set-Methoden für alle Objektvariablen
Grundlagen Programmierung
Stephan Kleuker
126
Möglichkeit 1: Direkte Erzeugung in anderer Klasse
class StudentSpielerei{
Student standardMIDStudi(){
Student ergebnis = new Student();
ergebnis.setStudiengang("MID");
return ergebnis;
}
}
Grundlagen Programmierung
Stephan Kleuker
127
Möglichkeit 2: Übergabe in Methode/ in Konstruktor
class Anonymisierer {
Student dummy;
Anonymisierer(Student dummy){
this.dummy=dummy;
}
void anonymisieren(Student zuAendern){
zuAendern.setVorname(this.dummy.getVorname());
zuAendern.setNachname(this.dummy.getNachname());
}
}
Grundlagen Programmierung
Stephan Kleuker
128
Nutzung in StudentSpielerei
class StudentSpielerei{
Student anonymAusprobieren(){
Student def = new Student("Mr","X",1990,"IMI",234243);
Anonymisierer ano = new Anonymisierer(def);
Student test = new Student("Ms","Y",1980,"MID",234244);
ano.anonymisieren(test);
return test;
}
}
Grundlagen Programmierung
Stephan Kleuker
129
(k)eine Besonderheit: Objekt übergibt sich selbst (1/2)
class Anonymisierer {
Student dummy;
Anonymisierer(Student dummy){
this.dummy=dummy;
}
void anonymisieren(Student zuAendern){
zuAendern.setVorname(this.dummy.getVorname());
zuAendern.setNachname(this.dummy.getNachname());
}
void leseDummyAus(StudentSpielerei spielerei){
this.dummy = spielerei.getStudi();
}
}
Grundlagen Programmierung
Stephan Kleuker
130
(k)eine Besonderheit: Objekt übergibt sich selbst (2/2)
class StudentSpielerei{
Student studi;
Student getStudi(){
return this.studi;
}
Student sichUebergeben(){
this.studi = new Student("Mr","X",1990,"IMI",234243);
Anonymisierer ano = new Anonymisierer(null);
ano.leseDummyAus(this);
Student test = new Student("Ms","Y",1980,"MID",234244);
ano.anonymisieren(test);
return test;
}
Grundlagen Programmierung
Stephan Kleuker
131
Abhängigkeiten
• Generell wird meist gefordert, dass nicht gleichzeitig eine
Klasse A eine Klasse B und eine Klasse B eine Klasse A nutzt
Grundlagen Programmierung
Stephan Kleuker
132
Alternative
Grundlagen Programmierung
Stephan Kleuker
133
Alternativen
• bisher bestehen Programme aus der
Nacheinanderausführung von Methodenaufrufen (Sequenz)
• typisch ist die Notwendigkeit der Alternative
wenn folgendes gilt,
dann soll folgendes gemacht werden
• oder
wenn folgendes gilt,
dann soll folgendes gemacht werden,
sonst soll folgendes gemacht werden
• wenn = if (dann wird implizit gesagt) sonst = else
Grundlagen Programmierung
Stephan Kleuker
134
Ausgabe des Studiengangsnamens
• Die Methode soll einen Langnamen für den Studiengang als
Ergebnis liefern, wenn der Name "IMI" ist, soll "Informatik –
Medieninformatik" das Ergebnis sonst der im Objekt
eingetragene Studiengangsname das Ergebnis sein
• Realisierung in der Klasse Student
String langnameBerechnen(){
String ergebnis = this.studiengang;
if(this.studiengang.equals("IMI")){
ergebnis = "Informatik - Medieninformatik";
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
135
Ausprobieren (in Studentspielerei) (1/2)
String einIMIStudent(){
Student eva= new Student("Eva", "Li", 1988, "IMI", 13);
String ergebnis = eva.langnameBerechnen();
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
136
Ausprobieren (in Studentspielerei) (2/2)
String keinIMIStudent(){
Student eva= new Student("Udo", "Li", 1987, "MID", 14);
String ergebnis = eva.langnameBerechnen();
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
137
Syntaxanalyse von if
if(this.studiengang.equals("IMI")){
ergebnis = "Informatik - Medieninformatik";
}
• Boolescher Ausdruck
(Bedingung) in runden
Klammern, Ausdruck in der
Klammer muss nach true
oder false ausgewertet
werden
• Zugriff auf alle sichtbaren
Objektvariablen,
Methodenparameter und
lokale Variablen der
umgebenden Blöcke
Grundlagen Programmierung
• Programmzeilen in
geschweiften Klammern;
wird ausgeführt, wenn
Ausdruck nach true
ausgewertet wird
• Zugriff auf alle sichtbaren
Objektvariablen,
Methodenparameter und
lokale Variablen der
umgebenden Blöcke
Stephan Kleuker
138
Visualisierung im Aktivitätsdiagramm - generell
if ( <Bedingung> ) {
<Teilprogramm>
}
• Raute steht für
Alternative und die
Vereinigung
verschiedener Abläufe
• Bei einer Alternative
stehen Bedingungen in
eckigen Klammern auf
den ausgehenden
Kanten
• ! steht für die Negation
Grundlagen Programmierung
[<Bedingung>]
[!<Bedingung>]
<Teilprogramm>
Stephan Kleuker
139
Visualisierung im Aktivitätsdiagramm - konkret
String ergebnis = this.studiengang
[this.studiengang
.equals("IMI")]
[!this.studiengang
.equals("IMI")]
ergebnis = "Informatik - Medieninformatik"
return ergebnis;
Grundlagen Programmierung
Stephan Kleuker
140
Boolescher Ausdruck
•
•
•
•
benannt nach George Boole (1815-1864), Mathematiker
wird nach false (falsch) oder true (wahr) ausgewertet
kann Methode mit Booleschem Ergebnis sein
kann einfacher Vergleich von Zahlen sein
geburtsjahr < 1900
1900 > geburtsjahr
geburtsjahr.equals(matrikelnummer) für Gleichheit
• Operator == prüft Identität, nicht zum inhaltlichen Vergleich
nutzbar
• auch <= >=
• negierbar, Negation mit Ausrufungszeichen
! (geburtsjahr < 1900)
• Boolesche Variable
Boolean jaja = false;
! jaja
Grundlagen Programmierung
Stephan Kleuker
141
Zusammengesetzter Boolescher Ausdruck (1/2)
• Boolesche Ausdrücke können mit den Booleschen
Operatoren "und" (&&) sowie "oder" (||) verknüpft werden
• Boolesche Ausdrücke können in runden Klammern stehen
• Auswertungsreihenfolge: Klammern binden mehr als
Negation, diese bindet mehr als Und, das bindet mehr als
Oder (einfacher Ansatz: immer Klammern setzen)
• Wahrheitstafeln
&&
true
true false
true false
false false false
Grundlagen Programmierung
||
true
true false
true true
false true false
Stephan Kleuker
!
true false
false true
142
Zusammengesetzter Boolescher Ausdruck (2/2)
• Beispiele mit Variablen Integer alter=23 und Integer iq=42
alter > 20 && iq > alter  true && true ergibt true
alter > 20 || iq < alter  true || false ergibt true
alter > 20 || iq < 10 && iq >99  true || false && false
ergibt true || false, ergibt true
(alter > 20 || iq < 10) && iq >99  (true || false) && false
ergibt true && false, ergibt false
!(alter>23) || alter<24  (!false || true) ergibt (true || true),
ergibt true
!(alter>23 || alter<24)  !(false || true) ergibt !(true),
ergibt false
! alter>23 gibt Fehler, da Integer-Objekt nicht negiert
werden kann
Grundlagen Programmierung
Stephan Kleuker
143
Analyse von Booleschen Ausdrücken in Code Pad
• zur Auswertung kein Semikolon am Zeilenende
Grundlagen Programmierung
Stephan Kleuker
144
Wahrheitstabellen
Boolean a;
Boolean b;
Boolean c;
a
false
false
false
false
true
true
true
true
b
false
false
true
true
false
false
true
true
Grundlagen Programmierung
c
a || b && c
false
false
true
false
false
false
true
true
false
true
true
true
false
true
true
true
Stephan Kleuker
(a || b) && c
false
false
false
true
false
true
false
true
145
Rechenregeln für Boolesche Ausdrücke
• nutzt Aussagenlogik
• ≡ heißt "logisch äquivalent", bedeutet dass beide
Ausdrücke immer den gleichen Wahrheitswert liefern
•
•
•
•
•
•
•
•
a && (b || c) ≡ (a && b) || (a && c)
a || (b && c) ≡ (a || b) && (a || c)
! (a && b) ≡ !a || !b
a && b ≡ b && a
! (a || b) ≡ !a && !b
a || b ≡ b || a
a && !a ≡ false
a && a ≡ a
a || !a ≡ true
a || a = a
a && true ≡ a
a && false ≡ false
a || false ≡ a
a || true ≡ true
Grundlagen Programmierung
Stephan Kleuker
146
Einsatz von Rechenregeln
• Umformung Boolescher Ausdrücke mit dem Ziel der
Vereinfachung (hier Integer-Variablen)
if (iq<99 && bmi>25 || iq>98 && bmi>25 || iq<99 && bmi<=25
|| iq>98 && bmi<=25){
<Teilprogramm>
}
iq<99 && bmi>25 || iq>98 && bmi>25 || iq<99 && bmi<=25
|| iq>98 && bmi<=25
≡
iq<99 && bmi>25 || iq<99 && bmi<=25
|| iq>98 && bmi>25 || iq>98 && bmi<=25
≡
iq<99 && (bmi>25 || bmi<=25)
|| iq>98 && (bmi>25 || bmi<=25)
≡ iq<99 && (true) || iq>98 && (true)
≡ iq<99 || iq>98 ≡ true (if ist überflüssig)
Grundlagen Programmierung
Stephan Kleuker
147
Ausdrücke mit ganzen Zahlen
Integer-Variablen a, b, und c, es gibt folgende Operatoren
• a + b (Addition)
• a – b (Subtraktion)
• a * b (Multiplikation)
• a / b (ganzzahlige Division 7/4 == 1)
• a % b (ganzzahliger Rest der Division (modulo) 7%4 == 3)
• Boolesche Ausdrücke der Form a + b < a * b möglich
• Ausdrücke können Variablen auf der linken Seite
zugewiesen werden
Integer oha = (7/4)*4 + (7%4);
• man beachte unglückliche Nutzung des Gleichheitszeichens
oha = oha + 1;
Grundlagen Programmierung
Stephan Kleuker
148
Analyse von ganzzahligen Ausdrücken in Code Pad
• es gilt: erst Klammern, dann *, /
und %, dann + und –
• mathematische Operatoren binden
stärker (werden zuerst
ausgewertet) als Boolesche
Operatoren
• Division durch Null nicht erlaubt,
man erhält in weiterem Fenster:
Grundlagen Programmierung
Stephan Kleuker
149
Ausdrücke mit Fließkomma-Zahlen
Double-Variablen a, b, und c, es gibt folgende Operatoren
• a + b (Addition)
• a – b (Subtraktion)
• a * b (Multiplikation)
• a / b (Division 7.0/4.0 == 1.75)
• a % b (Rest nach ganzzahliger Division 7.0%3.4 == 0.2)
• Boolesche Ausdrücke der Form a + b < a * b möglich
• Ausdrücke können Variablen auf der linken Seite
zugewiesen werden
Double oha = (7.0/4.0)*4.0;
• man beachte unglückliche Nutzung des Gleichheitszeichens
oha = oha + 1;
Grundlagen Programmierung
Stephan Kleuker
150
Analyse von Fließkommazahl-Ausdrücken
• es gilt, erst Klammern, dann
* und /, dann + und –
• mathematische Operatoren
binden stärker (werden
zuerst ausgewertet) als
Boolesche Operatoren
• Division durch Null führt zu
neuen Double-Werten
(später mehr):
-Infinity
Infinity
NaN
• Rechengenauigkeit beachten
Grundlagen Programmierung
Stephan Kleuker
151
Programmiervarianten (1/2)
• aktuell:
String langnameBerechnen(){
String ergebnis = this.studiengang;
if(this.studiengang.equals("IMI")){
ergebnis = "Informatik - Medieninformatik";
}
return ergebnis;
}
• Variante: direkter Rücksprung (evtl. kürzere Berechnung
aber schwerer zu Lesen, da es mehr als ein Ende gibt)
String langnameBerechnen2(){
String ergebnis = this.studiengang;
if(this.studiengang.equals("IMI")){
return "Informatik - Medieninformatik";
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
152
Visualisierung der Variante
String ergebnis = this.studiengang
[this.studiengang
.equals("IMI")]
[!this.studiengang
.equals("IMI")]
return "Informatik - Medieninformatik"
Grundlagen Programmierung
Stephan Kleuker
return ergebnis
153
Programmiervarianten (2/2)
• kürzer; zumindest für Anfänger ist es aber sinnvoll, eine
ergebnis-Variable einzuführen und zurückzugeben
String langnameBerechnen3(){
if(this.studiengang.equals("IMI")){
return "Informatik - Medieninformatik";
}
return this.studiengang;
}
• Nutzung eines aus anderen Programmiersprachen
übernommenen Operators
String langnameBerechnen4(){
return this.studiengang.equals("IMI")
? "Informatik - Medieninformatik"
: this.studiengang;
}
Grundlagen Programmierung
Stephan Kleuker
154
Operator ? :
• Operator hat folgende Syntax
• <Boolescher Ausdruck> ? <Ausdruck1> : <Ausdruck2>
• Wenn Boolescher Ausdruck nach wahr ausgewertet wird,
dann ist das Ergebnis der Wert des Ausdrucks1 sonst des
Ausdrucks2
• Ausdruck1 und Ausdruck2 müssen selben Typ haben
Integer mo = name.equals("Li") ? 42 : 23;
• äquivalent zu
Integer mo;
if(name.equals("Li"){
mo = 42;
} else {
mo = 23;
}
• Wunsch: verzichten Sie auf diesen coolen Operator
Grundlagen Programmierung
Stephan Kleuker
155
Nutzung von else
• Anforderung: Basierend auf dem Alter soll eine
Persönlichkeitseinstufung erfolgen
String persoenlichkeit(){
String ergebnis;
if(this.geburtsjahr < 1970){
ergebnis = "alter Sack";
} else {
ergebnis = "Windelhopser";
}
return ergebnis;
}
• Gibt wieder einige Programmiervarianten
Grundlagen Programmierung
Stephan Kleuker
156
Syntaxanalyse von if -else
if(this.geburtsjahr < 1970){
ergebnis = "alter Sack";
} else {
ergebnis = "Windelhopser";
}
• syntaktisch genau gleich,
wie das bisher
beschriebene if ohne else
Grundlagen Programmierung
• Programmfragment in
geschweiften Klammern;
wird ausgeführt, wenn
Ausdruck nach false
ausgewertet wird
• Zugriff auf alle sichtbaren
Objektvariablen,
Methodenparameter und
lokale Variablen der
umgebenden Blöcke
Stephan Kleuker
157
Schachtelung von Programmfragmenten
• Anforderung: Die Persönlichkeitseinstufung soll weiter
detailliert werden
String genauerePersoenlichkeit(){
String ergebnis;
if(this.geburtsjahr < 1970){
ergebnis = "alter Sack";
} else {
if (this.studiengang.equals("IMI")){
ergebnis = "Dynamit";
} else {
ergebnis = "Windelhopser";
}
}
return ergebnis;
} Programmierung
Grundlagen
Stephan Kleuker
158
Visualisierung von genauerePersoenlichkeit
String ergebnis
[this.geburtsjahr<1970]
ergebnis = "alter Sack"
[!this.geburtsjahr<1970]
[this.studiengang
.equals("IMI")]
[!this.studiengang
.equals("IMI")]
ergebnis = "Dynamit"
ergebnis = "Windelhopser"
return ergebnis
Grundlagen Programmierung
Stephan Kleuker
159
Eine der Implementierungsalternativen
String genauerePersoenlichkeit2(){
if(this.geburtsjahr < 1970){
return "alter Sack";
}
if (this.studiengang.equals("IMI")){
return "Dynamit";
}
return "Windelhopser";
}
• Verschachtelung von Anweisungen und komplexe
Boolesche Ausrücke machen Programme schwer lesbar
Grundlagen Programmierung
Stephan Kleuker
160
Visualisierung der Alternative
• Hinweis: In Visualisierung nicht sichtbar, ob else genutzt (da
mit return Ausführung endet
String ergebnis
[this.geburtsjahr<1970]
return "alter Sack"
[!this.geburtsjahr<1970]
[this.studiengang
.equals("IMI")]
return "Dynamit"
Grundlagen Programmierung
Stephan Kleuker
[!this.studiengang
.equals("IMI")]
return"Windelhopser"
161
Alternative mit Methodenaufteilung
String genauerePersoenlichkeit3(){
String ergebnis;
if(this.geburtsjahr < 1970){
ergebnis = "alter Sack";
} else {
ergebnis = jungePersoenlichkeit();
}
return ergebnis;
}
String jungePersoenlichkeit() {
String ergebnis;
if (this.studiengang.equals("IMI")){
ergebnis = "Dynamit";
} else {
ergebnis = "Windelhopser";
}
return ergebnis;
Grundlagen
Stephan Kleuker
} Programmierung
162
Hinweise zur Methodenaufteilung
• sehr sinnvoll: einfache kurze Methoden mit sinnvollen
Methodennamen
• Grundregel: wenn es zu komplex wird, neue Methode
auslagern
• Die hier gezeigte (für die Veranstaltung relevante)
Methodenaufteilung wird in älteren Programmiersprachen
kontrovers diskutiert
• Pro: bessere Lesbarkeit, klarere Struktur (allerdings mehr
Methoden)
• Contra: zusätzliche Methodenaufrufe benötigen Zeit (in Java
minimal, teilweise durch Compiler wegoptimiert)
Grundlagen Programmierung
Stephan Kleuker
163
Weitere, aber schwache Alternative
String genauerePersoenlichkeit4(){
if (
!(this.geburtsjahr < 1970)
&& this.studiengang.equals("IMI")){
return "Dynamit";
}
if (
!(this.geburtsjahr < 1970)
&& !this.studiengang.equals("IMI")){
return "Windelhopser";
}
return "alter Sack";
}
• unnötig komplizierte Boolesche Ausdrücke
Grundlagen Programmierung
Stephan Kleuker
164
Grundregel für Alternativen
Müssen zur Ausführung mehrere Bedingungen berücksichtigt
werden
• müssen die Booleschen Ausdrücke zunächst einzeln
formuliert werden
• muss überlegt werden, ob ein Ausdruck wichtiger als ein
anderer ist; falls es den gibt: if(<Bed.>) {… return…}
• müssen die zusammengesetzten Booleschen Ausdrücke
formuliert und in eine sinnvolle
– Sequenz von if-else-Befehlen, oder
– Verschachtelung von if-else-Befehlen
gebracht werden
Grundlagen Programmierung
Stephan Kleuker
165
equals
Grundlagen Programmierung
Stephan Kleuker
166
Inhaltliche Objektgleichheit mit equals
•
•
•
•
•
Vergleich von Strings auf gleichen Inhalt mit equals
genauer: jede vorhandene Java-Klasse hat equals-Methode
Folgerung: wir müssen auch equals-Methode schreiben
[Hinweis: ganz sauber etwas später]
wir bestimmen wann etwas gleich sein soll:
– typisch: alle Werte der Objektvariablen sollen
übereinstimmen
– Variante: Objekt hat eindeutigen Identifikationswert, z.
B. Matrikelnummer; restliche Objektwerte müssen nicht
übereinstimmen (Tippfehler, Heirat)
Grundlagen Programmierung
Stephan Kleuker
167
Methode equals für Klasse Student (erster Versuch)
Boolean equals(Student other){
if (other == null){
return false;
}
if (this.vorname.equals(other.getVorname())
&& this.nachname.equals(other.getNachname())
&& this.geburtsjahr.equals(other.getGeburtsjahr())
&& this.studiengang.equals(other.getStudiengang())
&& this.matrikelnummer
.equals(other.getMatrikelnummer())){
return true;
}
return false;
}
Grundlagen Programmierung
Stephan Kleuker
168
Erinnerung: null-Referenz
• Methoden können nur auf echten Objekten, nicht der nullReferenz ausgeführt werden
• Methodenaufrufe auf der null-Referenz führen zu
gefürchteten NullPointerExceptions
• defensive Programmierung: zuerst auf null testen
if (other == null){
return false;
}
• sonst:
Grundlagen Programmierung
Stephan Kleuker
169
Analyse des equals für Student
• Parameter sauber auf null überprüft, aber bei
this.nachname.equals(other.getNachname())
•
•
•
•
könnte nachname eine null-Referenz sein
Antwort: Nein, da beide Konstruktoren garantieren, dass
Objekte gesetzt werden (Eva Mustermann)
Kommentar: Halt! Mit Methode setNachname kann
nachträglich null-Referenz übergeben werden
Also entweder set-Methoden absichern oder equals
umschreiben
Ansatz: prüfe für jeden Parameter ob er null-Referenz ist
und mache dann inhaltliche Prüfung
nehme an, dass Objekte inhaltlich gleich, gebe bei
Ungleichheit false und nur ganz am Ende true zurück
Grundlagen Programmierung
Stephan Kleuker
170
Methode equals ohne NullPointerException
Boolean equals(Student other){
if (other == null){
return false;
}
if (geburtsjahr == null) {
if (other.getGeburtsjahr() != null) {
return false;
}
} else {
if (!geburtsjahr.equals(other.getGeburtsjahr())) {
return false;
}
}
// gleiche Untersuchungen fuer andere Objektvariablen
return true;
}
Grundlagen Programmierung
Stephan Kleuker
171
Sichtbarkeiten
• beim Auslagern von Methoden gab es folgendes Ergebnis:
String genauerePersoenlichkeit3(){ ... }
String jungePersoenlichkeit() { ...}
• Problem: Objekt-Nutzer können auch Methode
jungePersoenlichkeit() aufrufen, obwohl dies vielleicht nicht
gewünscht ist
• Lösung: Klassen, Objektvariablen und Methoden können mit
Sichtbarkeiten markiert werden, hier zunächst
– public: alle können darauf zugreifen
– private: nur innerhalb des Objektes kann darauf
zugegriffen werden
• Grundregel der Objektorientierung: Information-Hiding; nur
über Methoden kann auf Objektvariablen zugegriffen werden
Grundlagen Programmierung
Stephan Kleuker
172
Sichtbarkeiten in der Klasse Student
public class Student{
private String vorname ="Eva";
private String nachname ="Mustermann";
private Integer geburtsjahr = 1990;
private String studiengang = "IMI";
private Integer matrikelnummer = 232323;
public Student(String vorname, …
public Student(){ …
public void vertauscheNamen(){…
public String genauerePersoenlichkeit3(){…
private String jungePersoenlichkeit() {…
public Boolean equals(Student other){…
public String getVorname() {…
public String getNachname() {…
public void setVorname(String vorname) {…
public void setNachname(String nachname) {…
…
Grundlagen Programmierung
Stephan Kleuker
173
Kommentare - Einstieg
• Kommentare sollen das Lesen von Programmen für Andere
und sich selbst (!!!) einfacher machen
• zwei Kommentar-Arten
• Kurzkommentar nach // , Kommentar endet mit Zeile
• Langkommentar, beginnt mit /* und endet mit */
• Anfänger sollten intensiver kommentieren
• typische Kommentare
• Kurzbeschreibung: wozu gibt es Objektvariable
• Methode: wozu ist sie da, welche Parameter mit welchem
Sinn gibt es, wie sieht das berechnete Ergebnis aus
• meist wenig/keine Kommentare in Methoden, da durch
Namen, ihre Kürze und sprechende Variablen selbsterklärend
• systematische Kommentierung ( JavaDoc) später
Grundlagen Programmierung
Stephan Kleuker
174
Kommentare: Beispiel
/** Klasse zur Verwaltung des aktuellen Chefs. */
public class Chef {
private String name;
// Name des Chefs
private Integer level = 23;
// erreichte Stufe
/* Konstruktor fuer neues Chef-Objekt
* Parameter name: neuer Name des Chefs
*/
public Chef(String name){
this.name = name;
}
/* Methode zur Pruefung, ob Chef Andreas heisst
Ergebnis: heisst Chef Andreas */
public Boolean issesAndreas(){
if("Andreas".equals(this.name)){ // geht auch so
return true;
}
return false;
}
Grundlagen
Programmierung
Stephan Kleuker
}
175
Strings
Grundlagen Programmierung
Stephan Kleuker
176
Ein- und Ausgabe mit Klasse EinUndAusgabe
• Ein- und Ausgabe etwas trickreich bzw. schmuddelig,
deshalb hier objektorientiert saubere Klasse EinUndAusgabe
Methode
Rückgabetyp Aufgabe
Default
leseString
leseDouble
String
Integer
Double
liest Text von Konsole
liest ganze Zahl
liest Fließkommazahl
-1
-1.0
leseBoolean
Boolean
liest Wahrheitswert
false
leseInteger
• Eingabe endet immer mit dem Drücken von "Return"
• Default-Wert bei falscher Eingabe
Methode Parametertyp Aufgabe
ausgeben
String
gibt Text auf Konsole aus
Grundlagen Programmierung
Stephan Kleuker
177
Strings als Ausdrücke
• neben den Objektmethoden gibt es Möglichkeit, Strings mit
"+" zu verknüpfen (konkatenieren)
• weiterhin können Strings mit beliebigen Objekten mit "+"
verknüpft werden
Grundlagen Programmierung
Stephan Kleuker
178
Methode toString()
• neue Klassen werden unbefriedigend in Strings umgesetzt
• Lösung: Klasse erhält Methode public String toString()
public String toString(){
return this.vorname+" "+this.nachname+" ("
+ this.matrikelnummer+"):"+this.studiengang
}
• Methode wird implizit bei String-Bearbeitung angestoßen
• man kann toString als normale Methode nutzen
eva.toString()
Grundlagen Programmierung
Stephan Kleuker
179
Besondere Zeichen (1/2)
•
•
•
•
Ausgabe wird zur Zeit als unendliche Zeile ausgegeben
Zeilenumbruch mit Zeichen "\n"
Backslash leitet Sonderzeichen ein
\u leitet Unicode-Zeichen ein (genauer UTF-16)
Text
Ausgabe
Text
Ausgabe
\n
\t
\\
\"
\u00c4
\u00e4
Zeilenumbruch
Tabulator
\
"
Ä
ä
\u00d6
\u00f6
\u00dc
\u00fc
\u00df
Ö
ö
Ü
ü
ß
Grundlagen Programmierung
Stephan Kleuker
180
Besondere Zeichen (2/2)
• Ein- und Ausgabe erfolgt in BlueJ in "Terminal"
• Beispielmethode:
public void sonderzeichen(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("0123456789012345678\n");
io.ausgeben("01\t123\t45\n");
io.ausgeben("\"ein\\/Pfeil\"\n");
io.ausgeben("\u00c4 \u00e4 \u00d6 \u00f6 \u00dc \u00fc "
+" \u00df \u00E9 \u00A6 \u00A2 \u20AC \u2020 ");
}
Grundlagen Programmierung
Stephan Kleuker
181
Vision: alle Zeichen sichtbar mit Unicode
• Unicode [ˈjuːnɪkoʊd] ist ein internationaler Standard, in dem
langfristig für jedes sinntragende Schriftzeichen oder
Textelement aller bekannten Schriftkulturen und
Zeichensysteme ein digitaler Code festgelegt wird. Ziel ist
es, die Verwendung unterschiedlicher und inkompatibler
Kodierungen in verschiedenen Ländern oder Kulturkreisen
zu beseitigen. Unicode wird ständig um Zeichen weiterer
Schriftsysteme ergänzt. (wikipedia.de)
• recht mächtig und häufig genutzt: ISO 8859-1 (Latin1, z. B.
auch griechisch und hebräisch)
• <?xml version="1.0" encoding="UTF-8"?>
• <?xml version="1.0" encoding="ISO-8859-1"?>
• http://www.unicode.org
Grundlagen Programmierung
Stephan Kleuker
182
Einige Methoden der Klasse ArrayList<Typ>
MethoParameter Ergebnis Beschreibung
denname
add
Typ
fügt übergebenes Element
hinten an
add
Integer,
fügt übergebenes Element an
Typ
angegebener Position ein
get
Integer
Typ
remove
Integer
Typ
set
Integer,
Typ
Typ
size
Grundlagen Programmierung
Integer
gibt Element an gefragter
Position zurück
entfernt Element an gegebener
Position (ist auch Ergebnis)
ersetzt Objekt an angegebener
Position, gibt altes Objekt zurück
gibt Anzahl der Elemente
Stephan Kleuker
183
Spielerei mit ArrayList
import java.util.ArrayList;
public class ListenSpielerei {
public void spielen(){
ArrayList<Integer> zahlen = new ArrayList<Integer>();
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("1: "+zahlen+"\n");
zahlen.add(42);
zahlen.add(41);
io.ausgeben("2: "+zahlen+"\n");
1: []
zahlen.add(1,23);
2: [42, 41]
io.ausgeben("3: "+zahlen+"\n");
3: [42, 23, 41]
4: 41
io.ausgeben("4: "+zahlen.get(2)+"\n");
5: [67, 23, 41]
zahlen.set(0, 67);
6: [23, 41]
io.ausgeben("5: "+zahlen+"\n");
7: 2
zahlen.remove(0);
io.ausgeben("6: "+zahlen+"\n");
io.ausgeben("7: "+zahlen.size()+"\n");
Grundlagen
Programmierung
Stephan Kleuker
}
}
184
Schleife
Grundlagen Programmierung
Stephan Kleuker
185
Eingabedialog und Schleife
• Student-Objekt soll durch Tastatureingabe im Dialog erstellt
werden
• Erstellung soll in neuer Klasse Studentenverwaltung liegen
• Bei der Eingabe sollen Randbedingungen überprüft werden,
wie: der eingegebene String ist nicht leer
• Informeller Ansatz: Solange ein ungewünschter Wert
eingegeben wird, soll die Eingabe wiederholt werden
• Neues Sprachkonstrukt: Schleife
Solange folgende Bedingung gilt,
wiederhole folgende Schritte
Grundlagen Programmierung
Stephan Kleuker
186
Korrekte Eingabe des Vornamens
public class Studentenverwaltung{
public Student studentEingeben(){
Student ergebnis = new Student();
EinUndAusgabe io = new EinUndAusgabe();
String tmpVorname = "";
while(tmpVorname.equals("")){
io.ausgeben("Vorname: ");
tmpVorname = io.leseString();
}
ergebnis.setVorname(tmpVorname);
return ergebnis;
}
}
Grundlagen Programmierung
Stephan Kleuker
187
Ausprobieren in Studentspielerei (1/2)
public class Studentspielerei{
public void eingeben(){
Studentenverwaltung sv = new Studentenverwaltung();
Student ein = sv.studentEingeben();
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben(""+ein);
}
}
Grundlagen Programmierung
Stephan Kleuker
188
Ausprobieren in Studentspielerei (2/2)
Grundlagen Programmierung
Stephan Kleuker
189
Syntaxanalyse von while
while(tmpVorname.equals("")){
io.ausgeben("Vorname: ");
tmpVorname = io.leseString();
}
• Boolescher Ausdruck
(Bedingung) in runden
Klammern, Ausdruck in der
Klammer muss nach true
oder false ausgewertet
werden
Grundlagen Programmierung
• Programmfragment in
geschweiften Klammern;
wird ausgeführt, wenn
Ausdruck nach true
ausgewertet wird
• nach Programmfragmentausführung wird
Boolescher Ausdruck
erneut ausgewertet
Stephan Kleuker
190
Visualisierung im Aktivitätsdiagramm - generell
while ( <Bedingung> ) {
<Teilprogramm>
}
[!<Bedingung>]
• Raute am Anfang, in der
sich zwei Abläufe (Start
und Wiederholung)
vereinigen (auch als zwei
Rauten darstellbar)
• generell soll nur ein Pfeil
in eine Aktion laufen
Grundlagen Programmierung
[<Bedingung>]
<Teilprogramm>
Stephan Kleuker
191
Visualisierung der Methode
Student ergebnis = new Student()
EinUndAusgabe io = new EinUndAusgabe()
String tmpVorname = ""
[!tmpVorname.equals("")]
[tmpVorname.equals("")]
io.ausgeben("Vorname: ")
ergebnis.setVorname(tmpVorname)
tmpVorname = io.leseString()
Grundlagen Programmierung
Stephan Kleuker
return ergebnis
192
Klasse EinUndAusgabe.java
Methode
Nutzung
EinUndAusgabe()
Konstruktor
leseString()
Text einlesen bis "Return"
Integer-Objekt einlesen, default -1
Boolean-Objekt einlesen, default false
leseInteger()
leseBoolean()
leseDouble()
ausgeben(String)
zufall(Integer,
Integer)
Double-Objekt einlesen, default -1.0
Ausgabe des Strings auf der Konsole
erzeugt zufälligen Integer-Wert zwischen den
angegebenen Grenzen (inklusive)
Grundlagen Programmierung
Stephan Kleuker
193
Vervollständigung der Eingabe (1/4)
• Man kann jetzt ein vergleichbares Programmfragment für
alle Objektvariablen schreiben
• aber Grundregel erinnern: kein Code wiederholen
• Ansatz schreibe Hilfsmethoden
– zum Einlesen eines nicht leeren Textes
– zum Einlesen einer ganzen Zahl aus einem Intervall
[untereGrenze, obereGrenze]
• Hinweis 1: Software-Ergonomie nicht berücksichtigt
• Hinweis 2: Eingabe mehrerer Leerzeichen wird als korrekter
Text erkannt; String hat Methode trim() mit der alle
umgebenden Leerzeichen entfernt werden
Grundlagen Programmierung
Stephan Kleuker
194
Vervollständigung der Eingabe (2/4)
private String nichtLeererText(String aufforderung){
String ergebnis = "";
EinUndAusgabe io = new EinUndAusgabe();
while(ergebnis.equals("")){
io.ausgeben(aufforderung+": ");
ergebnis = io.leseString();
ergebnis = ergebnis.trim();
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
195
Vervollständigung der Eingabe (3/4)
private Integer zahlZwischen(String aufforderung,
Integer untereGrenze, Integer obereGrenze ){
Integer ergebnis = untereGrenze - 1;
EinUndAusgabe io = new EinUndAusgabe();
while(ergebnis < untereGrenze || ergebnis > obereGrenze){
io.ausgeben(aufforderung+": ");
ergebnis = io.leseInteger();
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
196
Vervollständigung der Eingabe (4/4)
public Student studentEingeben(){
Student ergebnis = new Student();
ergebnis.setVorname(nichtLeererText("Vorname"));
ergebnis.setNachname(nichtLeererText("Nachname"));
ergebnis.setStudiengang(nichtLeererText("Studiengang"));
ergebnis.setGeburtsjahr(
zahlZwischen("Geburtsjahr",1900,2000));
ergebnis.setMatrikelnummer(
zahlZwischen("Matrikelnummer",99999,1000000));
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
197
Beispiel für einen Nutzungsdialog
Grundlagen Programmierung
Stephan Kleuker
198
Analyse der Methodenschachtelung (1/2)
• Möglichkeit 1: Ergebnisobjekt wird Parameter eines neuen
Methodenaufrufs
ergebnis.setVorname(nichtLeererText("Vorname"));
alternativ:
String tmp = nichtLeererText("Vorname");
ergebnis.setVorname(tmp);
• Möglichkeit 2: auf berechnetem Ergebnisobjekt wird direkt
nächste Methode aufgerufen
ergebnis = io.leseString().ttrim();
alternativ:
String tmp = io.leseString();
ergebnis = tmp.trim();
Grundlagen Programmierung
Stephan Kleuker
199
Analyse der Methodenschachtelung (2/2)
• Ist Methodenschachtelung besser als schrittweise
Berechnung?
• Vorteil: Programme werden kürzer
• Vorteil: keine zusätzlichen Variablen (kein echter Vorteil, da
Kompilierer den Zwischenschritt wegoptimiert)
• Nachteil: wenn Hilfsvariable sinnvollen Namen hat, steigt
die Lesbarkeit
• Fazit: Gerade bei Anfängern sind Schachtelungen nicht
notwendig
• Grundregel: Programme müssen so geschrieben werden,
dass der unerfahrenste Programmierer im Projekt diese
verstehen und bearbeiten kann
Grundlagen Programmierung
Stephan Kleuker
200
Weitere Kürzungsmöglichkeit
• statt
public Boolean issesAndreas(){
if("Andreas".equals(this.name)){
return true;
}
return false;
}
• auch
public Boolean issesAndreas(){
return "Andreas".equals(this.name);
}
Grundlagen Programmierung
Stephan Kleuker
201
Gefahr der Endlosschleifen
• Schleifen haben immer die Gefahr, nicht zu terminieren
while(ergebnis < untereGrenze || ergebnis > obereGrenze){
• z. B. Nutzer "weigert sich" sinnvollen Wert einzugeben
• aber auch wenn z. B. untereGrenze = 1 und obereGrenze = 0
Nutzer hat keine Chance für Eingabe, um Schleife zu
beenden
• Programme benötigen Abbruchmöglichkeiten
• häufig: Betriebssystemprozess terminieren
• Entwicklungsumgebungen bieten immer
Abbruchmöglichkeit (in BlueJ Debugger aufrufen und
"Terminieren" wählen)
Grundlagen Programmierung
Stephan Kleuker
202
Hölzerne Programmierung
private String nichtLeererText(String aufforderung){
String ergebnis = "";
while(ergebnis.equals("")){
EinUndAusgabe io = new EinUndAusgabe(); // aua
io.ausgeben(aufforderung+": ");
ergebnis = io.leseString();
ergebnis = ergebnis.trim();
}
return ergebnis;
}
• so muss immer wieder neues Objekt für io erzeugt werden
(langsam; Java-Compiler optimiert zum Glück)
Grundlagen Programmierung
Stephan Kleuker
203
Regeln zur Nutzung lokaler Variablen
• lokale Variablen möglichst genau da deklarieren, wo sie
benötigt werden
• wenn möglich, sollten lokale Variablen nicht lange leben
(nicht mal genutzt und viele Zeilen später wieder genutzt
werden)
• lokale Variablen sollen sprechende Namen haben
(irgendwas mit tmp vielleicht akzeptabel, wenn Variable
drei Zeilen später stirbt)
• lokale Variablen nur innerhalb von Schleifen deklarieren,
wenn es sich um wahrscheinlich unterschiedlich genutzte
Objekte handelt
Grundlagen Programmierung
Stephan Kleuker
204
Schleifen-Variante - Beispiel
private String nichtLeererText(String aufforderung){
String ergebnis;
EinUndAusgabe io = new EinUndAusgabe();
do{
io.ausgeben(aufforderung+": ");
ergebnis = io.leseString();
ergebnis = ergebnis.trim();
}while(ergebnis.equals(""));
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
205
Analyse der do-Schleife
do {
<Teilprogramm>
} while (<Bedingung>)
<Teilprogramm>
• wird mindestens einmal
durchlaufen
• Schleife wird wiederholt
[<Bedingung>]
[!<Bedingung>]
solange Bedingung wahr ist
• heißt auch fußgesteuerte Schleife (while ist
kopfgesteuerte Schleife)
• jede while-Schleife ist in do-Schleife verwandelbar und
umgekehrt
• viele Programmierer verzichten auf do-Schleife
Grundlagen Programmierung
Stephan Kleuker
206
switch
Grundlagen Programmierung
Stephan Kleuker
207
Einfacher Nutzungsdialog mit switch (1/3)
• Typische Dialogstruktur mit Auswahlalternativen
• würde langes verschachteltes if benötigen
public class Minidialog {
public void dialog(){
EinUndAusgabe io = new EinUndAusgabe();
Integer ein = -1;
while(ein != 0){
io.ausgeben("(0) Programmende\n"
+"(1) waschen, f\u00f6hnen, schneiden\n"
+"(2) schneiden\n"
+"(3) rasieren\n"
+" Ihre Auswahl: ");
ein = io.leseInteger();
Grundlagen Programmierung
Stephan Kleuker
208
Einfacher Nutzungsdialog mit switch (2/3)
}
switch(ein){
case 0: {
break;
}
case 1: {
io.ausgeben("wash and dry\n");
}
case 2: {
io.ausgeben("cut\n");
break;
}
case 3: {
io.ausgeben("shave\n");
break;
}
default: {
io.ausgeben("Zahl zwischen 0 und 3\n");
break;
}
}
Grundlagen
Programmierung
}
}
Stephan Kleuker
209
Einfache Nutzungsdialog mit switch (3/3)
• Beispieldialog
(0) Programmende
(1) waschen, föhnen, schneiden
(2) schneiden
(3) rasieren
Ihre Auswahl: 4
Zahl zwischen 0 und 3
(0) Programmende
(1) waschen, föhnen, schneiden
(2) schneiden
(3) rasieren
Ihre Auswahl: 3
shave
(0) Programmende
(1) waschen, föhnen, schneiden
(2) schneiden
(3) rasieren
Ihre Auswahl: 2
cut
Grundlagen Programmierung
(0) Programmende
(1) waschen, föhnen, schneiden
(2) schneiden
(3) rasieren
Ihre Auswahl: 1
wash and dry
cut
(0) Programmende
(1) waschen, föhnen, schneiden
(2) schneiden
(3) rasieren
Ihre Auswahl: 0
Stephan Kleuker
210
Syntaxanalyse von switch
switch(ein){
case 0: {
break;
}
case 1: {
io.ausgeben("wash");
}
case 2: {
io.ausgeben("cut\n");
break;
}
default: {
io.ausgeben("Fehler");
break;
}
}
Grundlagen Programmierung
Stephan Kleuker
Ausdruck, der zu einer Zahl
oder einem Buchstaben (ab
Java 7 auch String)
ausgewertet wird
Konstante, die zum Typ des
Ausdruck passt; stimmen
die Werte überein, wird
zugehöriges Teilprogramm
ausgeführt
break zum Verlassen des
Blocks, sonst werden
Anweisungen des
Folgeblocks ausgeführt
default ist optional;
genutzt, wenn kein anderer
Fall zutrifft
211
Aktivitätsdiagramm für switch
[ein==0]
break
[ein==1]
[ein==2]
io.ausgeben("wash")
[!(ein==0 || ein==1
|| ein==2)]
io.ausgeben("Fehler")
io.ausgeben("cut\n")
break
Grundlagen Programmierung
Stephan Kleuker
break
212
Programmfragment mit if statt switch
}
}
if (ein == 0) {
;
} else {
if (ein == 1 || ein == 2) {
io.ausgeben("wash and dry\n");
if (ein == 2) {
io.ausgeben("cut\n");
}
} else {
if (ein == 3) {
io.ausgeben("shave\n");
} else {
io.ausgeben("Zahl zwischen 0 und 3\n");
}
}
}
Grundlagen Programmierung
Stephan Kleuker
213
Schleife 2
Grundlagen Programmierung
Stephan Kleuker
214
Weitere Schleifenbeispiele
• Innerhalb von Methoden "spürt" man wenig von
Objektorientierung (hauptsächlich Aufruf von Methoden)
• man greift auf Objektvariablen zu und deklariert lokale
Hilfsvariablen
• folgende Beispiele fokussieren Zahlen und Sammlungen von
Zahlen (genauer ArrayList)
• Methoden liegen in der Klasse
public class Zahlenanalyse {
private ArrayList<Integer> zahlen;
private String name = "default";
public Zahlenanalyse(ArrayList<Integer> zahlen) {
this.zahlen = zahlen;
} …
• name kann z. B. Messwerte oder Lottozahlen sein
Grundlagen Programmierung
Stephan Kleuker
215
weiterer Konstruktor, get – und set – Methoden
public Zahlenanalyse(ArrayList<Integer> zahlen, String name) {
this(zahlen);
this.name = name;
}
public ArrayList<Integer> getZahlen() {
return this.zahlen;
}
public void setZahlen(ArrayList<Integer> zahlen) {
this.zahlen = zahlen;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
Grundlagen
Programmierung
Stephan Kleuker
216
Ausgabe eines Zahlenintervalls
• gebe auf der Konsole alle Zahlen ausgehend von einem
Startwert bis zu einem Endwert (jeweils einschließlich) aus
public void zeigeZahlen(Integer start, Integer ende){
Integer zaehler = start;
EinUndAusgabe io = new EinUndAusgabe();
while(zaehler <= ende){
io.ausgeben(" "+zaehler);
zaehler = zaehler +1;
}
}
Grundlagen Programmierung
Stephan Kleuker
217
Methode ausführen
• Erzeuge Objekt der Klasse Zahlenanalyse mit Namen zahlenan1
-3 -2 -1 0 1 2 3
Grundlagen Programmierung
Stephan Kleuker
218
Schmuddelige Variante
• man kann in Methoden übergebene Objekte über deren
Methoden verändern (wichtig, später mehr)
• Grundregel: man soll nie Parameter als Hilfsvariablen nutzen
public void zeigeZahlenX(Integer start, Integer ende){
EinUndAusgabe io = new EinUndAusgabe();
while(start <= ende){
io.ausgeben(" "+start);
start = start +1; //geht, ist aber bah
}
}
Grundlagen Programmierung
Stephan Kleuker
219
Zeige Gerade Zahlen in einem Intervall
• typisch: Innerhalb der Schleife wird jedes Element
analysiert, ob es bestimmte Eigenschaft hat
public void zeigeGeradeZahlen(Integer start, Integer ende){
Integer zaehler = start;
EinUndAusgabe io = new EinUndAusgabe();
while(zaehler <= ende){
if(zaehler % 2 == 0){
io.ausgeben(" "+zaehler);
}
zaehler = zaehler + 1;
}
}
• untypisch: Berechnung und Ausgabe innerhalb einer
Methode, besser: eine Methode für Berechnungen, eine
Methode für Ausgaben (u. a. Ausgabe leicht änderbar)
Grundlagen Programmierung
Stephan Kleuker
220
Aufteilung von Berechnung und Ausgabe (1/3)
public void geradeZahlenAus(Integer start, Integer ende){
if (this.zahlen == null){
this.zahlen = new ArrayList<Integer>();
}
Integer zaehler = start;
while(zaehler <= ende){
if(zaehler % 2 == 0){
this.zahlen.add(zaehler);
}
zaehler = zaehler + 1;
}
}
• Hier Nutzung der Objektvariable zahlen
• generell erst prüfen, ob zahlen==null, sonst Fehler
• was passiert bei mehrmaligem Aufruf?
Grundlagen Programmierung
Stephan Kleuker
221
Aufteilung von Berechnung und Ausgabe (2/3)
• einfaches Iterieren über eine Liste mit get und size (etwas
hölzern, siehe später)
public void listeUntereinanderAusgeben(){
EinUndAusgabe io = new EinUndAusgabe();
Integer zaehler = 0;
while(zaehler < this.zahlen.size()){
io.ausgeben("\t"+this.zahlen.get(zaehler)+"\n");
zaehler = zaehler + 1;
}
}
Grundlagen Programmierung
Stephan Kleuker
222
Aufteilung von Berechnung und Ausgabe (3/3)
• Ausprobieren in nutzender Hilfsklasse
import java.util.ArrayList;
public class ZahlenanalyseSpielerei {
public void zeigeGeradeZahlen(){
EinUndAusgabe io = new EinUndAusgabe();
Startwert: -3
Zahlenanalyse zana = new Zahlenanalyse(null); Endwert: 3
-2
io.ausgeben("Startwert: ");
0
Integer start = io.leseInteger();
2
io.ausgeben("Endwert: ");
Integer ende = io.leseInteger();
zana.geradeZahlenAus(start, ende);
zana.listeUntereinanderAusgeben();
}
}
Grundlagen Programmierung
Stephan Kleuker
223
Algorithmus
Grundlagen Programmierung
Stephan Kleuker
224
Primzahlanalyse – Aufgabenstellung
• Primzahl: Natürliche Zahl n mit zwei Teilern: 1 und n
• konkret: 2, 3 ,5 ,7, …
• erste Überlegung zum Berechnungsverfahren (Algorithmus):
– Eingabe soll ein Integer-Objekt n sein
– nimm zunächst an, dass es eine Primzahl ist
– prüfe von zwei aufsteigend bis n, ob n durch diese Zahl
teilbar ist; ist es so, dann ist es keine Primzahl
– gib Ergebnis zurück
– da ganze Zahl übergeben wird, muss für nicht-natürliche
Zahlen die Antwort false sein (da Primzahlen erst bei
zwei beginnen, gilt das Ergebnis für alle n<2)
Grundlagen Programmierung
Stephan Kleuker
225
Primzahlanalyse – Version 0 (nicht schlecht)
public Boolean istPrimzahl0(Integer zahl){
if (zahl<2){
return false;
}
Boolean ergebnis = true;
Integer testwert = 2;
while(testwert<zahl){
if(zahl%testwert == 0){
ergebnis = false;
}
testwert = testwert + 1;
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
226
Primzahlanalyse – Version 1 (optimiert)
• gerade Zahlen ausschließen
• Schleife beenden, wenn es keine Primzahl ist
public Boolean istPrimzahl(Integer zahl){
if (zahl<2){
return false;
}
Boolean ergebnis = ((zahl % 2 != 0) || (zahl == 2));
Integer testwert = 3;
while(testwert<zahl && ergebnis == true){
if(zahl%testwert == 0){
ergebnis = false;
}
testwert = testwert + 2;
}
return ergebnis;
}
• fehlt: Schleife nur bis Wurzel aus n laufen lassen
Grundlagen Programmierung
Stephan Kleuker
227
Der Begriff des Algorithmus (1/2)
• Ein Algorithmus ist ein Verfahren (genauer die Beschreibung
eines Verfahrens) zur Lösung einer gegebenen Aufgabe
• “Algorithmus” ist einer der zentralen Begriffe der Informatik,
aber auch bekannt in vielen anderen Zusammenhängen, z. B.
– Kochrezept
– Anweisung zum Zusammenbau eines Geräts,
Möbelstücks, . . .
– Gebrauchsanweisung
– Musik-Noten
• Die Beschreibung eines Algorithmus kann in sehr
unterschiedlicher Form (Sprache) gegeben werden, z. B.
Programmiersprache
Grundlagen Programmierung
Stephan Kleuker
228
Der Begriff des Algorithmus (2/2)
• Der Begriff leitet sich ab von der latinisierten Form des
Namens Muhammad ibn Musa Al-Khwarizmi
• (Abu Ja’far) Muhammad ibn Musa Al-Khwarizmi:
– bedeutender Mathematiker und Astronom,
– lebte ca. 780 – 840, hauptsächlich in Bagdad
– führte Null und Dezimalsystem in westliche Welt ein
– Sein Text Hisab al-jabr w’al-muqabala ist erstes Lehrbuch
zur Algebra,
– beschreibt insbesondere das Lösen von Gleichungen;
– der Begriff “Algebra” ist vom Titel abgeleitet
Grundlagen Programmierung
Stephan Kleuker
229
Eigenschaften von Algorithmen
Eigenschaft
Bedeutung
Komplexität charakterisiert den für die Ausführung erforderlichen
Aufwand an Rechenzeit und Speicherplatz
Effizienz
der Algorithmus kommt mit möglichst wenig Zeit- und
Speicheraufwand aus
Endlichkeit Beschreibung des Algorithmus ist von endlicher Länge
(statisch)
Endlichkeit für Ausführung benötigten Ressourcen (Speicherplatz,
(dynamisch) Rechenzeit) sind jederzeit endlich
Terminiert- für jede zulässige Eingabe liefert der Algorithmus nach
heit
endlich vielen Schritten ein Ergebnis
DetermiZu jeder Aktion existiert in einem Algorithmus
nismus
höchstens eine Folgeaktion und der
Berechnungsablauf ist dadurch eindeutig bestimmt
DetermiAusgabewerte eindeutig durch die Eingabewerte
niertheit
bestimmt (Determinismus impliziert Determiniertheit)
Grundlagen Programmierung
Stephan Kleuker
230
Eigenschaften von istPrimzahl(Integer zahl)
Eigenschaft
Bedeutung
Komplexität Schrittanzahl klar von Eingabe abhängig,
benötigte Variablen einfach ablesbar
Effizienz
Version 1 ist schneller als Version 0 (weniger Schritte)
Endlichkeit
(statisch)
Endlichkeit
(dynamisch)
Terminiertheit
Determinismus
ca. 14 Zeilen
Determiniertheit
für jeden Integer-Wert jederzeit das gleiche Ergebnis
Speicher nur für Variablen ergebnis und testwert,
Rechenzeit begrenzt durch zahl*x Schritte
klare, für bestimmte Zahl immer gleiche Antwort:
true oder false
Sequenz, Schleife mit ja oder nein, if mit einem Fall
Grundlagen Programmierung
Stephan Kleuker
231
Zentrale Aufgabe: Algorithmen optimieren
•
•
•
•
0. Schritt: Klare Definition der Aufgabenstellung
1. Schritt: Entwicklung einer Lösung
2. Schritt: Optimierung der Lösung
Abhängig von der Relevanz der Aufgabenstellung steigt oder
fällt die Optimierungsbedeutung
• Bremsen im Auto, Turbulenzen beim Fliegen, andere
Umwelteinflüsse beim Raketenstart, auf einen zufliegender
Flugkörper, minimale Schwankung des Aktienpreises:
Effizienz bekommt enorme Bedeutung!
•  Vorlesung "Algorithmen und Datenstrukturen" (nicht nur
Verfahren, auch Schulung der Denkweise)
Grundlagen Programmierung
Stephan Kleuker
232
Bestimme Primzahl in einem Zahlenbereich
•
Aufgabe: Fülle Liste in Zahlenanalyse mit Primzahlen aus
einem vorgegebenen Bereich
public void zahlbereichMitPrim(Integer start, Integer ende) {
if (zahlen == null){
this.zahlen = new ArrayList<Integer>();
}
Integer zaehler = start;
while (zaehler <= ende) {
if (istPrimzahl(zaehler)) {
this.zahlen.add(zaehler);
}
zaehler = zaehler + 1;
}
}
Grundlagen Programmierung
Stephan Kleuker
233
Listenauswahl
• Suche alle Zahlen, die mit der Ziffer 3 enden und füge sie in
ein neues Objekt der Klasse Zahlenanalyse
public Zahlenanalyse zahlenMitDreiAmEnde() {
ArrayList<Integer> ergebnis = new ArrayList<Integer>();
Integer zaehler = 0;
if (this.zahlen != null) {
while (zaehler < this.zahlen.size()) {
Integer element = this.zahlen.get(zaehler);
if (element % 10 == 3) {
ergebnis.add(element);
}
zaehler = zaehler + 1;
}
}
return new Zahlenanalyse(ergebnis);
}
Grundlagen Programmierung
Stephan Kleuker
234
geschachtelte Schleifen
Grundlagen Programmierung
Stephan Kleuker
235
Einschub: Ineinander geschachtelte Schleifen
• die innere Schleife wird für jedes Element der äußeren
Schleife durchlaufen !!!
public void schleifeInSchleife(){
EinUndAusgabe io = new EinUndAusgabe();
Integer zaehler = 0;
while (zaehler < 5){
Integer zaehler2 = 20;
while (zaehler2 < 25){
io.ausgeben(zaehler+":"+zaehler2+" ");
zaehler2 = zaehler2 + 1;
0:20 0:21 0:22
}
1:20 1:21 1:22
zaehler = zaehler + 1;
2:20 2:21 2:22
io.ausgeben("\n");
3:20 3:21 3:22
4:20 4:21 4:22
}
}
Grundlagen
Programmierung
Stephan Kleuker
0:23
1:23
2:23
3:23
4:23
0:24
1:24
2:24
3:24
4:24
236
Strukturierte Ausgabe in Zahlenanalyse
• in jeder Zeile genau anzahl Elemente (Ausnahme letzte Zeile)
• Zwei Schleifen mit einem äußeren und einem inneren Zähler
public void strukturiertAusgeben(Integer anzahl){
if (this.zahlen == null){
return;
}
EinUndAusgabe io = new EinUndAusgabe();
Integer zaehler = 0;
while(zaehler < this.zahlen.size()){
Integer zeilenzaehler = 0;
while(zeilenzaehler<anzahl && zaehler < this.zahlen.size()){
io.ausgeben(""+this.zahlen.get(zaehler)+"\t");
zeilenzaehler = zeilenzaehler + 1;
zaehler = zaehler + 1;
}
io.ausgeben("\n");
}
Grundlagen Programmierung
Stephan Kleuker
237
}
Strukturierte Ausgabe - Variante
• hier geht es auch ohne doppelte Schleifen
public void strukturiertAusgeben(Integer anzahl) {
if (zahlen == null){
return;
}
EinUndAusgabe io = new EinUndAusgabe();
Integer zaehler = 0;
while (zaehler < this.zahlen.size()) {
io.ausgeben("" + this.zahlen.get(zaehler) + "\t");
zaehler = zaehler + 1;
if(zaehler % anzahl == 0){
io.ausgeben("\n");
}
}
}
Grundlagen Programmierung
Stephan Kleuker
238
Anwendung bisheriger Methoden
public void primAnalysieren(){
Zahlenanalyse zana = new Zahlenanalyse(null);
zana.zahlbereichMitPrim(100, 470);
Zahlenanalyse tmp = zana.zahlenMitDreiAmEnde();
tmp.strukturiertAusgeben(5);
}
103
113
163
173
193
223
233
263
283
293
313
353
373
383
433
443
463
letzten beiden Zeilen alternativ zusammengefasst als:
zana.zahlenMitDreiAmEnde().strukturiertAusgeben(5)
Grundlagen Programmierung
Stephan Kleuker
239
Gemeinsamkeit (1/3)
• Aufgabe: Gibt es in zwei Listen gemeinsame Elemente?
• Ansatz: Annahme, es gibt keine gemeinsamen Elemente, bis
eines gefunden ist
• Nimm erstes Element der ersten Liste und überprüfe mit
jedem Element der zweiten Liste ob diese gleich sind, wenn
true, gibt Antwort aus
• …
• Nimm letztes Element der ersten Liste und überprüfe mit
jedem Element der zweiten Liste ob diese gleich sind, wenn
true, gibt Antwort aus
• Gib false als Antwort aus
Grundlagen Programmierung
Stephan Kleuker
240
Gemeinsamkeit (2/3)
public Boolean gibtGleiche(Zahlenanalyse other) {
ArrayList<Integer> liste = other.getZahlen();
Integer zaehler1 = 0;
while (zaehler1 < this.zahlen.size()) {
Integer zaehler2 = 0;
while (zaehler2 < liste.size()) {
if(this.zahlen.get(zaehler1).equals(liste.get(zaehler2))){
return true;
}
Achtung, hier fehlt was:
zaehler2 = zaehler2 + 1;
Es fehlen die Prüfungen,
}
ob eine der Listen null ist
zaehler1 = zaehler1 + 1;
(Fehler werden wir
später finden)
}
return false;
}
Grundlagen Programmierung
Stephan Kleuker
241
Gemeinsamkeit (3/3)
public void gleicheAnalysieren() {
Zahlenanalyse tmp1 = new Zahlenanalyse(null);
tmp1.geradeZahlenAus(1, 23);
Zahlenanalyse tmp2 = new Zahlenanalyse(null);
tmp2.geradeZahlenAus(23, 42);
Zahlenanalyse tmp3 = new Zahlenanalyse(null);
tmp3.geradeZahlenAus(22, 32);
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("tmp1 und tmp2: "+tmp1.gibtGleiche(tmp2)+
io.ausgeben("tmp2 und tmp1: "+tmp2.gibtGleiche(tmp1)+
io.ausgeben("tmp1 und tmp3: "+tmp1.gibtGleiche(tmp3)+
io.ausgeben("tmp3 und tmp1: "+tmp3.gibtGleiche(tmp1)+
}
tmp1 und tmp2: false
tmp2 und tmp1: false
tmp1 und tmp3: true
tmp3 und tmp1: true
Grundlagen Programmierung
Stephan Kleuker
"\n");
"\n");
"\n");
"\n");
242
Iterator
Grundlagen Programmierung
Stephan Kleuker
243
Effizientere Listenbearbeitung - Iterator
• Problem: Der Zugriff mit get(i) ist relativ langsam, man kann
schneller von i zum i+1-Element manövrieren
• Zur schrittweisen Bearbeitung von Listen gibt es IteratorObjekte; Objekte kennt aktuell betrachtetes Element
• Listen haben Methode iterator(); gibt Iteratorobjekt
• Auszug aus Methoden von Iterator<T>
MethoParameter Ergebnis
denname
hasNext
Boolean
Beschreibung
next
gibt aktuelles Element des
Iterators zurück und setzt ihn
ein Element weiter
Grundlagen Programmierung
Typ
gibt es für Iterator nächstes
Element?
Stephan Kleuker
244
Iteratornutzung - allgemein
X
Z
liste
Z
liste
Iterator<Integer> i = liste.iterator()
i.hasNext() ergibt true
X
liste.next() ergibt X und Iterator wird Feld weiter gesetzt
i.hasNext() ergibt true
X
Z
liste
liste.next() ergibt Z und Iterator wird Feld weiter gesetzt
i.hasNext() ergibt false
Grundlagen Programmierung
Stephan Kleuker
245
Methodenvergleich
public void listeUntereinanderAusgebenIterator() {
EinUndAusgabe io = new EinUndAusgabe();
Iterator<Integer> it = this.zahlen.iterator();
while (it.hasNext()) {
io.ausgeben("\t" + it.next() + "\n");
}
}
public void listeUntereinanderAusgebenAlt() {
EinUndAusgabe io = new EinUndAusgabe();
Integer zaehler = 0;
while (zaehler < this.zahlen.size()) {
io.ausgeben("\t" + this.zahlen.get(zaehler) + "\n");
zaehler = zaehler + 1;
}
}
Grundlagen Programmierung
Stephan Kleuker
246
Analyse vom Iterator
• sehr einfacher Durchlauf durch die Liste
• (meist) etwas schnellerer Durchlauf durch die Liste
• sicherer Durchlauf, da man nicht einfach auf nicht existente
Elemente zugreifen kann
• es ist allerdings nicht möglich, die Nummer (Position) des
betrachteten Elements auszugeben (mit mitlaufender
Zählvariable schon)
Grundlagen Programmierung
Stephan Kleuker
247
for
Grundlagen Programmierung
Stephan Kleuker
248
for-Schleife
• häufig sehr ähnliche Struktur einer Schleife
Integer zaehler = 0;
while (zaehler …) {
// do something
zaehler = zaehler + 1;
}
• für Schleifen mit festem Start- und Endwert gibt es Variante
for(Integer zaehler = 0; zaehler…; zaehler = zaehler+1)
for( <Startanweisung>; <Abbruchbedingung>;
<AnweisungNachTeilprogramm>) {
<Teilprogramm>
}
Grundlagen Programmierung
Stephan Kleuker
249
Schleifenvergleich
public void zeigeZahlen(Integer start, Integer ende) {
Integer zaehler = start;
EinUndAusgabe io = new EinUndAusgabe();
while (zaehler <= ende) {
io.ausgeben(" " + zaehler);
zaehler = zaehler + 1;
}
}
public void zeigeZahlenFor(Integer start, Integer ende) {
EinUndAusgabe io = new EinUndAusgabe();
for(Integer zaehler = start; zaehler<= ende;
zaehler = zaehler+1){
io.ausgeben(" " + zaehler);
}
}
Grundlagen Programmierung
Stephan Kleuker
250
for-Schleife als Aktivitätsdiagramm
for(Integer zaehler = start; zaehler<= ende;
zaehler = zaehler+1){
io.ausgeben(" " + zaehler);
}
Integer zaehler = start
[!(zaehler<= ende)]
[zaehler<= ende]
io.ausgeben(" " + zaehler)
zaehler = zaehler+1
Grundlagen Programmierung
Stephan Kleuker
251
for-Schleife mit Iterator
public void listeUntereinanderAusgebenIterator() {
EinUndAusgabe io = new EinUndAusgabe();
Iterator<Integer> it = this.zahlen.iterator();
while (it.hasNext()) {
io.ausgeben("\t" + it.next() + "\n");
}
}
public void listeUntereinanderAusgebenIteratorFor() {
EinUndAusgabe io = new EinUndAusgabe();
for(Iterator<Integer> it = this.zahlen.iterator();
it.hasNext();) {
io.ausgeben("\t" + it.next() + "\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
252
Regeln für for-Schleifen
for( <Startanweisung>; <Abbruchbedingung>;
<AnweisungNachTeilprogramm>)
• erfahrener Programmierer erwartet beim Lesen einer ForSchleife, dass beim Start der Schleife bekannt ist, wie oft sie
durchlaufen wird (Abbruchbedingung nicht im
Schleifenrumpf verändern)
• <Startanweisung> kann leer gelassen werden
• <AnweisungNachTeilprogramm> kann weggelassen werden
Grundlagen Programmierung
Stephan Kleuker
253
for-Schleife mit impliziten Iterator
• Listendurchlauf sieht häufig so aus:
for(Iterator<Integer> it = liste.iterator(); it.hasNext();)
• Ab Java 5: leichte Abkürzung
public void listeUntereinanderAusgebenIteratorForEach() {
EinUndAusgabe io = new EinUndAusgabe();
for(Integer el:this.zahlen) {
io.ausgeben("\t" + el + "\n");
}
}
• Achtung: Nutzung des Iterator-Objekts ist wichtige, sich in
vielen Programmierbereichen wiederholende, Idee zur
Abarbeitung von Sammlungen (Listen, Mengen, Einlesen
von Dateien, Einlesen von Daten aus Datenbank …)
Grundlagen Programmierung
Stephan Kleuker
254
Einfaches Durchlaufen von Sammlungen
for(Integer el: this.zahlen) {
io.ausgeben("\t" + el + "\n");
}
• Sammlung , die durchlaufen werden soll
• Typ der Elemente der Sammlung
• lokale Variable vom Typ der Elemente der
Sammlung; Variable nimmt nacheinander alle
Werte der Sammlung an
• Programm, dass für alle Elemente der Sammlung
ausgeführt wird
Grundlagen der Programmierung
Stephan Kleuker
255
Unit test
Grundlagen Programmierung
Stephan Kleuker
256
Ausprobieren oder systematisch Testen
• bisher werden Methoden zum Ausprobieren direkt in BlueJ
aufgerufen und das Ergebnis manuell überprüft
• um Schritte zusammenzufassen, wurden Hilfsklassen wie
ZahlenAnalyseSpielerei geschrieben
• dieser Ansatz wird durch die Nutzung spezieller Testklassen
vereinfacht:
– Nutzung von JUnit (hier Version 4)
– Tests werden in neuer Klasse (ähnlich zu Spielerei) in
Java geschrieben
– Man kann für Tests gemeinsame Ausgangssituation
schaffen
– Jeder Test läuft unabhängig von anderen Tests
– es gibt spezielle Zusicherungsmethoden zum Überprüfen
Grundlagen Programmierung
Stephan Kleuker
257
Testerstellung in BlueJ
Grundlagen Programmierung
Stephan Kleuker
258
Erste Testfälle (1/2)
import org.junit.Assert;
import org.junit.Test;
public class ZahlenanalyseTest{
@Test
public void testIstPrimzahl1() {
Zahlenanalyse zana = new Zahlenanalyse(null);
Boolean nicht42 = zana.istPrimzahl(42);
Assert.assertTrue("42 ist Primzahl", !nicht42);
}
@Test
public void testIstPrimzahl2() {
Zahlenanalyse zana = new Zahlenanalyse(null);
Boolean doch41 = zana.istPrimzahl(41);
Assert.assertTrue("41 ist keine Primzahl", doch41);
}
}
Grundlagen Programmierung
Stephan Kleuker
259
Erste Testfälle (2/2)
Grundlagen Programmierung
Stephan Kleuker
260
Aufbau der Testklasse
Klassenname
beliebig, üblich:
Name der zu
testenden Klasse
mit "Test" am
Ende
jeder Test in eigener
Methode, sollte mit
"public void test…"
beginnen; Testname
sollte sich auf getestete
Methode beziehen
diese Annotation
(?!?) sorgt für die
Ausführung als
Test[genauer
später]
public class ZahlenanalyseTest {
@Test
public void testIstPrimzahl1() {
Zahlenanalyse zana = new Zahlenanalyse(null);
Boolean nicht42 = zana.istPrimzahl(42);
Assert.assertTrue("42 ist Primzahl", !nicht42);
}
es gibt verschiedene Überprüfungsmethoden (assertTrue
reicht); erster Parameter ist Meldung im Fehlerfall, zweiter
Parameter ist Boolescher Ausdruck (erster Parameter optional)
Grundlagen Programmierung
Stephan Kleuker
261
Test-Fixture (Test-Ausgangskonfiguration)
• Testfall sieht in der Regel so aus, dass eine bestimmte
Konfiguration von Objekten aufgebaut wird, gegen die der
Test läuft
• Menge von Testobjekten wird als Test-Fixture bezeichnet
• Damit fehlerhafte Testfälle nicht andere Testfälle
beeinflussen können, wird die Test-Fixture für jeden Testfall
neu initialisiert
• In der mit @Before annotierten Methode public void setUp()
werden Objektvariablen initialisiert
• In der mit @After annotierten Methode public void
tearDown() werden wertvolle Testressourcen wie zum
Beispiel Datenbank- oder Netzwerkverbindungen wieder
freigegeben
Grundlagen Programmierung
Stephan Kleuker
262
Testklasse leicht umgeschrieben
public class ZahlenanalyseTest {
private Zahlenanalyse zana;
@Before
public void setUp() {
zana = new Zahlenanalyse(null);
}
@Test
public void testIstPrimzahl1() {
Boolean nicht42 = zana.istPrimzahl(42);
Assert.assertTrue("42 ist Primzahl", !nicht42);
}
@Test
public void testIstPrimzahl2() {
Boolean doch41 = zana.istPrimzahl(41);
Assert.assertTrue("41 ist keine Primzahl", doch41);
}
}Grundlagen Programmierung
Stephan Kleuker
263
Prinzipieller Ablauf von JUnit
• Suche in der Testklasse alle Methoden, die mit @Test
annotiert sind,
• führe für jede der gefundenen Methoden folgende Schritte
aus:
– führe setUp (mit @Before annotierte Methode) aus
– führe den Test aus und protokolliere das Ergebnis
– führe tearDown (mit @After annotierte Methode) aus
• im Beispiel: setup(), testIstPrimzahl1(), setup(),
testIstPrimzahl2()
• sollte ein Test scheitern, wird dieser sofort beendet, die
anderen Tests unabhängig davon ausgeführt
• Tests sollten möglichst nur eine Zusicherung (assert…) haben
Grundlagen Programmierung
Stephan Kleuker
264
Wie erstellt man Testfälle
• Grundsätzlich liest man intensiv die Aufgabenstellung und
beantwortet folgende Fragen:
• was sind die typischen Abläufe bzw. typischen Ergebnisse;
für jeden der gefundenen Fälle wird ein Test geschrieben
• was sind die besonderen Randfälle, die auftreten können;
für jeden Randfall wird ein getrennter Testfall geschrieben
• Beispiel: ein Parameter liste vom Typ ArrayList<Integer>
– was passiert, wenn liste==null ist
– was passiert bei einer leeren Liste
– was passiert bei besonderen Listen, die z. B. nur ein
Element, dies aber mehrfach enthalten
Grundlagen Programmierung
Stephan Kleuker
265
Weiteres Testbeispiel (1/4)
// Imports fehlen
public class ZahlenanalyseTest {
private Zahlenanalyse zana42und23;
private Zahlenanalyse zanaNull;
private Zahlenanalyse zana23;
@Before
public void setUp() {
ArrayList<Integer> l1 = new ArrayList<Integer>();
l1.add(42);
l1.add(23);
zana42und23 = new Zahlenanalyse(l1);
zanaNull = new Zahlenanalyse(null);
ArrayList<Integer>l2 = new ArrayList<Integer>();
l2.add(23);
zana23 = new Zahlenanalyse(l2);
}
Grundlagen Programmierung
Stephan Kleuker
266
Weiteres Testbeispiel (2/4)
@Test
public void testZahlenMitDreiAmEnde1(){
Zahlenanalyse tmp = zana42und23.zahlenMitDreiAmEnde();
Assert.assertTrue(tmp.getZahlen().size() == 1);
Assert.assertTrue(tmp.getZahlen().get(0) == 23);
}
@Test
public void testZahlenMitDreiAmEnde2(){
Zahlenanalyse tmp = zanaNull.zahlenMitDreiAmEnde();
Assert.assertTrue(tmp.getZahlen().size() == 0);
}
@Test
public void testZahlenMitDreiAmEnde3(){
Zahlenanalyse tmp = zana23.zahlenMitDreiAmEnde();
Assert.assertTrue(tmp.getZahlen().size() == 1);
Assert.assertTrue(tmp.getZahlen().get(0) == 23);
}
Grundlagen Programmierung
Stephan Kleuker
267
Weiteres Testbeispiel (3/4)
@Test
public void testgibtGleiche1(){
Boolean tmp = zana42und23.gibtGleiche(zanaNull);
Assert.assertTrue(!tmp);
}
@Test
public void testgibtGleiche2(){
Boolean tmp = zana42und23.gibtGleiche(zana23);
Assert.assertTrue(tmp);
}
@Test
public void testgibtGleiche3(){
Boolean tmp = zana23.gibtGleiche(zana42und23);
Assert.assertTrue(!tmp); //?!?
}
Grundlagen Programmierung
Stephan Kleuker
268
Weiteres Testbeispiel (4/4)
ein Test zeigt, dass nullReferenzen nicht
berücksichtigt werden,
anderer Test zeigt falschen
Testfall
Grundlagen Programmierung
Stephan Kleuker
269
Systematische Entwicklung
• Neben echten Denkfehlern befinden sich häufig viele
Flüchtigkeitsfehler in Programmen
• Sinnvoll: Inkrementelle Entwicklung, d. h. nachdem eine
Methode implementiert wurde, werden sofort zugehörige
Testfälle geschrieben
• Variante ist "Test first"; nachdem man die Aufgabenstellung
verstanden hat, programmiert man zunächst die Testfälle
und schreibt dann schrittweise immer mehr Programmteile,
so dass immer mehr Testfälle keine Fehler melden
• man beachte, dass Entwickler betriebsblind gegenüber
ihren eigenen Fehlern werden
Grundlagen Programmierung
Stephan Kleuker
270
Hinweise zu JUnit
• JUnit kann auch zur Organisation von Tests (Gruppierungen)
genutzt werden
• JUnit oder TestNG Standard bei den meisten Entwicklern
• JUnit kann so nicht (nicht einfach) Eingaben in der Konsole
simulieren
• es gibt viele weitere Testwerkzeuge, einige auf Basis von JUnit,
die viele andere Tests automatisiert durchführen können
• Man muss Programme aber auch in Richtung Testbarkeit
entwickeln:
– get- und set-Methoden für alle Objektvariablen
– evtl. private-Methoden public machen
Grundlagen Programmierung
Stephan Kleuker
271
Systematische Objektbearbeitung (1/2)
• hat ein Objekt eine Collection von Objekten (z. B. ArrayList)
in einer Objektvariablen, so gilt folgende Regel zur
Bearbeitung:
• grundsätzlich stellt das Objekt selbst Methoden zur
Verfügung, um die Collection zu bearbeiten, d. h. Elemente
zu suchen
• also schlecht:
Zahlenanalyse tmp = zanaNull.zahlenMitDreiAmEnde();
if(tmp.getZahlen().size() == 0)) ...
• besser: Zahlenanalyse bietet Methoden wie:
– berechneListengroesse()
– hinzufuegen(Integer)
Grundlagen Programmierung
Stephan Kleuker
272
Systematische Objektbearbeitung (2/2)
• Veranschaulichung als schlechte Idee: Organe
herausoperieren, einschicken, bearbeiten, zurückschicken
und wieder einsetzen
• also keine getZahlen()-Methode? Diskutabel
• wir benötigen Methode zum effizienten Testen
• in Tests darf gegen gewisse Regeln verstoßen werden (muss
aber nicht)
• Klassen müssen ab und zu Methoden enthalten, die das
Testen erleichtern bzw. erst ermöglichen
Grundlagen Programmierung
Stephan Kleuker
273
iterativ inkrementelle
Entwicklung
Grundlagen Programmierung
Stephan Kleuker
274
Fallstudie: Studentenverwaltung
• Aufgabenstellung: Zu entwickeln ist eine auf Texteingaben
und Textausgaben basierende Verwaltung von
Studierenden, dabei soll folgende Funktionalität geboten
werden:
– neuen Studenten eintragen und in die Verwaltung
übernehmen
– Studenten anhand der Matrikelnummer suchen
– Vor- und Nachname eines anhand seiner
Matrikelnummer identifizierten Studenten ändern
– Ermittlung der Anzahl der Studierenden in einem
ausgewählten Studiengang
• Die bisherige Klasse Student kann genutzt werden
Grundlagen Programmierung
Stephan Kleuker
275
Zentrale Idee 1: systematische Planung
• welche Klassen benötigt man
• welche Methoden müssen Objekte der Klassen zur
Verfügung stellen
• ersten beiden Schritte werden schrittweise durch
Programmieraufgaben gelehrt und in der Veranstaltung
"Objektorientierte Analyse und Design" aufgearbeitet
• welchen Algorithmus nutzt man in den Methoden
• Erfahrungen einfließen lassen
• ähnliche Aufgaben mit zugehörigen Lösungen studieren
• Algorithmus auf Papier als Aktivitätsdiagramm spezifizieren
• Inkrementell und iterativ entwickeln
Grundlagen Programmierung
Stephan Kleuker
276
Zentrale Idee 2: Inkrementelle Entwicklung
• Programm wird schrittweise entwickelt
• zuerst eine Funktionalität vollständig realisieren, dann
nächste ergänzen
• jede entwickelte Funktionalität wird zuerst getestet, dann
neue hinzugefügt
• nach jeder neuen Funktionalität werden alte Tests
wiederholt
– Vorgehen auch auf Aktivitätsdiagramme übertragbar:
– erst typischen Ablauf (einfache Sequenz) zeichnen
– dann für jede Aktion nacheinander über mögliche
Alternativen nachdenken
Grundlagen Programmierung
Stephan Kleuker
277
Zentrale Idee 3: Iterative Entwicklung
• zuerst nur minimale Implementierung
public void methodeOhneRueckgabe(<Parameter>){
}
public Integer methodeMitRueckgabe(<Parameter>){
return null;
}
• dann typischen Ablauf ergänzen
• dann Alternativen analysieren, Spezialfälle früh abarbeiten
• bei komplexeren Berechnungen über Auslagerung in private
Methoden nachdenken
• bei Code-Wiederholung Auslagerung in private Methode
• (eng verwandt mit Inkrement-Begriff)
Grundlagen Programmierung
Stephan Kleuker
278
Erste Programmplanung
• statt Programmcode steht gewünschte Berechnung in
Aktion
Funktionalität auswählen
[neuer
Studi]
Studentendaten
eintragen und
in Liste
packen
[Studi
suchen]
[Studi
ändern]
Matrikelnummer
eingeben und
zugehörigen
Studenten
ausgeben
Grundlagen Programmierung
[Anzahl
berechnen]
Matrikelnummer
eingeben und
Studentendaten ändern
Stephan Kleuker
[Ende]
Studiengang
eingeben und
zugehörige
Studentenzahl
ausgeben
279
weitere Entwicklung
• nach der ersten Planung kann mit der Realisierung
begonnen werden
• Planung erlaubt hier parallele Arbeiten an einzelnen
Funktionalitäten, nachdem Klassenaufbau geklärt ist
import java.util.ArrayList;
public class Studentenverwaltung{
private ArrayList<Student> studenten;
public Studentenverwaltung(){
this.studenten = new ArrayList<Student>();
}
• hier nur ein Weg vorgestellt
Grundlagen Programmierung
Stephan Kleuker
280
Überlegung zu get- und set-Methoden
• set-Methode und Konstruktor garantieren, dass man nicht
über die leere Liste nachdenken muss
• damit nicht auf "Innereien" gearbeitet wird, gibt es
Methode hinzufuegen
public ArrayList<Student> getStudenten() {
return this.studenten;
}
public void setStudenten(ArrayList<Student> studenten) {
if(studenten != null){
this.studenten = studenten;
}
}
public void hinzufuegen(Student neu){
this.studenten.add(neu);
}
Grundlagen Programmierung
Stephan Kleuker
281
Realisierung des Dialogs (Prinzip bekannt) (1/2)
public void steuern(){
Integer ein = -1;
EinUndAusgabe io = new EinUndAusgabe();
while(ein !=0){
io.ausgeben("N\u00e4chste Aktion:\n"
+ " (0) Programm beenden\n"
+ " (1) Neuen Studenten einf\u00fcgen\n"
+ " (2) Student mit Matrikelnummer suchen\n"
+ " (3) Studierendendaten \u00e4ndern\n"
+ " (4) Studierende pro Studiengang: ");
ein = io.leseInteger();
switch(ein){
case 0: {
break;
}
case 1: {
studentEingeben();
break;
}
Grundlagen Programmierung
Stephan Kleuker
282
Realisierung des Dialogs (Prinzip bekannt) (2/2)
case 2: {
studentSuchen();
break;
}
case 3: {
studentBearbeiten();
break;
}
case 4: {
studentenZaehlen();
break;
}
default: {
io.ausgeben("Zahl zwischen 0 und 4 eingeben\n");
break;
}
}
}
}
io.ausgeben("\n");
Grundlagen Programmierung
Stephan Kleuker
283
Erstes Inkrement mit erster Iteration komplettieren
• Steuerung manuell testbar durch folgende Methoden
public void studentEingeben(){
}
public void studentSuchen(){
}
public void studentBearbeiten(){
}
public void studentenZaehlen(){
}
Grundlagen Programmierung
Stephan Kleuker
284
studentEingeben() mit Hilfsmethoden (bekannt)
• letzte Zeile leicht modifiziert
public void studentEingeben(){
Student ergebnis = new Student();
ergebnis.setVorname(nichtLeererText("Vorname"));
ergebnis.setNachname(nichtLeererText("Nachname"));
ergebnis
.setStudiengang(nichtLeererText("Studiengang"));
ergebnis
.setGeburtsjahr(zahlZwischen("Geburtsjahr",1900,2000));
ergebnis
.setMatrikelnummer(zahlZwischen("Matrikelnummer"
,99999,1000000));
this.studenten.add(ergebnis);
}
Grundlagen Programmierung
Stephan Kleuker
285
studentSuchen() – Aktivitätsdiagramm verfeinern
Iteration 0
Matrikelnummer
eingeben und
zugehörigen
Student
ausgeben
Iteration 2
Matrikelnummer
eingeben
Student suchen
Iteration 1
Matrikelnummer
eingeben
[gefunden]
Student suchen
Student
ausgeben
[nicht
gefunden]
nicht
gefunden
ausgeben
Student ausgeben
Grundlagen Programmierung
Stephan Kleuker
286
Aktion "Student suchen" verfeinert
Student ergebnis = null
Parameter:
Matrikelnummer m
Iterator<Student> it= this.studenten.iterator()
[!it.hasNext()]
[it.hasNext()]
Student s = it.next()
[s hat übergebene
Matrikelnummer m]
ergebnis = s
Grundlagen Programmierung
return ergebnis
[!(s hat
übergebene
Matrikelnummer m)]
Stephan Kleuker
287
studentSuchen() – Realisierung (1/2)
• Berechnung von Ein- und Ausgabe trennen
• Methoden mit gleichen Namen erlaubt, solange
Parametertypen unterschiedlich
public void studentSuchen(){
EinUndAusgabe io = new EinUndAusgabe();
Integer mat = zahlZwischen("Matrikelnummer:"
, 99999, 1000000);
Student s = studentSuchen(mat);
if(s != null){
io.ausgeben("Daten: "+s+"\n");
} else {
io.ausgeben("nicht gefunden\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
288
studentSuchen() – Realisierung (2/2)
• einfacher Iterator, da Liste nicht leer sein kann
• Hinweis: Implementierung erlaubt leider doppelte
Matrikelnummern
public Student studentSuchen(Integer mat){
Student ergebnis = null;
for(Student s:this.studenten){
if(s.getMatrikelnummer().equals(mat)){
ergebnis = s;
Erinnerung:
}
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
289
Aufbau einer Testumgebung
import
import
import
public
org.junit.Assert;
org.junit.Before;
org.junit.Test;
class StudentenverwaltungTest {
private
private
private
private
private
Studentenverwaltung studis;
Student s1 =new Student("Uwe","X",1987,"IMI",424241);
Student s2 =new Student("Ute","Y",1988,"IMI",424242);
Student s3 =new Student("Ulf","X",1989,"MID",424243);
Student s4 =new Student("Uta","B",1987,"MID",424244);
@Before
public void setUp(){
studis = new Studentenverwaltung();
studis.hinzufuegen(s1);
studis.hinzufuegen(s2);
studis.hinzufuegen(s3);
studis.hinzufuegen(s4);
}
Grundlagen Programmierung
Stephan Kleuker
290
studentSuchen() - Tests
• Programme mit direkten Nutzerinteraktionen sind (für uns)
recht schwer testbar, Rest geht aber problemlos
@Test
public void testSuchenErfolgreich(){
Assert.assertTrue(studis.studentSuchen(424242).equals(s2));
}
@Test
public void testSuchenErfolglos1(){
Assert.assertTrue(studis.studentSuchen(434242)==null);
}
@Test
public void testSuchenErfolglos2(){
studis = new Studentenverwaltung();
Assert.assertTrue(studis.studentSuchen(424242)==null);
}
Grundlagen Programmierung
Stephan Kleuker
291
studentBearbeiten() - Aktivitätsdiagramm
Matrikelnummer
eingeben
Matrikelnummer
eingeben und
Studentendaten ändern
Student suchen
[gefunden]
[nicht gefunden]
neuen Vornamen eingeben
nicht
gefunden
ausgeben
neuen Nachnamen eingeben
Student aktualisieren
Grundlagen Programmierung
Stephan Kleuker
292
studentBearbeiten() - Realisierung
private void studentBearbeiten(){
EinUndAusgabe io = new EinUndAusgabe();
Integer mat = zahlZwischen("Matrikelnummer:"
, 99999, 1000000);
Student s = studentSuchen(mat);
if(s == null){
io.ausgeben("nicht gefunden\n");
return;
}
String neuVor = nichtLeererText("neuer Vorname ("
+"alt:"+s.getVorname()+"): ");
String neuNach = nichtLeererText("neuer Nachname ("
+"alt:"+s.getNachname()+"): ");
s.setVorname(neuVor);
s.setNachname(neuNach);
io.ausgeben("neu: "+s);
}
Grundlagen Programmierung
Stephan Kleuker
293
studentenZaehlen() – Aktivitätsdiagramm (1/2)
Iteration 0
Studiengang
eingeben und
zugehörige
Studentenzahl
ausgeben
Grundlagen Programmierung
Iteration 1
Studiengangnamen eingeben
Studierende zählen
Anzahl ausgeben
Stephan Kleuker
294
studentenZaehlen() – Aktivitätsdiagramm (2/2)
Integer ergebnis = 0
Parameter:
Studiengang fach
Iterator<Student> it= this.studenten.iterator()
[!it.hasNext()]
[it.hasNext()]
Student s = it.next()
[s ist im übergebenen
Studiengang fach]
ergebnis =ergebnis +1
Grundlagen Programmierung
return ergebnis
[!(s ist im
übergebenen
Studiengang fach)]
Stephan Kleuker
295
studentenZaehlen() – Realisierung
private void studentenZaehlen(){
EinUndAusgabe io = new EinUndAusgabe();
String fach = nichtLeererText("Studiengang: ");
Integer anzahl = studentenZaehlenIn(fach);
io.ausgeben("in "+fach+": "+anzahl+"\n");
}
private Integer studentenZaehlenIn(String fach){
Integer ergebnis = 0;
for(Student s:this.studenten){
if(s.getStudiengang().equals(fach)){
ergebnis = ergebnis + 1;
}
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
296
studentenZaehlen() - Tests
@Test
public void testZaehlen1(){
Assert.assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
}
@Test
public void testZaehlen2(){
Assert.assertTrue(studis.studentenZaehlenIn("MID").equals(2));
}
@Test
public void testZaehlen3(){
Assert.assertTrue(studis.studentenZaehlenIn("FBI").equals(0));
}
@Test
public void testZaehlen4(){
studis = new Studentenverwaltung();
Assert.assertTrue(studis.studentenZaehlenIn("IMI").equals(0));
}
Grundlagen Programmierung
Stephan Kleuker
297
Beispiel: Inkrementelle Entwicklung
• nächstes Inkrement: Es sollen Studenten gelöscht werden
können. Dazu wird eine Matrikelnummer eingegeben und
der zugehörige Student gelöscht.
• Problem für den Hinterkopf: Wenn man über eine Liste
iteriert, kann man dann in der laufenden Bearbeitung
Elemente entfernen?
Matrikelnummer
eingeben und
Studenten mit
dieser Nummer
löschen
Grundlagen Programmierung
Stephan Kleuker
298
zentraler Löschalgorithmus
Parameter:
Matrikelnummer m
Student ergebnis = null
Iterator<Student> it= this.studenten.iterator()
[!it.hasNext()]
[it.hasNext()]
Student tmp = it.next()
[tmp hat übergebene
Matrikelnummer m]
studenten.remove(tmp)
Grundlagen Programmierung
Stephan Kleuker
[!(tmp hat
übergebene
Matrikelnummer m)]
299
Änderung im Nutzungsdialog
in steuern():
...
+ " (4) Studierende pro Studiengang\n"
+ " (5) Student l\u00f6schen: "); // neu
ein = io.leseInteger();
switch(ein){
...
case 5: {
// neu
studentLoeschen();
break;
}
...
Grundlagen Programmierung
Stephan Kleuker
300
Löschen mit klassischem Iterator
public void studentLoeschen(){
Integer mat = zahlZwischen("Matrikelnummer"
, 99999, 1000000);
studentloeschen(mat);
}
// mit Iterator löschen, recht einfach
public void studentloeschen1(Integer mat) {
EinUndAusgabe io = new EinUndAusgabe();
Iterator<Student> it = studenten.iterator();
while(it.hasNext()){
Student tmp = it.next();
if(tmp.getMatrikelnummer().equals(mat)){
it.remove();
io.ausgeben("Student gel\u00f6scht\n");
}
}
}
Grundlagen Programmierung
Stephan Kleuker
301
Testen
@Test
public void testLoeschenErfolg(){
studis.studentloeschen(424242);
Assert.assertTrue(studis.studentSuchen(424242)==null);
Assert.assertTrue(studis.studentenZaehlenIn("IMI").equals(1));
Assert.assertTrue(studis.studentenZaehlenIn("MID").equals(2));
}
@Test
public void testLoeschenNichtExistent(){
studis.studentloeschen(414242);
Assert.assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
Assert.assertTrue(studis.studentenZaehlenIn("MID").equals(2));
}
Grundlagen Programmierung
Stephan Kleuker
302
Genauere Analyse mit dem Debugger (1/2)
Grundlagen Programmierung
Stephan Kleuker
303
Genauere Analyse mit dem Debugger (2/2)
Grundlagen Programmierung
Stephan Kleuker
304
Löschvariante mit direktem Positionszugriff
// mit einfacher for-Schleife; kritisch bearbeitete
// Liste zu ändern, geht aber
public void studentloeschen(Integer mat) {
EinUndAusgabe io = new EinUndAusgabe();
for(Integer i=0; i<this.studenten.size(); i++){
Student tmp = this.studenten.get(i);
if(tmp.getMatrikelnummer().equals(mat)){
this.studenten.remove(i);
io.ausgeben("Student gel\u00f6scht\n");
}
}
}
Grundlagen Programmierung
Stephan Kleuker
305
Löschvariante mit Iterator und direktem Zugriff
public void studentloeschenFalsch(Integer mat) {
EinUndAusgabe io = new EinUndAusgabe();
for(Student tmp:this.studenten){
if(tmp.getMatrikelnummer().equals(mat)){
this.studenten.remove(tmp);
io.ausgeben("Student gel\u00f6scht\n");
}
}
}
• Methode funktioniert nicht !!!
• es wird eine ConcurrentModificationException geworfen
• durch impliziten Iterator wird Listenänderung verweigert
Grundlagen Programmierung
Stephan Kleuker
306
Löschvariante mit Iterator und späterem Zugriff
public void studentloeschen3(Integer mat) {
EinUndAusgabe io = new EinUndAusgabe();
Student weg = null;
for(Student tmp:this.studenten){
if(tmp.getMatrikelnummer().equals(mat)){
weg = tmp;
}
}
if (weg != null){
this.studenten.remove(weg);
io.ausgeben("Student gel\u00f6scht\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
307
Löschen mehrerer Elemente
• nächstes Inkrement: es soll der unwahrscheinliche Fall
ergänzt werden, dass alle Studierenden eines Studiengangs
gelöscht werden sollen
• wieder sind alle vorgestellten Varianten möglich
• hier: Trennung in zu löschende Elemente heraussuchen und
danach alle Elemente entfernen
• falls man sich Positionen der zu entfernenden Elemente
merkt (ist weitere Variante), muss man beim Löschen
beachten, dass sich Positionen durch das Löschen verändern
können
• Bsp: Lösche an Position 2 und 3, muss als remove(2) und
remove(2) realisiert werden (oder: remove(3); remove(2))
Grundlagen Programmierung
Stephan Kleuker
308
Studiengang löschen
public void studiengangLoeschen(){
EinUndAusgabe io = new EinUndAusgabe();
String fach = nichtLeererText("Studiengang: ");
Integer anzahl = studiengangLoeschen(fach);
io.ausgeben("Es werden "+anzahl+" Studenten gel\u00f6scht\n");
}
public Integer studiengangLoeschen(String fach) {
ArrayList<Student> weg = new ArrayList<Student>();
for(Student tmp:this.studenten){
if(tmp.getStudiengang().equals(fach)){
weg.add(tmp);
}
}
for(Student tmp:weg){
this.studenten.remove(tmp);
}
return weg.size();
Stephan Kleuker
}Grundlagen Programmierung
309
Testfälle
@Test
public void testLoeschenExistierendenStudiengangs(){
Integer anzahl = studis.studiengangLoeschen("MID");
assertTrue(anzahl.equals(2));
assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
assertTrue(studis.studentenZaehlenIn("MID").equals(0));
}
@Test
public void testLoeschenNichtExistentenStudiengangs(){
Integer anzahl = studis.studiengangLoeschen("ITI");
assertTrue(anzahl.equals(0));
assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
assertTrue(studis.studentenZaehlenIn("MID").equals(2));
}
Grundlagen Programmierung
Stephan Kleuker
310
Erweiterung: Austauschstudierende – Ansatz 1
• Inkrement: es sollen Austauschstudenten mit verwaltet
werden können, für die das Herkunftsland mit
aufgenommen werden soll; bei einigen Methoden sollen
Studierende unterschieden werden
• ist keine rein funktionale Erweiterung, da neue
Objektvariable
• Ansatz 1: Ergänzung der Klasse Student um Objektvariablen
– String land
– Boolean istAustausch
– machbar, aber Nachteil dass häufig if (this.isAustausch==
true) in vielen Methoden steht
Grundlagen Programmierung
Stephan Kleuker
311
Erweiterung: Austauschstudierende – Ansatz 2
• Ansatz 2: Ergänzung der Klasse Student um Objektvariable
– String land
– Trick: wenn kein Austauschstudent dann land == null;
– machbar, aber Nachteil dass häufig if (this.land == null)
in vielen Methoden steht
– cool, aber für andere schwer lesbar, da Variable land
bzw. Wert null eine besondere Bedeutung zugeordnet
wird
Grundlagen Programmierung
Stephan Kleuker
312
Vererbung
Grundlagen Programmierung
Stephan Kleuker
313
Erweiterung: Austauschstudierende - Vererbung
• objektorientierte Antwort heißt: Erweiterung einer
existierenden Klasse (meist Vererbung genannt)
• Der Zugriff auf Teile der erweiterten Klasse erfolgt mit super
statt this
Grundlagen Programmierung
Stephan Kleuker
314
Vererbung mit Konstruktornutzung
public class Austauschstudent extends Student{
private String land = null;
public Austauschstudent(String land, String vorname,
String nachname, Integer geburtsjahr,
String studiengang, Integer matrikelnummer){
super(vorname, nachname, geburtsjahr,
studiengang, matrikelnummer);
this.land = land;
}
// geht auch ohne super, da Student() existiert
public Austauschstudent(){
}
public String getLand() {
return land;
}
public void setLand(String land) {
this.land = land;
Grundlagen
Programmierung
Stephan Kleuker
}
}
315
Vererbung und Konstruktoren genauer
• Jeder Konstruktor in einer erbenden (= erweiternden) Klasse
ruft Konstruktor der beerbten (= erweiterten) Klasse auf
• dieser Konstruktoraufruf muss erste Zeile in Konstruktoren der
erbenden Klasse sein
• wird kein Konstruktoraufruf in der erbenden Klasse angegeben,
wird automatisch der Default-Konstruktor (= parameterloser
Konstruktor) der beerbten Klasse zuerst aufgerufen
• hat dann beerbte Klasse keinen Default-Konstruktor wird ein
Fehler ausgegeben
• Grundregel der sauberen Programmierung: In Konstruktoren
von erbenden Klassen wird als erstes immer ein Konstruktor
der Oberklasse aufgerufen; also:
public Austauschstudent(){
super();
}
Grundlagen Programmierung
Stephan Kleuker
316
Vererbung, was geht nicht
Grundlagen Programmierung
Stephan Kleuker
317
Vererbung – Nutzung von Gemeinsamkeiten
• Grundsätzlich kann ein Objekt der erbenden Klasse an jeder
Stelle genutzt werden, an der auch ein Objekt der beerbten
Klasse stehen kann
• damit sind alle public-Methoden aus der beerbten Klasse in
der erbenden Klasse nutzbar!
• Zuweisungen an Variablen vom Typ der beerbten Klasse sind
erlaubt
Student s = new Austauschstudent();
Austauschstudent aus = new Student(); // geht nicht, nie !!!
• Sammlungen mit Objekten des Typs der beerbten Klasse
können Objekte der erbenden Klasse aufnehmen
ArrayList<Student> studis = new ArrayList<Student>();
studis.add(new Austauschstudent());
Grundlagen Programmierung
Stephan Kleuker
318
Integration in die Studentenverwaltung (1/2)
• in steuern():
+ " (7) Austauschstudent einf\u00fcgen: "); // neu
ein = io.leseInteger();
switch(ein){ ...
case 7: {
// neu
austauschstudentenEingeben();
break; ...
}
public void austauschstudentenEingeben(){
Austauschstudent ergebnis = new Austauschstudent();
ergebnis.setVorname(nichtLeererText("Vorname"));
ergebnis.setNachname(nichtLeererText("Nachname"));
ergebnis.setStudiengang(nichtLeererText("Studiengang"));
ergebnis.setGeburtsjahr(
zahlZwischen("Geburtsjahr",1900,2000));
ergebnis.setMatrikelnummer(
zahlZwischen("Matrikelnummer",99999,1000000));
ergebnis.setLand(nichtLeererText("Land"));
this.studenten.add(ergebnis);
}
Grundlagen Programmierung
Stephan Kleuker
319
Integration in die Studentenverwaltung (2/2)
• leicht modifiziertes Test-Setup mit drei IMI-Studis
private Studentenverwaltung studis;
private Student s1 =new Student("Uwe","X",1987,"IMI",424241);
private Student s2 =new Austauschstudent("CHN","Xi","Yu",
1988,"IMI",424242);
private Student s3 =new Austauschstudent("USA","Mo","Jo",
1989,"MID",424243);
private Student s4 =new Student("Uta","B",1987,"MID",424244);
• Alle Tests laufen
weiterhin!
Grundlagen Programmierung
Stephan Kleuker
320
Überschreiben
Grundlagen Programmierung
Stephan Kleuker
321
Vererbung: Möglichkeiten zur Individualisierung
• Ab und zu möchte man, dass sich eine Methode bei einer
erbenden Klasse etwas anders als bei der beerbten Klasse
verhält; hierzu können Methoden überschrieben werden
• aktuell wird für Austauschstudent und Student die gleiche
toString-Methode genutzt
public void austauschstudentAusgeben(){
Austauschstudent aus =new Austauschstudent("USA","Mo"
,"Jo",1989,"MID",424243);
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("Ausgabe: "+aus);
}
Ausgabe: Mo Jo (424243):MID
• Nun soll bei Austauschstudenten nur Vorname, Name, Land
und Studiengang ausgegeben werden
Grundlagen Programmierung
Stephan Kleuker
322
Methoden überschreiben
@Override
public String toString(){
return super.getVorname() + " " + super.getNachname()
+" (" + this.land+"): " + super.getStudiengang();
}
Ausgabe: Mo Jo (USA):MID
• Zugriff auf Methoden der beerbten Klasse über
super.<Methode>
Grundlagen Programmierung
Stephan Kleuker
323
zu @Override
• @Override ist eine Annotation (Erinnerung an @Test)
• Annotationen werden zur deklarativen Programmierung
genutzt; d. h. es wird beschrieben, was gemacht werden
soll, aber nicht wie
• hier: Der Compilier soll prüfen, dass eine Methode der
beerbten Klasse überschrieben wird
• Annotationen können beliebige Sprachkonstrukte (z. B.
Klassen, Objektvariablen, Methoden, lokale Variablen)
annotieren
• Annotationen spielen in C# und Java bei fortgeschrittenen
Programmierkonzepten häufig eine zentrale Rolle; wird in
der Anfängerveranstaltung aber nicht betrachtet
Grundlagen Programmierung
Stephan Kleuker
324
Direkter Zugriff auf geerbte Objektvariablen
• generell können mit get- und set-Methoden die
Objektvariablen der beerbten Klasse bearbeitet werden
• einfacher wird es, wenn man Sichtbarkeit protected nutzt
public class Student{
protected String vorname ="Eva";
protected String nachname ="Mustermann";
protected Integer geburtsjahr = 1990;
protected String studiengang = "IMI";
protected Integer matrikelnummer = 232323;
• in Austauschstudent:
@Override
public String toString(){
return super.vorname + " " + super.nachname + " ("
+ this.land + "): " + super.studiengang;
}
• direkter Zugriff auf Objektvariablen der beerbten Klasse
durch super.<Objektvariable>
Grundlagen Programmierung
Stephan Kleuker
325
Welche Ausgabemethode wird genutzt?
•
Methode in Klasse Analyse
public void wasWirdGezeigt(){
ArrayList<Student> list = new ArrayList<Student>();
list.add(new Austauschstudent("USA",
"Mo","Jo",1989,"MID",424243));
list.add(new Student("Mo","Jo",1989,"MID",424243));
EinUndAusgabe io = new EinUndAusgabe();
for(Student s:list){
io.ausgeben(s+"\n");
Mo Jo (USA): MID
}
Mo Jo (424243):MID
}
Grundlagen Programmierung
Stephan Kleuker
326
dynamische Polymorphie
Grundlagen Programmierung
Stephan Kleuker
327
Grundregel der Vererbung
• Jedes Objekt einer erbenden Klasse kann jedes Objekt ihrer
Beerbten ersetzen, es folgt:
– überschreibende Methoden dürfen in der abgeleiteten
Klasse nur schwächere Vorbedingungen haben
– überschreibende Methoden dürfen in der abgeleiteten
Klasse nur stärkere Nachbedingungen haben
Beispiele:
• man kann statt eines Student-Objektes auch ein
Austauschstudent-Objekt nutzen, da sich das Verhalten
durch überschriebene Methoden nur im Detail verändert
• Methode zum Speichern von Daten wird nicht mit einer
Methode zum Formatieren der Festplatte überschrieben
Dr. Stephan Kleuker
Stephan Kleuker
328
Idee der dynamischen Polymorphie
• Beim Aufruf einer Methode wird zur Laufzeit geprüft, zu
welcher Klasse (genauer am weitesten abgeleiteten Klasse)
das Objekt gehört
• dann wird in dieser Klasse nach der Methode gesucht und
wenn gefunden, ausgeführt
• danach wird schrittweise jede beerbte Klasse nach und nach
geprüft, ob sie die Methode realisiert und dann ausgeführt
Student studi = x;
studi.mach();
bedeutet nicht unbedingt, dass Methode mach() in Studi
ausgeführt wird, wenn x zu einer direkt oder indirekt
beerbten Klasse von Studi gehört
• Hinweis: nicht einfach, macht aber die Entwicklung oft
sehr viel einfacher und eleganter; zentrales Konzept
Grundlagen Programmierung
Stephan Kleuker
329
Beispiel zur dynamischen Polymorphie (1/6)
public class A{
public void meth1(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("A1\n");
}
public void meth2(){
meth3();
}
public void meth3(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("A3\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
330
Beispiel zur dynamischen Polymorphie (2/6)
public class B extends A{
@Override
public void meth1(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("B1\n");
}
@Override
public void meth3(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("B3\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
331
Beispiel zur dynamischen Polymorphie (3/6)
public class C extends B{
@Override
public void meth1(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("C1\n");
}
@Override
public void meth2(){
super.meth2();
}
@Override
public void meth3(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("C3\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
332
Beispiel zur dynamischen Polymorphie (4/6)
public class Analyse{
meth1: aus(A1)
meth2: meth3()
meth3: aus(A3)
public void analyseA(){
A a = new A();
a.meth1();
a.meth2();
}
meth1: aus(B1)
meth3: aus(B3)
A1
A3
meth1: aus(C1)
meth2: super.meth2()
meth3: aus(C3)
Grundlagen Programmierung
Stephan Kleuker
333
Beispiel zur dynamischen Polymorphie (5/6)
meth1: aus(A1)
meth2: meth3()
meth3: aus(A3)
public void analyseB(){
A b = new B();
b.meth1();
b.meth2();
}
meth1: aus(B1)
meth3: aus(B3)
B1
B3
meth1: aus(C1)
meth2: super.meth2()
meth3: aus(C3)
Grundlagen Programmierung
Stephan Kleuker
334
Beispiel zur dynamischen Polymorphie (6/6)
meth1: aus(A1)
meth2: meth3()
meth3: aus(A3)
public void analyseC(){
A c = new C();
c.meth1();
c.meth2();
}
meth1: aus(B1)
meth3: aus(B3)
C1
C3
meth1: aus(C1)
meth2: super.meth2()
meth3: aus(C3)
Grundlagen Programmierung
Stephan Kleuker
335
Einfache Erweiterung (1/2)
• In erbenden Klassen können Methoden ergänzt werden, die
dann von Objekten dieser Klasse (und davon erbenden
Klassen) nutzbar sind
• in Austauschstudent:
public String gruss(){
if(this.land.equals("USA")){
return "Howdy " + super.vorname;
}
if(this.land.equals("OSF")){
return "Moin " + super.vorname;
}
return "Hello "+ super.vorname;
}
Grundlagen Programmierung
Stephan Kleuker
336
Einfache Erweiterung (2/2)
• Erweiterungen in der beerbten Klasse und für Variablen
vom Typ der beerbten Klasse nicht nutzbar
• in Analyse:
public void gruessen(){
Austauschstudent aus = new Austauschstudent("USA",
"Mo","Jo",1989,"MID",424243);
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben(aus.gruss());
Howdy Mo
}
Grundlagen Programmierung
Stephan Kleuker
337
casten
Grundlagen Programmierung
Stephan Kleuker
338
Neues Inkrement
• Die Verwaltung soll um eine Möglichkeit ergänzt werden,
die Anzahl der Austauschstudenten zu berechnen
• Problem: ArrayList<Student> kennt nur Objekte der Klasse
Student und man kann mit bisherigem Wissen nicht
feststellen, ob Objekt auch zu einer erbenden Klasse gehört
• Gibt allerdings schmuddeligen (wieso? später!) Ansatz
– Boolescher Operator instanceof, genauer
<Objekt> instanceof <Klassenname>
– gibt true, wenn Objekt auch zu dieser Klasse gehört;
Objekt gehört zu der Klasse, von der es instanziiert
wurde (new <Klassenname>) und zu allen Klassen, die
diese Klasse beerbt hat (direkt oder indirekt)
Grundlagen Programmierung
Stephan Kleuker
339
Beispiel für instanceof
public void instanceofSpielerei(){
Austauschstudent aus = new Austauschstudent("USA",
"Mo","Jo",1989,"MID",424243);
Student s0 = new Austauschstudent("USA",
"Mo","Jo",1989,"MID",424243);
Student s1 = new Student("Mo","Jo",1989,"MID",424243);
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("aus: "+(aus instanceof Austauschstudent)+"\n");
io.ausgeben("aus: "+(aus instanceof Student)+"\n");
io.ausgeben("s0: "+(s0 instanceof Austauschstudent)+"\n");
io.ausgeben("s0: "+(s0 instanceof Student)+"\n");
io.ausgeben("s1: "+(s1 instanceof Austauschstudent)+"\n");
io.ausgeben("s1: "+(s1 instanceof Student)+"\n");
}
aus: true
aus: true
s0: true
s0: true
s1: false
s1: true
Grundlagen Programmierung
Stephan Kleuker
340
Casten
• Wenn man weiß, dass ein Objekt eines Typs auch zu einer
anderen Klasse gehört, kann man das Objekt in ein Objekt
der anderen Klasse umwandeln (casten):
(<NameDerErbendenKlasse) Objektvariable
• Sollte man in eine falsche Klasse casten, erhält man einen
Fehler (Exception)
• Auch casten sollte man mit Bedacht einsetzen
Grundlagen Programmierung
Stephan Kleuker
341
Beispiel für Casten
public void castenSpielerei(){
Student s0 = new Austauschstudent("USA",
"Mo","Jo",1989,"MID",424243);
Austauschstudent aus = (Austauschstudent) s0;
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben(aus.gruss());
s0 = new Student("Mo","Jo",1989,"MID",424243);
aus = (Austauschstudent) s0;
io.ausgeben(aus.gruss());
}
Grundlagen Programmierung
Stephan Kleuker
342
instanceof und casten nur im "Notfall"
• Casten sowie instanceof sollte man nur mit allergrößter
Vorsicht nutzen, da
– der Programmcode viele if-Konstrukte enthält
– bei Erweiterungen mit weiteren erbenden Klassen weitere
Alternativen hinzukommen
– wenn man instanceof und casten häufig benötigt, hat man
beim Programmdesign einen großen Fehler gemacht
• z. B. eine ArrayList<Student> und man immer wieder
Alternativen für Austauschstudenten benötigt
• Grundsätzlich deutet Nutzung auf schlechte Programmierung
• Ausnahmen selten sinnvoll, nur bei Frameworks, bei denen
Software für andere Software erstellt wird
Grundlagen Programmierung
Stephan Kleuker
343
Anzahl Austauschstudenten: schwächere Lösung
public void anzahlAustauschstudentenAusgeben(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("Es gibt "+ anzahlAustauschstudenten()
+ " Austauschstudenten\n");
}
public Integer anzahlAustauschstudentenNichtSoToll(){
Integer ergebnis = 0;
for(Student s: this.studenten){
if(s instanceof Austauschstudent){
ergebnis = ergebnis +1;
}
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
344
Anzahl Austauschstudenten: bessere Alternative
• Nutzung von dynamischer Polymorphie
• Einführung in Student einer neuen Methode
zaehlenAlsAustauschstudent
• Methode gibt den Wert 0 für Student zurück
• Methode wird in Austauschstudent überschrieben und gibt
Wert 1 zurück
• Werte aller Studierenden werden summiert
• Hinweis: Ok, ist kleiner Trick, aber die Behandlung von
Alternativen wurde in Polymorphie verschoben
• Ansatz für weitere erbende Klassen von Student ohne CodeÄnderung in der Studentenverwaltung
Grundlagen Programmierung
Stephan Kleuker
345
Realisierung (1/2)
• in Student:
public Integer zaehlenAlsAustauschstudent(){
return 0;
}
• in Austauschstudent:
@Override
public Integer zaehlenAlsAustauschstudent(){
return 1;
}
Grundlagen Programmierung
Stephan Kleuker
346
Realisierung (2/2)
public Integer anzahlAustauschstudenten(){
Integer ergebnis = 0;
for(Student s:this.studenten){
ergebnis = ergebnis + s.zaehlenAlsAustauschstudent();
}
return ergebnis;
}
• zugehöriger Test:
@Test
public void testAustauschstudentenZaehlen(){
Integer anzahl = studis.anzahlAustauschstudenten();
Assert.assertTrue(anzahl.equals(2));
}
Grundlagen Programmierung
Stephan Kleuker
347
Überblick: Wiederverwendung durch OO
• Im Laufe der Entwicklung der für eine Software benötigten
Klassen kann es auffallen, dass man einige „ähnliche“
Klassen findet
• Ähnlich bedeutet eine große Gemeinsamkeit bei gewissen
Objektvariablen und Methoden und größere Unterschiede
bei anderen Objektvariablen und Methoden
• Die Grundidee bei der Objektorientierung ist es, die großen
Gemeinsamkeiten in eine Klasse zu packen und die
Spezialfälle in andere Klassen, die die gemeinsamen
Eigenschaften der anderen Klasse erben können
Dr. Stephan Kleuker
Stephan Kleuker
348
abstrakte Klasse
Grundlagen Programmierung
Stephan Kleuker
349
Fallstudie: Arenenkampf
• In einer Arena sollen verschiedene Kämpfer gegeneinander
antreten können. Dabei soll der Nutzer sich einen Kämpfer
wählen und gegen eine Gruppe anderer Kämpfer antreten.
Jeder Kämpfer wird durch seinen Namen, sein Geschick und
seine Stärke charakterisiert. Ein Kampf findet Eins-gegenEins statt, wobei die Kämpfer sich gegenseitig attackieren
und versuchen die Attacke abzuwehren. Jeder Kämpfer hat
eine Anzahl von Gesundheitspunkten, die, nachdem er
attackiert wurde, sinken kann. Ist die Punktzahl nicht mehr
positiv, scheidet der Kämpfer aus. Der Nutzer kämpft
nacheinander gegen die Gruppe anderer Kämpfer. Ziel ist
es, alle anderen Kämpfer zu besiegen.
Grundlagen Programmierung
Stephan Kleuker
350
Kämpfer (1/3) - Modellierung
public class Kaempfer {
protected String name;
protected Integer gesundheit;
protected Integer staerke;
protected Integer geschick;
public Kaempfer(){
}
public Kaempfer(String name, Integer gesundheit,
Integer staerke, Integer geschick) {
this.name = name;
this.gesundheit = gesundheit;
this.staerke = staerke;
this.geschick = geschick;
}
Grundlagen Programmierung
Stephan Kleuker
351
Kämpfer (2/3) – übliche get- und set-Methoden
public Integer getGesundheit() { return gesundheit;}
public void setGesundheit(Integer gesundheit) {
this.gesundheit = gesundheit;
}
public Integer getStaerke() { return staerke;}
public void setStaerke(Integer staerke) {
this.staerke = staerke;
}
public Integer getGeschick() { return geschick; }
public void setGeschick(Integer geschick) {
this.geschick = geschick;
}
public String getName() { return name;}
public void setName(String name) {
this.name = name;
}
Grundlagen Programmierung
Stephan Kleuker
352
Kämpfer (3/3) – Kernfunktionalität
• Angreifen: zufälliger Schadenswert wird berechnet
public Integer angreifen(){
EinUndAusgabe io = new EinUndAusgabe();
return io.zufall(2, this.staerke)
* io.zufall(2, this.geschick);
}
• Angegriffen werden: Angriff erfolgt mit einem
Schadenswert, der noch abgemildert werden kann
public Integer einstecken(Integer haue){
EinUndAusgabe io = new EinUndAusgabe();
Integer ergebnis = io.zufall(0,haue);
this.gesundheit = this.gesundheit - ergebnis;
return ergebnis;
}
}
Grundlagen Programmierung
Stephan Kleuker
353
Arena - Konzept
Nutzer erstellt seinen Kämpfer (Held)
Gegner werden erstellt
[Kämpfer lebt
und Gegner vorhanden]
[!(Kämpfer lebt
und Gegner vorhanden)]
Herausforderer auswählen
Held kämpft gegen
Herausforderer bis
Sieger feststeht,
evtl. Herausforderer
löschen
Grundlagen Programmierung
Stephan Kleuker
[Kämpfer
lebt]
gewonnen
[!(Kämpfer
lebt)]
verloren
354
Arena – Realisierung (1/4)
import java.util.ArrayList;
public class Arena {
private ArrayList<Kaempfer> gegner
= new ArrayList<Kaempfer>();
private Kaempfer held;
Nutzer erstellt seinen Kämpfer
public Kaempfer kaempferErstellen(){
Integer punkte = 30;
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("Teilen Sie "+punkte
+ " in Kraft und Geschick auf:\n"
+ "Kraft (1-"+(punkte-1)+"): ");
Integer kraft = 0;
while (kraft<1 || kraft>punkte-1){
kraft = io.leseInteger();
}
return new Kaempfer("Isch",500,kraft,30-kraft);
}
Grundlagen Programmierung
Stephan Kleuker
355
Arena – Realisierung (2/4)
Gegner werden erstellt
public void gegnerErstellen() {
for (Integer i = 1; i <= 4; i = i + 1) {
gegner.add(new Kaempfer("Andy"+i, i * 100, i*3, i*3));
}
}
public Kaempfer kaempfen(Kaempfer k1, Kaempfer k2) {
while (k1.getGesundheit() > 0 && k2.getGesundheit() > 0) {
ersterHautZweiter(k1, k2);
if (k2.getGesundheit() > 0) {
Kämpfer1 kämpft
ersterHautZweiter(k2, k1);
gegen Kämpfer2 bis
}
Sieger feststeht
}
if (k1.getGesundheit() >= 0)
return k1;
return k2;
}
Grundlagen Programmierung
Stephan Kleuker
356
Arena – Realisierung (3/4)
private void ersterHautZweiter(Kaempfer k1, Kaempfer k2) {
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben(k1.getName() + " haut zu.\n");
Integer schaden = k2.einstecken(k1.angreifen());
io.ausgeben(k2.getName() + " verliert " + schaden
+ " Punkte.\n");
io.ausgeben(k1.getName() + " hat " + k1.getGesundheit()
+ " Punkte, "
+ k2.getName() + " hat " + k2.getGesundheit()
+ " Punkte.\n*****\n");
}
Grundlagen Programmierung
Stephan Kleuker
357
Arena – Realisierung (4/4)
public void kampfOrganisieren() {
EinUndAusgabe io = new EinUndAusgabe();
this.held = kaempferErstellen();
gegnerErstellen();
while (held.getGesundheit() > 0 && gegner.size() > 0) {
Kaempfer herausforderer = gegner.get(0);
Kaempfer sieger = kaempfen(held, herausforderer);
if (held.equals(sieger)) {
gegner.remove(0);
}
}
if (held.getGesundheit() > 0) {
io.ausgeben("Sie haben glorreich gewonnen.\n");
} else {
io.ausgeben("Sie haben schmachvoll verloren.\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
358
Ausschnitt aus Kampfprotokoll
Teilen Sie 30 in Kraft und Geschick auf:
Kraft (1-29): 13
Isch haut zu.
Andy1 verliert 154 Punkte.
Isch hat 500 Punkte, Andy1 hat -54 Punkte.
*****
Isch haut zu.
Andy2 verliert 25 Punkte.
Isch hat 500 Punkte, Andy2 hat 175 Punkte.
*****
...
*****
Andy4 haut zu.
Isch verliert 21 Punkte.
Andy4 hat 19 Punkte, Isch hat -12 Punkte.
*****
Sie haben schmachvoll verloren.
Grundlagen Programmierung
Stephan Kleuker
359
Inkrement: neue Kämpferarten
• Erweiterung: Es sollen unterschiedliche Kämpfer mit
verschiedenen Angriffs- und Abwehrverhalten spezifiziert
werden können.
• Ansatz 1 (machbar): neue Kaempfer-Klassen erben von
Kaempfer und überschreiben angreifen() und einstecken()
• logisches Problem: Die aktuell vorhandenen
Implementierungen des beiden Methoden stehen auch nur
für eine Art von Kämpfer
• Lösung: Abstrakte Klasse
Grundlagen Programmierung
Stephan Kleuker
360
Idee: Abstrakte Klasse
• abstrakte Klassen sind dazu konzipiert, dass von ihnen geerbt
werden muss
• abstrakte Klassen enthalten Teilimplementierungen, die
vererbt werden sollen (trotzdem überschreibbar)
• Methoden, die eine erbende Klasse realisieren muss (damit
wird dynamische Polymorphie möglich) werden als abstract
markiert und haben keine Implementierung
• Klasse selbst wird auch als abstract markiert
• von abstrakter Klasse erbende Klasse realisiert entweder alle
abstrakten Methoden der Oberklasse oder ist selber abstrakt
• von abstrakten Klassen können keine Objekte erzeugt werden
• abstrakte Klasse aber als Typ für Variablen verwendbar
Grundlagen Programmierung
Stephan Kleuker
361
Abstrakter Kämpfer
public abstract class Kaempfer {
protected String name;
protected Integer gesundheit;
protected Integer staerke;
protected Integer geschick;
public Kaempfer(){}
public Kaempfer(String name, Integer gesundheit,
Integer staerke, Integer geschick) {
this.name = name;
this.gesundheit = gesundheit;
this.staerke = staerke;
this.geschick = geschick;
}
public abstract Integer angreifen();
public abstract Integer einstecken(Integer haue);
}
// folgen normale get- und set-Implementierungen
Grundlagen Programmierung
Stephan Kleuker
362
Beispielrealisierung 1 – von vorher übernommen
public class Simplo extends Kaempfer {
public Simplo() {}
public Simplo(String name, Integer gesundheit,
Integer staerke, Integer geschick) {
super(name, gesundheit, staerke, geschick);
}
@Override
public Integer angreifen(){
EinUndAusgabe io = new EinUndAusgabe();
return io.zufall(2, super.staerke)
* io.zufall(2, super.geschick);
}
@Override
public Integer einstecken(Integer haue){
EinUndAusgabe io = new EinUndAusgabe();
Integer ergebnis = io.zufall(0, haue);
super.gesundheit = super.gesundheit - ergebnis;
return ergebnis;
}
Grundlagen
Programmierung
Stephan Kleuker
363
Beispielrealisierung 2 – schwach, kann einstecken
public class Nerdo extends Kaempfer {
public Nerdo() {}
public Nerdo(String name, Integer gesundheit,
Integer staerke, Integer geschick) {
super(name, gesundheit, staerke, geschick);
}
@Override
public Integer angreifen(){
EinUndAusgabe io = new EinUndAusgabe();
return io.zufall(2, super.staerke)
* io.zufall(2, super.geschick)/3;
}
@Override
public Integer einstecken(Integer haue){
EinUndAusgabe io = new EinUndAusgabe();
Integer ergebnis = io.zufall(0,haue/3);
super.gesundheit = super.gesundheit - ergebnis;
return ergebnis;
}
Grundlagen
Programmierung
Stephan Kleuker
364
Beispielrealisierung 3 – stark, steckt nicht gut ein
public class Brutalo extends Kaempfer {
public Brutalo() {}
public Brutalo(String name, Integer gesundheit,
Integer staerke, Integer geschick) {
super(name, gesundheit, staerke, geschick);
}
@Override
public Integer angreifen(){
EinUndAusgabe io = new EinUndAusgabe();
return super.staerke * io.zufall(3, super.geschick);
}
@Override
public Integer einstecken(Integer haue){
EinUndAusgabe io = new EinUndAusgabe();
Integer ergebnis = io.zufall(haue/2,haue);
super.gesundheit = super.gesundheit - ergebnis;
return ergebnis;
}
}Grundlagen Programmierung
Stephan Kleuker
365
Notwendige Änderungen in Arena
• Erinnerung: new nicht für abstrakte Klassen erlaubt
return new Simplo("Isch",500,kraft,30-kraft);
bleibt: ArrayList<Kaempfer> gegner, aber:
public void gegnerErstellen(){
gegner.add(new Nerdo("Ulf",100,3,3));
gegner.add(new Simplo("Uta",200,6,6));
gegner.add(new Simplo("Urs",300,9,9));
gegner.add(new Brutalo("Ute",400,12,12));
}
Grundlagen Programmierung
Stephan Kleuker
366
Interface
Grundlagen Programmierung
Stephan Kleuker
367
Völlig Abstrakte Klassen
• wichtig bei Nutzung der dynamischen Polymorphie sind die
"gemeinsame Herkunft" (d. h. beerbte Klasse) und die in
allen Klassen nutzbaren Methoden
• nächster Schritt ist die vollständig abstrakte Klasse ohne
Objektvariablen und mit nur abstrakten Methoden
• dieses wird in Java auch Interface genannt
• ein Interface I wird durch implements I (statt extends I)
realisiert
• Interfaces können andere Interfaces beerben (extends)
Grundlagen Programmierung
Stephan Kleuker
368
Beispiel: Interface
public interface KaempferInterface{
public Integer angreifen();
public Integer einstecken(Integer haue);
public Integer getGesundheit();
public String getName();
}
Grundlagen Programmierung
Stephan Kleuker
369
Beispiel: Realisierung eines Interface (1/2)
public class Hulko implements KaempferInterface {
private String name;
private Integer gesundheit;
public Hulko(String name, Integer gesundheit) {
this.name = name;
this.gesundheit = gesundheit;
}
@Override
public Integer angreifen() {
return 100;
}
Grundlagen Programmierung
Stephan Kleuker
370
Beispiel: Realisierung eines Interface (2/2)
@Override
public Integer einstecken(Integer haue) {
this.gesundheit = this.gesundheit - haue/10;
return haue/10;
}
@Override
public Integer getGesundheit() {
return this.gesundheit;
}
@Override
public String getName() {
return this.name;
}
}
• zur Nutzung in Arena Kaempfer durch KaempferInterface
ersetzen; oder auch Kaempfer implements Interface
Grundlagen Programmierung
Stephan Kleuker
371
Design by Contract
• Interfaces zentrale Idee zur Realisierung von Software in
Teams
• Ansatz: Man überlegt sich Klassen und definiert Interfaces
für diese Klassen
• Vertrag zwischen Nutzer des Interfaces und Realisierer
• Nutzer weiß, dass er eine Klasse bekommt, die das Interface
realisiert
• Entwickler verpflichtet sich, das Interface zu realisieren; wie
es gemacht wird, geht Nutzer nichts an
• zum Testen kann Nutzer des Interfaces minimale
Implementierung des Interfaces selbst vornehmen
• grundsätzlich gilt: es reichen nicht nur Methodennamen;
Vor- und Nachbedingungen zu definieren
Grundlagen Programmierung
Stephan Kleuker
372
Vervollständigtes Interface als Vertrag
public interface KaempferInterface{
/** Die Methode gibt einen Angriffswert des Objekts
* zurück, der abhängig von der momentanen Stärke ist.
* @return ein nicht-negativer Wert kleiner-gleich 250 */
public Integer angreifen();
/** Methode berechnet den Effekt eines erhaltenen
* Angriffs der Stärke haue. Es wird erwartet, dass der
* Gesundheitswert negativ beeinflusst wird.
* @param haue nicht negativer Wert des empfangenen Schlags
* @return Stärke der Auswirkung auf das eigene Objekt,
*
Wert liegt zwischen 0 und haue */
public Integer einstecken(Integer haue);
/** Gibt aktuellen Gesundheitswert zurück.
* @return aktueller Gesundheitswert */
public Integer getGesundheit();
/** Gibt Namen des Kämpfers zurück.
* @return Name des Kämpfers */
public String getName();
}
Grundlagen Programmierung
Stephan Kleuker
373
Kommentare
Grundlagen Programmierung
Stephan Kleuker
374
Einschub Dokumentation (1/5)
• vorherige Dokumentationsform nicht zufällig
• erlaubt Programmdokumentation aus dem Quellcode zu
generieren
• Generierung erfolgt durch Java-Hilfsprogramm javadoc
• javadoc hat viele Parameter mit denen z. B. das Layout oder
der Detaillierungsgrad der Information (sollen z. B.
Objektvariablen in der Dokumentation sichtbar sein?)
eingestellt werden kann
• generierte Dokumentation besteht typischerweise aus
einem Übersichtsteil und der Detaildokumentation
• hier wird nur Grundprinzip erklärt
• Ähnliches Konzept für weitere Sprachen: Doxygen
http://www.stack.nl/~dimitri/doxygen/
Grundlagen Programmierung
Stephan Kleuker
375
Einschub Dokumentation (2/5)
Grundlagen Programmierung
Stephan Kleuker
376
Einschub Dokumentation (3/5)
Grundlagen Programmierung
Stephan Kleuker
377
Einschub Dokumentation (4/5)
• Grundsätzlich ist jedes Sprachelement (Klasse,
Objektvariable, Methode) vor ihrer Deklaration zu
dokumentieren
• Javadoc-Kommentar beginnt mit /**
• Text bis zum ersten Punkt wird in die Zusammenfassung
aufgenommen, Rest steht bei Details
• Jeder Übergabeparameter ist mit @param zu
dokumentieren
• Gibt es Methodenrückgabe, ist diese mit @return zu
dokumentieren
• In der Dokumentation können HTML4-Tags genutzt werden
Grundlagen Programmierung
Stephan Kleuker
378
Einschub Dokumentation (5/5)
• sorgfältige Dokumentation ist zentrale Aufgabe des
Entwicklers
• man schreibt so, dass ein anderer Entwickler das Programm
nutzen, aber auch weiterentwickeln kann
• Textfragmente können durchaus redundante Informationen
enthalten, da sie oft nicht zusammenhängend gelesen werden
• wann entsteht Dokumentation (keine klare Antwort):
– nach der Programmerstellung (keine aufwändige
Aktualisierung; nicht mehr alle Details im Kopf)
– nach Methodenerstellung (alle Details der Erstellung noch
bekannt; muss bei Änderungen angepasst werden)
– vor der Methodenerstellung (man kann sich so eine
Aufgabenstellung definieren; Änderungen sind aufwändig)
Grundlagen Programmierung
Stephan Kleuker
379
Mehrfachvererbung
Grundlagen Programmierung
Stephan Kleuker
380
Mehrfachvererbung
• einige objektorientierte
Sprachen unterstützen
Mehrfachvererbung
• Problem: wenn Methode mit
gleicher Signatur von
verschiedenen Klassen
geerbt (Notlösung: man
muss Klasse angeben, deren
Methode genutzt werden
soll)
• Auflösung dynamischer
Polymorphie machbar, aber
aufwändig
Grundlagen Programmierung
Stephan Kleuker
Kaempfer
Guru
Lasko
381
Mehrfachvererbung mit Interfaces
• Java erlaubt es, dass eine Klasse mehrere Interfaces
realisiert
public interface GuruInterface {
public String weisheit(Integer nr);
}
KaempferInterface
GuruInterface
Lasko
Grundlagen Programmierung
Stephan Kleuker
382
Beispiel für Realisierung mehrerer Interfaces
public class Lasko implements KaempferInterface, GuruInterface {
@Override
public String weisheit(Integer nr) {
if(nr.equals(42)){
return "Das ist die Antwort";
}
return "Suche die Frage";
}
@Override
public Integer angreifen() {return 0;}
@Override
public Integer einstecken(Integer haue) {return 0;}
@Override
public Integer getGesundheit() {return 1;}
}
@Override
public String getName() {return "Lasko";}
Grundlagen Programmierung
Stephan Kleuker
383
Anmerkungen zur Vererbung
• Vererbung ist ein wichtiger Ansatz, damit ähnlicher Code
nicht doppelt geschrieben werden muss
• Vererbung spielt beim Aufbau von Programmbibliotheken
eine wichtige Rolle (Übergang vom generellen Konzept bis
zur Speziallösung)
• Aber, Vererbung ist kein „Muss“, sie ergibt sich in der
Programmentwicklung als sinnvolle Vereinfachung
• OO-Anfänger suchen oft krampfhaft nach Möglichkeiten zur
Nutzung von Vererbung, das Ergebnis sind häufig schlecht
strukturierte Programme
Dr. Stephan Kleuker
Stephan Kleuker
384
Doch Mehrfachvererbung?
• Bei der Ausführung von Methoden fällt frühzeitig auf, dass
jede Klasse eine Vererbung nutzt, erbende Klassen sogar zwei
Grundlagen Programmierung
Stephan Kleuker
385
Klasse Object
Grundlagen Programmierung
Stephan Kleuker
386
Klasse Object
• In Java erben alle Klassen automatisch von der Klasse
Object, dies ist nicht änderbar
• Ansatz erlaubt es, über dynamische Polymorphie
Gemeinsamkeiten von Objekten zu nutzen, bekannt:
– toString(): String-Repräsentation des Objekt
– equals(): Überprüfung auf Gleichheit
• weiterer Ansatz: ArrayList<Object> kann beliebige Objekte
aufnehmen (Rückumwandlung nur mit casten)
• Zentrale Idee ist, diese Methoden (wenn benötigt) zu
überschreiben
• Überschreiben von toString() und equals() immer,
hashCode() fast immer sinnvoll
Grundlagen Programmierung
Stephan Kleuker
387
jetzt variierte Beispielklasse
public class Punkt{
private Integer x;
private Integer y;
public Punkt(Integer x, Integer y) {
this.x = x;
this.y = y;
}
public Integer getX() { return this.x; }
public Integer getY() { return this.y; }
public void setX(Integer x) {
this.x = x;
}
}
public void setY(Integer y) {
this.y = y;
}
Grundlagen Programmierung
Stephan Kleuker
388
Direkte Ausgabe
import java.util.ArrayList;
public class Analyse{
public void ausgeben(){
EinUndAusgabe io = new EinUndAusgabe();
Punkt p1 = new Punkt(0,0);
Punkt p2 = new Punkt(0,0);
io.ausgeben("p1: "+p1+"\n");
io.ausgeben("p2: "+p2+"\n");
}
}
p1: Punkt@42e816
p2: Punkt@190d11
• Hier wurde toString()-Methode der Klasse Object genutzt
Grundlagen Programmierung
Stephan Kleuker
389
Nutzung von toString
• in Punkt:
@Override
public String toString(){
return "["+this.x+","+this.y+"]";
}
• Aufruf von ausgeben() in Analyse liefert
p1: [0,0]
p2: [0,0]
Grundlagen Programmierung
Stephan Kleuker
390
Identität und Gleichheit
• bisher verboten, Objekte mit == zu prüfen
• == prüft auf Identität, handelt es sich um dieselben Objekte?
• mit equals soll inhaltliche Gleichheit geprüft werden, also ob
es sich um das gleiche Objekt handelt (fast immer das, was
man wissen will)
• Standardimplementierung von equals() in Object
unterscheidet dasselbe und das gleiche Objekt nicht
public Boolean equals (Object other){
return this == other;
}
• Jede Java-Klasse implementiert equals() selbst, ansonsten
werden inhaltliche Gleichheit und Identität nicht
unterschieden
Grundlagen Programmierung
Stephan Kleuker
391
Identität bei Strings
public void stringgleicheit(){
EinUndAusgabe io = new EinUndAusgabe();
String s1 = "Hallo";
String s2 = "Hall";
s2 = s2 + "o";
io.ausgeben(s1+"=="+s2+": "+(s1==s2)+"\n");
io.ausgeben("s1.equals(s2): "+(s1.equals(s2))+"\n");
}
Hallo==Hallo: false
s1.equals(s2): true
• Anmerkung: Da es in der Java-Spezifikation offen ist, ob es
für inhaltlich gleiche Strings unterschiedliche Objekte geben
muss, kann "Hallo"=="Hallo" auch in einem Block nach true
ausgewertet werden
Grundlagen Programmierung
Stephan Kleuker
392
Identität bei Punkt-Objekten
public void gleichUndIdentisch(){
EinUndAusgabe io = new EinUndAusgabe();
Punkt p1 = new Punkt(0,0);
Punkt p2 = new Punkt(0,0);
Punkt p3 = p1;
io.ausgeben("p1==p2: "+(p1==p2)+"\n");
io.ausgeben("p1==p3: "+(p1==p3)+"\n");
io.ausgeben("p1.equals(p2): "+(p1.equals(p2))+"\n");
io.ausgeben("p1.equals(p3): "+(p1.equals(p3))+"\n");
}
p1==p2: false
p1==p3: true
p1.equals(p2): false
p1.equals(p3): true
Grundlagen Programmierung
Stephan Kleuker
393
Visualisierung von ==
• Bei der Identitätsprüfung wird geprüft, ob zwei Variablen
auf den gleichen Speicherbereich verweisen
Punkt p1 = new Punkt(0,0);
Punkt p2 = new Punkt(0,0);
Punkt p3 = p1;
Variablen
p1
p2
Speicher
x
0
y
0
x
0
y
0
p3
Grundlagen Programmierung
Stephan Kleuker
394
remove(Object) für ArrayList
public void objektInListeLoeschen(){
EinUndAusgabe io = new EinUndAusgabe();
ArrayList<Punkt> ap = new ArrayList<Punkt>();
Punkt p1 = new Punkt(0,0);
Variablen
ap.add(p1);
p1
ap.add(new Punkt(0,0));
ap.add(p1);
0
io.ausgeben("Liste1 : "+ap+"\n");
ap
ap.remove(new Punkt(0,0));
1
io.ausgeben("Liste2 : "+ap+"\n");
2
ap.remove(p1);
io.ausgeben("Liste3 : "+ap+"\n");
}
Liste1 : [[0,0], [0,0],
Liste2 : [[0,0], [0,0],
Liste3 : [[0,0], [0,0]]
Grundlagen Programmierung
Stephan Kleuker
Speicher
x
0
y
0
x
0
y
0
[0,0]]
[0,0]]
395
Nutzung von equals()
• muss public boolean equals(Object) überschrieben werden
• alle möglichen Fälle für Parameter vom Typ Object beachten
– kann null sein
– kann zu anderer Klasse gehören
– muss dann inhaltlich untersucht werden
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Punkt)) {
return false;
}
Punkt other = (Punkt) obj;
if (this.x.equals(other.getX())
&& this.y.equals(other.getY())) {
return true;
}
return false;
Grundlagen
Programmierung
Stephan Kleuker
}
396
Ausgaben für equals()
• für gleichUndIdentisch()
p1==p2: false
p1==p3: true
p1.equals(p2): true
p1.equals(p3): true
• für objektInListeLoeschen()
Liste1 : [[0,0], [0,0], [0,0]]
Liste2 : [[0,0], [0,0]]
Liste3 : [[0,0]]
• Anmerkung: Es gibt Situationen, in denen man nicht alle
Objektvariablen vergleichen will/muss (z. B. sollte
Matrikelnummer bei Studierenden reichen)
Grundlagen Programmierung
Stephan Kleuker
397
Erinnerung: Java arbeitet mit Objektreferenzen 1
public void zuweisen(){
EinUndAusgabe io = new EinUndAusgabe();
Punkt p1 = new Punkt(0,0);
Punkt p2 = p1;
p1: [0,42]
p2.setY(42);
p2: [0,42]
io.ausgeben("p1: "+p1+"\n");
io.ausgeben("p2: "+p2+"\n");
}
Speicher
Variablen
p1
x
0
y
42
p2
Grundlagen Programmierung
Stephan Kleuker
398
Erinnerung: Java arbeitet mit Objektreferenzen 2
public void zuweisen1(){
EinUndAusgabe io
= new EinUndAusgabe();
ArrayList<Punkt> ap
= new ArrayList<Punkt>();
Punkt p1 = new Punkt(0,0);
ap.add(p1);
ap.add(new Punkt(0,0));
ap.add(p1);
io.ausgeben("Liste1: "+ap+"\n");
p1.setX(41);
ap.get(0).setY(42);
io.ausgeben("Liste2: "+ap+"\n");
io.ausgeben("p1: "+p1+"\n");
} Liste1: [[0,0], [0,0], [0,0]]
Liste2: [[41,42], [0,0], [41,42]]
p1: [41,42]
Grundlagen Programmierung
Stephan Kleuker
Variablen
p1
ap
Speicher
x
0
y
0
0
x
0
1
y
0
x
41
y
42
0
x
0
1
y
0
2
p1
ap
2
399
wenn keine Referenzen erwünscht
• in der Praxis muss fast nur mit Objektreferenzen gearbeitet
werden; trotzdem soll es möglich sein, Ausgangsobjekte
nicht zu verändern
• Wunsch: Erstellung echter Objektkopien ohne gemeinsame
Referenzen
• Ansatz: Realisierung einer Methode clone()
• In Java bereits durch Klasse Object etwas unterstützt, gibt
Methode protected Object clone()
• protected nicht direkt nutzbar, aber überschreibbar
• Klasse soll dann Interface Cloneable realisieren
• Beim Kopieren muss der clone()-Befehl an jede
Objektvariable weitergegeben werden; diesen wieder
weitergeben
Grundlagen Programmierung
Stephan Kleuker
400
Beispiel: Realisierung von Clone
• Anmerkung: für elementare Datentypen und Klassen die
Konstanten nutzen (Integer), wird kein clone() benötigt
• Beobachtung: Integer hat keine set-Methode für den Wert
public class Punkt implements Cloneable{
//..
@Override
public Punkt clone(){
return new Punkt(this.x, this.y);
}
Grundlagen Programmierung
Stephan Kleuker
401
Nutzung von clone()
public void zuweisen2(){
EinUndAusgabe io = new EinUndAusgabe();
ArrayList<Punkt> ap = new ArrayList<Punkt>();
Punkt p1 = new Punkt(0,0);
ap.add(p1.clone());
ap.add(new Punkt(0,0));
ap.add(p1.clone());
io.ausgeben("Liste1: "+ap+"\n");
p1.setX(41);
ap.get(0).setY(42);
io.ausgeben("Liste2: "+ap+"\n");
io.ausgeben("p1: "+p1+"\n");
}
Liste1: [[0,0], [0,0], [0,0]]
Liste2: [[0,42], [0,0], [0,0]]
p1: [41,0]
Grundlagen Programmierung
Stephan Kleuker
402
Clone-Variante: Kopierkonstruktor
• Wenn häufiger Kopien gewünscht, dann auch als
Konstruktor realisierbar, der zu clonendes Objekt erhält
public Punkt(Punkt other){
this.x = other.getX();
this.y = other.getY();
}
• in Analyse, zuweisen2():
ap.add(new Punkt(p1));
ap.add(new Punkt(0,0));
ap.add(new Punkt(p1));
Liste1: [[0,0], [0,0], [0,0]]
Liste2: [[0,42], [0,0], [0,0]]
p1: [41,0]
Grundlagen Programmierung
Stephan Kleuker
403
Beispiel für (fast) vollständige Klasse (1/4)
public class Linie implements Cloneable{
private Punkt start;
private Punkt ende;
public Linie(Punkt start, Punkt ende) {
this.start = start;
this.ende = ende;
}
public Punkt getStart() {
return start;
}
public void setStart(Punkt start) {
this.start = start;
}
Grundlagen Programmierung
Stephan Kleuker
404
Beispiel für (fast) vollständige Klasse (2/4)
public Punkt getEnde() {
return ende;
}
public void setEnde(Punkt ende) {
this.ende = ende;
}
@Override
public String toString(){
return "["+this.start+"->"+this.ende+"]";
}
@Override
public Linie clone(){
return new Linie(this.start.clone(), this.ende.clone());
}
Grundlagen Programmierung
Stephan Kleuker
405
Beispiel für (fast) vollständige Klasse (3/4)
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Linie)) {
return false;
}
Linie other = (Linie) obj;
if (this.ende == null) {
if (other.getEnde() != null) {
return false;
}
} else if (!this.ende.equals(other.getEnde())) {
return false;
}
if (this.start == null) {
if (other.getStart() != null) {
return false;
}
} else if (!this.start.equals(other.getStart())) {
return false;
}
return true;
Grundlagen
Programmierung
Stephan Kleuker
}
}
406
Beispiel für (fast) vollständige Klasse (4/4)
public void linienspielerei(){
EinUndAusgabe io = new EinUndAusgabe();
Linie l1 = new Linie(new Punkt(0,0),new Punkt(3,3));
Linie l2 = l1;
Linie l3 = l2.clone();
io.ausgeben("l1==l2: "+(l1==l2)+"\n");
io.ausgeben("l1==l3: "+(l1==l3)+"\n");
io.ausgeben("l1.equals(l2): "+(l1.equals(l2))+"\n");
io.ausgeben("l1.equals(l3): "+(l1.equals(l3))+"\n");
l2.setStart(new Punkt(4,4));
l1==l2: true
io.ausgeben("l1: "+l1+"\n");
l1==l3: false
io.ausgeben("l2: "+l2+"\n");
l1.equals(l2): true
io.ausgeben("l3: "+l3+"\n");
l1.equals(l3): true
l3.setEnde(l2.getStart());
l1: [[4,4]->[3,3]]
l1.getStart().setY(42);
l2: [[4,4]->[3,3]]
io.ausgeben("l1: "+l1+"\n");
l3: [[0,0]->[3,3]]
io.ausgeben("l2: "+l2+"\n");
l1: [[4,42]->[3,3]]
io.ausgeben("l3: "+l3+"\n");
l2: [[4,42]->[3,3]]
}
l3: [[0,0]->[4,42]]
Grundlagen Programmierung
Stephan Kleuker
407
Analyse mit Speicherbildern (1/2)
Linie l1 = new Linie(new Punkt(0,0),new Punkt(3,3));
Linie l2 = l1;
Linie l3 = l2.clone();
start
l1
ende
x
0
y
0
x
3
y
3
x
0
y
0
x
3
y
3
l2
start
l3
ende
Grundlagen Programmierung
Stephan Kleuker
408
Analyse mit Speicherbildern (2/2)
l2.setStart(new Punkt(4,4));
l3.setEnde(l2.getStart());
l1.getStart().setY(42);
start
l1
ende
0
0
x
4
y
42
x
3
y
3
x
0
y
0
x
3
y
3
l2
start
l3
ende
Grundlagen Programmierung
Stephan Kleuker
409
Collection Framework
Grundlagen Programmierung
Stephan Kleuker
410
Ausschnitt aus Collection Framework (java.util)
Grundlagen Programmierung
Stephan Kleuker
411
Das Interface Collection (Ausschnitt)
Method Summary
boolean add(Object o)
Ensures that this collection contains the specified
element.
boolean addAll(Collection c)
Adds all of the elements in the specified
collection to this collection.
void clear()
Removes all of the elements from this collection.
boolean contains(Object o)
Returns true if this collection contains the
specified element.
boolean isEmpty()
Returns true if this collection contains no elements.
Iterator iterator()
Returns an iterator over the elements in this collection.
boolean remove(Object o) Removes a single instance of the specified element
from this collection, if it is present.
boolean retainAll(Collection c) Retains only the elements in this collection that
are contained in the specified collection
int size()
Returns the number of elements in this collection.
Object[] toArray()
Returns an array containing all of the elements in this
collection.
Benutzeroberflächen und
Software-Ergonomie
Stephan Kleuker
412
Das Interface List (Ausschnitt)
Method Summary
void add(int index, Object element) Inserts the specified element at the
specified position in this list.
boolean addAll(int index, Collection c)
Inserts all of the elements in the
specified collection into this list at the specified position.
Object get(int index) Returns the element at the specified position in this list.
int indexOf(Object o)
Returns the index in this list of the first
occurrence of the specified element, or -1 if this list does not contain
this element.
int lastIndexOf(Object o) Returns the index in this list of the last occurrence
of the specified element, or -1 if this list does not contain this element.
Object remove(int index) Removes (and returns) the element at the specified
position in this list.
Object set(int index, Object element) Replaces the element at the specified
position in this list with the specified element.
Benutzeroberflächen und
Software-Ergonomie
Stephan Kleuker
413
Warum verschiedene Sammlungen
Jede Implementierung besonders geeignet unter bestimmten
Rahmenbedingungen sollen Objekte doppelt
vorkommen können?
[ja]
spielt die Reihenfolge
eine Rolle?
[nein]
spielt die Reihenfolge
eine Rolle?
[ja]
[ja]
[nein]
[nein]
Liste
ArrayList
Vector
...
Multimenge
Bag (Apache
Collections)
Grundlagen Programmierung
sortierte Menge
SortedSet
...
Stephan Kleuker
Menge
HashSet
...
414
Beispielnutzung einer Menge (mit Problem)
public void objektInMengeLoeschen(){
EinUndAusgabe io = new EinUndAusgabe();
HashSet<Punkt> ap = new HashSet<Punkt>();
Punkt p1 = new Punkt(0,0);
ap.add(p1);
ap.add(new Punkt(0,0));
ap.add(p1);
io.ausgeben("Menge1: "+ap+"\n");
ap.remove(new Punkt(0,0));
io.ausgeben("Menge2: "+ap+"\n");
Menge1: [[0,0], [0,0]]
ap.remove(p1);
Menge2: [[0,0], [0,0]]
io.ausgeben("Menge3: "+ap+"\n");
Menge3: [[0,0]]
}
• Problem, da es den Punkt insgesamt nur einmal geben
sollte, er aber doppelt ist, nur Hinzufügen eines identischen
Objekts wird verhindert
Grundlagen Programmierung
Stephan Kleuker
415
Idee von hashCode()
• equals-Berechnungen können sehr aufwändig sein
• ergänze schnell zu berechnende Methode, die für gleiche
Elemente immer gleichen Wert liefert und für
unterschiedliche Objekte möglichst unterschiedlichen Wert
• Gleichheitsprüfung: prüfe, ob schnell berechnete Werte
übereinstimmen und nur dann wird equals ausgeführt
• ohne HashCode gilt aber:
public void zeigeHashCode(){
EinUndAusgabe io = new EinUndAusgabe();
Punkt p1 = new Punkt(0,0);
Punkt p2 = new Punkt(0,0);
io.ausgeben("p1: "+p1.hashCode()+"\n");
io.ausgeben("p2: "+p2.hashCode()+"\n");
}
Grundlagen Programmierung
Stephan Kleuker
p1: 14576877
p2: 12677476
416
Realisierung mit hashCode()
• in Punkt
@Override
public int hashCode() {
return this.x + (this.y*33);
}
p1: 0
p2: 0
• Methode zeigeHashCode() liefert
• Methode objektInMengeLoeschen() liefert
Menge1: [[0,0]]
Menge2: []
Menge3: []
Grundlagen Programmierung
Stephan Kleuker
417
Array
Grundlagen Programmierung
Stephan Kleuker
418
Idee von Arrays
• Nutzung der bisher bekannten Sammlungen kann recht
aufwändig sein, da z. B. beim Hinzufügen immer neuer Platz
im Speicher gesucht werden soll
• Effizienter sind Objekte, die einmal gespeichert werden und
ihre Größe nicht mehr ändern
• praktisch einsetzbar, wenn man die maximale Anzahl von
Objekten kennt, die alle den gleichen Typen haben und
deren Anzahl nicht allzu groß ist
• Zugehöriger Datentyp wird Array (Feld, Reihung) genannt
• besondere Form der Typangabe
<Typ>[] <Variablenname> ;
oder äquivalent
<Typ> <Variablenname> [];
• Arrays können wie Sammlungen iteriert werden, Länge
allerdings durch <Variablenname>.length bestimmbar
Grundlagen Programmierung
Stephan Kleuker
419
Varianten der Initialisierung
public class Analyse {
private String[] wo1 = {"Mo","Di","Mi","Do","Fr","Sa","So"};
private String[] wo2 = new String[7]; //null-Werte
private String[] wo3;
public void initialisieren(){
//this.wo3 = {"42"} geht nicht
this.wo3 = this.wo2;
EinUndAusgabe io = new EinUndAusgabe();
for(Integer i=0; i<this.wo1.length; i=i+1){
this.wo2[i]=this.wo1[i];
}
for(Integer i=0; i<this.wo3.length; i=i+1){
io.ausgeben(this.wo3[i]);
}
MoDiMiDoFrSaSo
io.ausgeben("\n");
}
Grundlagen Programmierung
Stephan Kleuker
420
Beispiel: Klasse für einen Lotto-Tipp (1/4)
• sinnvoll, Arrays mit eigener Bedeutung in Klassen zu kapseln
public class Tipp {
private Integer[] werte = new Integer[6];
public Tipp() {
EinUndAusgabe io = new EinUndAusgabe();
Integer i = 0;
while (i < this.werte.length) {
Integer kugel = io.zufall(1, 49);
if (kommtNichtVor(kugel, i)) {
this.werte[i] = kugel;
i = i + 1;
}
}
}
Grundlagen Programmierung
Stephan Kleuker
421
Beispiel: Klasse für einen Lotto-Tipp (2/4)
public Boolean kommtNichtVor(Integer wert, Integer position){
for (Integer i = 0; i < position; i = i + 1) {
if (this.werte[i].equals(wert)) {
return false;
}
}
return true;
}
public Integer[] getWerte() {
return this.werte;
}
public void setWerte(Integer[] werte) {
this.werte = werte;
}
Grundlagen Programmierung
Stephan Kleuker
422
Beispiel: Klasse für einen Lotto-Tipp (3/4)
public Boolean enthaelt(Integer wert) {
for (Integer i : this.werte) {
if (i.equals(wert)) {
return true;
}
}
return false;
}
@Override
public String toString() {
String ergebnis = "[ ";
for (Integer i : this.werte) {
ergebnis = ergebnis + i + " ";
}
return ergebnis + "]";
}
Grundlagen Programmierung
Stephan Kleuker
423
Beispiel: Klasse für einen Lotto-Tipp (4/4)
• Analyse der Übereinstimmungen von zwei Tipps
• Ansatz: Jedes Element des ersten Tipps wird mit jedem
Element des zweiten Tipps verglichen (gibt keine Doppelten)
public Integer gemeinsam(Tipp tip) {
Integer ergebnis = 0;
for (Integer i : this.werte) {
for (Integer j : tip.getWerte()) {
if (i.equals(j)) {
ergebnis = ergebnis + 1;
}
}
}
return ergebnis;
}
}
Grundlagen Programmierung
Stephan Kleuker
424
Testen von Tipp (1/2)
public class TippTest {
private Tipp t1 = new Tipp();
private Tipp t2 = new Tipp();
@Test
public void testUnterschiedlicheWerte(){
for(Integer i=0; i<100; i=i+1){
unterschiedlich(new Tipp());
}
}
private void unterschiedlich(Tipp tip){
Integer inhalt[] = tip.getWerte();
for(Integer i=0; i<inhalt.length-1; i=i+1){
Assert.assertTrue(inhalt[i]>0 && inhalt[i]<50);
for(Integer j=i+1; j<inhalt.length; j=j+1){
Assert.assertTrue(!inhalt[i].equals(inhalt[j]));
}
}
Grundlagen Programmierung
Stephan Kleuker
}
425
Testen von Tipp (2/2) - Ausschnitt
@Test
public void testNuller(){
t1.setWerte(new Integer[]{1,2,3,4,5,6});
t2.setWerte(new Integer[]{11,12,13,14,15,16});
Assert.assertTrue(t1.gemeinsam(t2).equals(0));
}
@Test
public void testFuenfer(){
t1.setWerte(new Integer[]{4,12,43,24,5,36});
t2.setWerte(new Integer[]{31,12,43,4,24,36});
Assert.assertTrue(t1.gemeinsam(t2).equals(5));
}
@Test
public void testSechser(){
t1.setWerte(new Integer[]{4,12,43,24,36,31});
t2.setWerte(new Integer[]{31,12,43,4,24,36});
Assert.assertTrue(t1.gemeinsam(t2)==.equals(6));
}
}
Grundlagen Programmierung
Stephan Kleuker
426
Analyse von Häufigkeiten (1/3)
public void haeufigkeiten(Integer anzahl){
Tipp mein = new Tipp();
Integer[] ergebnis = { 0, 0, 0, 0, 0, 0, 0 };
Integer[] gezogen = new Integer[49];
for (Integer i = 0; i < gezogen.length; i = i + 1) {
gezogen[i] = 0;
}
losenUndAuswerten(mein, ergebnis, gezogen, anzahl);
EinUndAusgabe io = new EinUndAusgabe();
for(Integer i = 0; i < ergebnis.length; i = i + 1){
io.ausgeben(i+"er: "+ergebnis[i]+"\n");
}
for(Integer i = 0; i < gezogen.length; i = i + 1){
io.ausgeben((i+1)+":"+gezogen[i]+" ");
if((i+1)%6 == 0){
io.ausgeben("\n");
}
}
}
Grundlagen
Programmierung
Stephan Kleuker
427
Analyse von Häufigkeiten (2/3)
public void losenUndAuswerten(Tipp mein, Integer[] ergebnis,
Integer[] gezogen, Integer anzahl) {
for (Integer i = 0; i < anzahl; i = i + 1) {
Tipp tmp = new Tipp();
Integer treffer = mein.gemeinsam(tmp);
ergebnis[treffer] = ergebnis[treffer] + 1;
for (Integer j = 0; j < 49; j = j + 1) {
if (tmp.enthaelt(j + 1)) {
gezogen[j] = gezogen[j] + 1;
}
}
}
}
Grundlagen Programmierung
Stephan Kleuker
428
Analyse von Häufigkeiten (3/3) – 2000000 Versuche
• Dauer: 14 Sekunden
0er: 870573
1er: 828056
2er: 263832
3er: 35540
4er: 1967
5er: 32
6er: 0
1:244608 2:244572 3:245968 4:245208 5:244385 6:245379
7:244733 8:244578 9:243898 10:244732 11:245054 12:244219
13:244770 14:245695 15:244858 16:244865 17:244949 18:244964
19:244590 20:245296 21:244815 22:244602 23:244568 24:244466
25:245505 26:244264 27:244369 28:245617 29:245516 30:245340
31:245063 32:244694 33:245223 34:244721 35:245899 36:244103
37:244962 38:245284 39:245049 40:245308 41:244512 42:244984
43:244649 44:244848 45:244985 46:245573 47:244426 48:244670
49:244664
Grundlagen Programmierung
Stephan Kleuker
429
Mehrdimensionale Arrays 1
• Achtung niemals dadurch Klassen ersetzen!
public void mehrdimensional1(){
EinUndAusgabe io = new EinUndAusgabe();
String[][] werte = {{"Mo","Jo","USA"}
,{"Luc","Lack","FRA"}};
for(String[] stud:werte){
for(String dat:stud){
io.ausgeben(dat+" ");
}
io.ausgeben("\n");
Mo Jo USA
}
Luc Lack FRA
}
Grundlagen Programmierung
Stephan Kleuker
430
Mehrdimensionale Arrays 2
public void mehrdimensional2(){
EinUndAusgabe io = new EinUndAusgabe();
String[][][] all = {{{"Mo","Jo","USA", "NY"}
,{"Luc","Lack","FRA"}}
,{{"Sue","Wue","PRC"}
,{"Sam","Fox","GB", "ENG"}}};
for(String[][] sem:all){
for(String[] stud:sem){
Mo Jo USA NY
for(String dat:stud){
Luc Lack FRA
io.ausgeben(dat+" ");
*****
}
Sue Wue PRC
io.ausgeben("\n");
Sam Fox GB ENG
*****
}
io.ausgeben("*****\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
431
Erinnerung: Arbeit mit Referenzen
Ausgangspunkt
• Gegeben Klasse Punkt
– mit Objektvariablen x, y
– zugehörigen get- und set-Methoden
– passender equals-Methode
– und toString-Methode
• Klasse Interaktionsbrett u. a. zum Zeichnen von Linien
void neueLinie(java.lang.Integer x1, java.lang.Integer y1,
java.lang.Integer x2, java.lang.Integer y2)
Methode zum Zeichnen einer neuen Linie.
Grundlagen Programmierung
Stephan Kleuker
432
Arrays und Referenzen (1/5)
public class FigurMalerei{
private
private
private
private
Interaktionsbrett ib = new Interaktionsbrett();
Punkt p1 = new Punkt(20,30);
Punkt p2 = new Punkt(50,30);
Punkt[][] figuren = {dreieck(p1,p2,new Punkt(35,5)),
dreieck(new Punkt(35,55),p2,p1)};
public Punkt[] dreieck(Punkt p1, Punkt p2, Punkt p3){
return new Punkt[]{p1,p2,p3};
}
Grundlagen Programmierung
Stephan Kleuker
433
Ausgangssituation im Speicher
p1
p2
[0]
figuren
x
20
y
30
x
50
y
30
[0]
x
[1]
35
y
5
x
35
y
55
[0]
[1]
[2]
[1]
[2]
Stephan Kleuker
434
Arrays und Referenzen (2/5)
public void malen(Punkt[] punkte){
for(Integer i=0; i<punkte.length; i=i+1){
this.ib.neueLinie(punkte[i].getX(),
punkte[i].getY(),
punkte[(i+1)%punkte.length].getX(),
punkte[(i+1)%punkte.length].getY());
}
}
public void malen(){
for(Punkt[] arr:this.figuren){
malen(arr);
}
}
Grundlagen Programmierung
Stephan Kleuker
435
Arrays und Referenzen (3/5)
public void analyse1(){
malen();
}
Grundlagen Programmierung
Stephan Kleuker
436
Arrays und Referenzen (4/5)
public void analyse2(){
this.figuren[0][2].setX(50);
malen();
}
Grundlagen Programmierung
Stephan Kleuker
437
Arrays und Referenzen (5/5)
public void analyse3(){
this.p1.setX(2);
malen();
}
Grundlagen Programmierung
Stephan Kleuker
438
Auswahl einer Collection
Grundlagen Programmierung
Stephan Kleuker
439
Erinnerung und Erweiterung: Studentenverwaltung
Nächste Aktion:
(0) Programm beenden
(1) Neuen Studenten einfügen
(2) Student mit Matrikelnummer suchen
(3) Studierendendaten ändern
(4) Studierende pro Studiengang
(5) Student löschen
(6) Studenten eines Fachs löschen
(7) Neuen Austauschstudenten einfügen
(8) Anzahl Austauschstudenten ausgeben
(9) Alle Studierenden anzeigen
public class Studentenverwaltung {
private ArrayList<Student> studenten;
Grundlagen Programmierung
Stephan Kleuker
440
Aufgabe: (9) Alle Studierenden anzeigen
• einfache Realisierung
public void zeigeAlleStudenten(){
EinUndAusgabe io = new EinUndAusgabe();
for (Student s: this.studenten){
io.ausgeben(s+"\n");
}
}
• ArrayList sehr einfach nutzbar, wenn Sammlung von
Objekten vollständig verarbeitet werden soll
• Vorüberlegung: HashSet etwas besser, da doppelte
Studenten vermieden werden (aber keine Vergabe
doppelter Matrikelnummern)
Grundlagen Programmierung
Stephan Kleuker
441
Analyse der Implementierung
public Student studentSuchen(Integer mat){
for(Student s:this.studenten){
if(s.getMatrikelnummer().equals(mat)){
return s;
}
}
return null;
}
• sehr aufwändige Realisierung, da immer alle Objekte
durchsucht werden
• zeigeAlleStudenten(): sehr einfache Realisierung, da immer
alle Studierende durchlaufen werden müssen
• wenn studentSuchen() sehr häufig genutzt, könnte das
Programm hier als langsam angesehen werden
• toll wäre Ansatz der schnellen Arrays mit direktem Zugriff
auf das Objekt
Grundlagen Programmierung
Stephan Kleuker
442
java.util.HashMap
• Idee: Speichere Objekte in Paaren (Key, Value), z. B.
(Matrikelnummer, zugehöriger Student)
• Ähnlich wie Array mit Paaren (Integer, Feldinhalt)
• zentrale Methoden:
– get (Key): gibt das zugehörige Value-Objekt (oder null)
– put(Key,Value): trägt das Paar in die HashMap ein; sollte
für Key anderer Value-Eintrag vorliegen, wird dieser
überschrieben
– remove(Key): löscht den Eintrag zum zugehörigen Key
• hilfreich:
– containsKey(Key): existiert zum Key ein Value-Objekt
– containsValue(Value): existiert Value-Objekt in HashMap
Grundlagen Programmierung
Stephan Kleuker
443
Erinnerung: ordentlicher Punkt (ohne null) (1/2)
public class Punkt {
private Integer x;
private Integer y;
public Punkt(Integer x, Integer y) {
this.x = x;
this.y = y;
}
public Integer getX() { return this.x; }
public Integer getY() { return this.y; }
public void setX(Integer x) { this.x = x; }
public void setY(Integer y) { this.y = y; }
Grundlagen Programmierung
Stephan Kleuker
444
Erinnerung: ordentlicher Punkt (ohne null) (2/2)
@Override
public String toString(){
return "["+this.x+","+this.y+"]";
}
@Override
public int hashCode() { return this.x + (this.y*33); }
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Punkt)) {
return false;
}
Punkt other = (Punkt) obj;
return (this.x.equals(other.getX())
&& this.y.equals(other.getY()));
}
}
Grundlagen
Programmierung
Stephan Kleuker
445
Beispiel für HashMap-Nutzung (1/2)
import java.util.HashMap;
public class HashMapSpielerei{
public void analyse(){
HashMap<Integer,Punkt> punkte
= new HashMap<Integer,Punkt>();
EinUndAusgabe io = new EinUndAusgabe();
Punkt p = new Punkt(1,1);
punkte.put(17, new Punkt(0,0));
punkte.put(1, p);
punkte.put(18, p);
io.ausgeben("A: "+punkte+"\n");
A: {17=[0,0], 1=[1,1], 18=[1,1]}
Grundlagen Programmierung
Stephan Kleuker
446
Beispiel für HashMap-Nutzung (2/2)
p.setY(4);
io.ausgeben("B: "+punkte+"\n");
io.ausgeben("C: "+punkte.get(1)+"\n");
io.ausgeben("D: "+punkte.get(2)+"\n");
punkte.put(17, new Punkt(3,3));
io.ausgeben("E: "+punkte+"\n");
punkte.remove(18);
io.ausgeben("F: "+punkte+"\n");
punkte.put(1,null);
io.ausgeben("G: "+punkte+"\n")
}
}
Grundlagen Programmierung
B:
C:
D:
E:
F:
G:
{17=[0,0],
[1,4]
null
{17=[3,3],
{17=[3,3],
{17=[3,3],
Stephan Kleuker
1=[1,4], 18=[1,4]}
1=[1,4], 18=[1,4]}
1=[1,4]}
1=null}
447
Änderungen in Studentenverwaltung (1/4)
import java.util.HashMap;
public class Studentenverwaltung{
private HashMap<Integer,Student> studenten;
public Studentenverwaltung(){
studenten = new HashMap<Integer,Student>();
}
public void hinzufuegen(Student neu){
studenten.put(neu.getMatrikelnummer(),neu);
}
// weitere, zunächst kleine Anpassungen in get- und set
Grundlagen Programmierung
Stephan Kleuker
448
Änderungen in Studentenverwaltung (2/4)
// machbar, aber diese Methode ist sehr rechenintensiv,
// wenn häufiger benötigt, dann besser auf HashMap verzichten
public void zeigeAlleStudenten(){
EinUndAusgabe io = new EinUndAusgabe();
for (Student s: this.studenten.values()){
io.ausgeben(s+"\n");
}
}
public void studentloeschen(Integer mat) {
EinUndAusgabe io = new EinUndAusgabe();
Student tmp = this.studenten.remove(mat);
if(tmp!=null){
io.ausgeben("Student gel\u00f6scht\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
449
Änderungen in Studentenverwaltung (3/4)
// Nutzung unterschiedlicher Sammlungen zusammen
public Integer studiengangLoeschen(String fach) {
ArrayList<Integer> weg = new ArrayList<Integer>();
for(Student tmp:this.studenten.values()){
if(tmp.getStudiengang().equals(fach)){
weg.add(tmp.getMatrikelnummer());
}
}
for(Integer tmp:weg){
this.studenten.remove(tmp);
}
return weg.size();
}
public Student studentSuchen(Integer mat){
return this.studenten.get(mat);
}
Grundlagen Programmierung
Stephan Kleuker
450
Änderungen in Studentenverwaltung (4/4)
// jetzt sehr einfache Programmverbesserung möglich
public void studentEingeben(){
Student ergebnis = new Student();
ergebnis.setVorname(nichtLeererText("Vorname"));
ergebnis.setNachname(nichtLeererText("Nachname"));
ergebnis.setStudiengang(nichtLeererText("Studiengang"));
ergebnis.setGeburtsjahr(
zahlZwischen("Geburtsjahr",1900,2000));
Integer mat = zahlZwischen("Matrikelnummer",99999,1000000);
if(studenten.get(mat) == null){
ergebnis.setMatrikelnummer(mat);
hinzufuegen(ergebnis);
} else {
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("keine doppelten Matrikelnummern");
}
Grundlagen
Programmierung
Stephan Kleuker
451
}
ArrayList oder HashSet
• Erinnerung:
– ArrayList: Doppelte möglich, Ordnung beibehalten
– HashSet: keine Doppelten, ungeordnet
• Idee: HashSet besser, da so doppelte Einträge vermieden
werden
• Stimmt, da kein Student mehrfach eintragbar
• bleibt kritisch, da Matrikelnummer immer noch doppelt
vergebbar (außer wenn equals nur Matrikelnummer prüft;
dann überschreibt aber neuer Student alten Studenten)
• Fazit 1: Doppelte Matrikelnummernvergabe immer prüfen
• Fazit 2: HashSet etwas besser als ArrayList geeignet
Grundlagen Programmierung
Stephan Kleuker
452
Exception
Grundlagen Programmierung
Stephan Kleuker
453
Erinnerung: Studentenverwaltung
***Semester XXXX***
Nächste Aktion:
(0) Programm beenden
(1) Neuen Studenten einfügen
(2) Student mit Matrikelnummer suchen
(3) Studierendendaten ändern
(4) Studierende pro Studiengang
(5) Student löschen
(6) Studenten eines Fachs löschen
(7) Neuen Austauschstudenten einfügen
(8) Anzahl Austauschstudenten ausgeben
(9) Alle Studierenden anzeigen
(10) Semester eintragen
public class Studentenverwaltung {
private ArrayList<Student> studenten;
private String semester = "Semester XXXX";
Grundlagen Programmierung
Stephan Kleuker
454
Schreiben – Ansatz (1/2)
• Basisansatz: Lesen (Input) oder Schreiben (Output) einzelner
Bytes einer Datei(machbar, aber für Datentypen, die größer als
Byte sind, unhandlich)
• Es handelt sich um Streams
• Schreiben: Datei öffnen und immer hinten anfügen
• Lesen: Datei öffnen und von vorne nach hinten lesen
• Streams sind immer unidirektional (lesen / schreiben)
• Das Paket java.io stellt verschiedene Klassen zur Verfügung,
die auf dem Streamkonzept basieren
Grundlagen Programmierung
Stephan Kleuker
455
Schreiben – Ansatz (2/2)
• Prinzipieller Ansatz
– öffne Datei
– schreibe relevante Informationen
– schließe Datei (WICHTIG !!!! -> schleichender Fehler)
• Frage was wird geschrieben
• Antwort: hängt von der genutzten Realisierung ab, abhängig
vom Einsatzbereich
• Ansatz hier: es können beliebige Beans geschrieben werden
– Beans:
• parameterloser Konstruktor
• get- und set-Methoden für alle Objektvariablen
• Typen der Objektvariablen sind Beans
Grundlagen Programmierung
Stephan Kleuker
456
Öffnen einer Datei
• Java erlaubt einfaches Lesen und Speichern im XML-Format,
wenn alle zu speichernden Objekte get- und set- Methoden
in Standard-Form und parameterlosen Konstruktor haben
• Zum Öffnen einer Datei "datei.xml" zum Schreiben von
Daten wird folgende Konstruktion genutzt
XMLDecoder file = null;
file = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream("datei.xml")));
• Ermöglicht das sequentielle Schreiben (hintereinander) von
Objekten in die Datei
• Konstruktion wird (deutlich) später erläutert, muss jetzt
erstmal hingenommen werden
Grundlagen Programmierung
Stephan Kleuker
457
Notwendige Imports
• Hier kompakte Übersicht, weitere Erklärungen bei Nutzung
import
import
import
import
import
import
import
import
import
java.beans.XMLDecoder;
java.beans.XMLEncoder;
java.io.BufferedInputStream;
java.io.BufferedOutputStream;
java.io.File;
java.io.FileInputStream;
java.io.FileNotFoundException;
java.io.FileOutputStream;
java.util.ArrayList;
Grundlagen Programmierung
Stephan Kleuker
458
Programmerweiterungsfragmente
+ "(11) Daten speichern\n"
+ "(12) Daten laden: ");
case 11: {
datenSpeichern();
break;
}
case 12: {
datenLaden();
break;
}
public void datenSpeichern() {
String datei = nichtLeererText(
"Dateiname (Abbruch mit \"Ende\")");
if (!datei.toUpperCase().equals("ENDE")) {
datenSpeichern(datei);
}
}
Grundlagen Programmierung
Stephan Kleuker
459
Programmfragment – nicht lauffähig
• der markierte Konstruktor kann eine sogenannte Exception
(Ausnahme) werfen, die behandelt werden muss
Grundlagen Programmierung
Stephan Kleuker
460
Exception - Anwendungsszenario
bisher bekannt
• typischer Ablauf: Sequenz und Schleifen mit typischen
Verhalten
• alternative Abläufe: erwartete Spezialfälle, die den typischen
Ablauf variieren (if- Anweisungen)
neu
• Ausnahme-Situationen, die keinen typischen Programmablauf
ermöglichen, aber in denen das Programm sinnvoll reagieren
kann, Beispiele:
– erfolgreicher Aufbau einer Datenbankverbindung,
Netzwerkverbindung oder zu einer Datei, die während der
Nutzung abbricht
• Wunsch: Programm wieder in einen nutzbaren Zustand führen
Grundlagen Programmierung
Stephan Kleuker
461
Exception - Ablaufprinzip
Ausnahmesituation tritt auf
• wenn Situation erkannt, wird typischer Programmablauf
sofort verlassen und Programmstück für diesen Fehler
angesprungen
• das Programmstück ist entweder in der Methode, die gerade
läuft, oder in einer aufrufenden Methode
• sinnvoll: unabhängig ob Ausnahmesituation aufgetreten ist,
sollten Abschlussaktionen möglich sein
wichtige Hinweise:
• Exception sollen nicht einfaches if ersetzen
• Exception-Handling soll keine Programmierfehler kaschieren
Grundlagen Programmierung
Stephan Kleuker
462
Beispiel: lokale Behandlung
public void datenSpeichern(String datei) {
XMLEncoder file = null;
try {
file = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream(datei)));
file.writeObject(semester);
file.writeObject(studenten);
} catch (FileNotFoundException e) {
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("Probleme beim Schreiben: " + e);
} finally {
if (file != null) {
file.close();
}
}
}
Grundlagen Programmierung
Stephan Kleuker
463
Fall 1: lokale Exception-Behandlung
Grundlagen Programmierung
Stephan Kleuker
Typ1
Typ2
TypX
464
Methode weiterleiten (Fall2)
ohne
Exception an aufrufende
public void machWas(...) {
normalesProgramm;
normalesProgramm;
try {
normalesProgramm;
AnweisungEvtlException;
normalesProgramm;
} catch (ExceptionTyp1 e) {
ReaktionAufException;
} catch (ExceptionTyp2 e) {
ReaktionAufException;
} finally {
Abschlussaktion;
}
normalesProgramm;
}
Speicherergebnis (Ausschnitt)
Dateiname (Abbruch mit "Ende"): daten.xml
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_12" class="java.beans.XMLDecoder">
<string>Semester XXXX</string>
<object class="java.util.ArrayList">
<void method="add">
<object class="Student">
<void property="geburtsjahr">
<int>1987</int>
</void>
<void property="matrikelnummer">
<int>424241</int>
</void>
<void property="nachname">
<string>X</string>
</void>
...
Grundlagen Programmierung
Stephan Kleuker
465
Einschub: BlueJ-Macke
• BlueJ hat Schwierigkeiten mit der Nutzung der Klassen
XMLDecoder und XMLEncoder
• Typische Fehlermeldung:
java.lang.reflect.InvocationTargetException
Continuing ...
• Lösung: einmal, z. B. im Konstruktor, muss vor der Nutzung
folgende Zeilen ergänzt werden:
public Studentenverwaltung() {
Thread.currentThread().setContextClassLoader(getClass()
.getClassLoader());
studenten = new ArrayList<Student>();
}
Grundlagen Programmierung
Stephan Kleuker
466
Laden - Ansatz
• Der Ansatz zum Laden ist sehr ähnlich zum Speichern
• Es wird wieder ein Stream benutzt, aus dem Daten gelesen
werden können (eine Datei kann z. B. als Stream geöffnet
werden)
• die Daten werden wieder Schritt für Schritt eingelesen; dabei
muss die Reihenfolge des Schreibens beachtet werden
• mit readObject werden Objekte gelesen, die gecastet werden
müssen
• wieder ist das Schließen der Datei eminent wichtig
• wieder müssen Ausnahmen (Datei nicht lesbar, oder
Verbindung bricht ab) beachtet werden
• Anmerkung: Klasse java.io.File kann zur Analyse von Dateien
genutzt werden
Grundlagen Programmierung
Stephan Kleuker
467
Datei zum Laden auswählen
public void datenLaden() {
EinUndAusgabe io = new EinUndAusgabe();
String datei=nichtLeererText("Dateiname (Abbruch \"Ende\")");
if (datei.toUpperCase().equals("ENDE")){
return;
}
File file = new File(datei);
if (!file.exists()){
io.ausgeben("Datei existiert nicht.\n");
return;
}
if (file.isDirectory()){
io.ausgeben("Verzeichnis nicht nutzbar.\n");
return;
}
if (!file.canRead()) {
io.ausgeben("Datei nicht lesbar.\n");
return;
}
datenLaden(datei);
}
Grundlagen Programmierung
Stephan Kleuker
468
Datei laden
public void datenLaden(String datei) {
EinUndAusgabe io = new EinUndAusgabe();
XMLDecoder file = null;
try {
file = new XMLDecoder(
new BufferedInputStream(
new FileInputStream(datei)));
this.semester = (String) file.readObject();
this.studenten = (ArrayList<Student>) file.readObject();
io.ausgeben("Daten geladen.\n");
} catch (FileNotFoundException e) {
io.ausgeben("Probleme beim Lesen: " + e);
} finally {
if(file!=null){
file.close();
}
}
Grundlagen Programmierung
Stephan Kleuker
469
}
Ausschnitt Nutzungsdialog
(12) Daten laden: 12
Dateiname (Abbruch mit "Ende"): Hallo.text
Datei existiert nicht.
(12) Daten laden: 12
Dateiname (Abbruch mit "Ende"): ..
Verzeichnis nicht nutzbar.
(12) Daten laden: 12
Dateiname (Abbruch mit "Ende"): eNDe
(12) Daten laden: 12
Dateiname (Abbruch mit "Ende"): daten.xml
Daten geladen.
Grundlagen Programmierung
Stephan Kleuker
470
Nerviger Compiler
•
•
•
•
Programm erzeugt beim Übersetzen eine Warning
Grundregel: Warning beseitigen
Hier: Warning hat Recht, kann aber nicht beseitigt werden
Ansatz nur in solchen Fällen: spezielle Annotation
@SuppressWarnings("unchecked")
public void datenLaden(String datei) {
Grundlagen Programmierung
Stephan Kleuker
471
Test
• Wichtig: Aufräumen nicht vergessen (noch besser in @Beforeund @After-Methoden, da dann garantiert ausgeführt)
@Test
public void testPersistenz1(){
studis.datenSpeichern("tmp.txt");
studis.studiengangLoeschen("ITI");
studis.studiengangLoeschen("MID");
studis.datenLaden("tmp.txt");
Assert
.assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
Assert
.assertTrue(studis.studentenZaehlenIn("MID").equals(2));
File file = new File("tmp.txt");
file.delete();
}
• weitere Testsszenarien denkbar und sinnvoll
Grundlagen Programmierung
Stephan Kleuker
472
Fall 2: Exception weiterreichen
• Wird eine Exception nicht lokal behandelt, wird sie an die
aufrufende Methode weitergeleitet
• Damit Weiterleitung möglich, muss hinter der
Parameterliste eine throws-Zeile mit allen möglichen
Exceptiontypen stehen
public void mach() throws ExceptionTyp1, ExceptionTyp2
• in der aufrufenden Methode muss Exception bearbeitet
werden, wieder
– Fall 1: lokal behandeln
– Fall 2: über throws-Deklaration an aufrufende Methode
weiterleiten
• existiert aufrufende Methode nicht, endet Programm mit
Fehlermeldung
Grundlagen Programmierung
Stephan Kleuker
473
Beispiel: Weiterreichen einer Exception (1/2)
@SuppressWarnings("unchecked")
public void datenLaden(String datei)
throws FileNotFoundException {
XMLDecoder file = null;
file = new XMLDecoder(new BufferedInputStream(
new FileInputStream(datei)));
this.semester = (String) file.readObject();
this.studenten = (ArrayList<Student>) file.readObject();
file.close();
}
Grundlagen Programmierung
Stephan Kleuker
474
Beispiel: Weiterreichen einer Exception (2/2)
public void datenLaden() {
EinUndAusgabe io = new EinUndAusgabe();
String datei = nichtLeererText("Dateiname "
+"(Abbruch mit \"Ende\")");
if (datei.toUpperCase().equals("ENDE")) {
return;
}
try {
datenLaden(datei);
io.ausgeben("Daten geladen.\n");
} catch (FileNotFoundException e) {
io.ausgeben("Problem beim Laden.\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
475
Variante
• zumindest theoretisch könnte Datei offen bleiben
• zu try muss es zumindest catch- oder finally-Block geben
@SuppressWarnings("unchecked")
public void datenLaden2(String datei)
throws FileNotFoundException {
XMLDecoder file = null;
try {
file = new XMLDecoder(new BufferedInputStream(
new FileInputStream(datei)));
this.semester = (String) file.readObject();
this.studenten = (ArrayList<Student>) file.readObject();
} finally {
if (file != null) {
file.close();
}
}
}
Grundlagen
Programmierung
Stephan Kleuker
476
Testen von unerwünschten Exceptions
@Test
public void testPersistenz1(){
try {
studis.datenSpeichern("tmp.txt");
studis.studiengangLoeschen("ITI");
studis.studiengangLoeschen("MID");
studis.datenLaden("tmp.txt");
Assert
.assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
Assert
.assertTrue(studis.studentenZaehlenIn("MID").equals(2));
File file = new File("tmp.txt");
file.delete();
} catch (FileNotFoundException e) {
Assert.assertTrue("unerwartete Exception",false);
}
}
Grundlagen Programmierung
Stephan Kleuker
477
Testen von erwünschten Exceptions
@Test
public void testPersistenz2(){
try {
File file = new File("tmp.txt");
file.delete();
studis.datenLaden("tmp.txt");
Assert.assertTrue(false);
} catch (FileNotFoundException e) {
Assert
.assertTrue(studis.studentenZaehlenIn("IMI").equals(2));
Assert
.assertTrue(studis.studentenZaehlenIn("MID").equals(2));
}
}
Grundlagen Programmierung
Stephan Kleuker
478
Fall 2: weiterleitende Exception-Behandlung
Typ1
Typ2
Exception an aufrufende
Methode weiterleiten (Fall2)
public void rufAuf(...)
throws ExTyp2 {
ohne
normalesProgramm;
try {
machWas(...);
normalesProgramm;
} catch (ExTyp1 e) {
ReaktionAufException;
} finally {
Abschlussaktion;
}
}
public void machWas(...)
throws ExTyp1, ExTyp2 {
normalesProgramm;
AnweisungEvtlException;
normalesProgramm;
}Grundlagen Programmierung
Stephan Kleuker
479
Exceptions selbst werfen (auslösen)
• In unerwünschten Situationen kann man selbst Exceptions
werfen; hierzu dient der Befehl throw, genauer
throw new ExceptionTyp("Grund der Ausnahme");
• Man kann hier bereits in Java existierende Exceptions
nutzen, die typischerweise einen Konstruktor mit zu
übergebendem Grund enthalten
• Man kann selbst Exception-Klassen schreiben; diese müssen
von der Klasse Exception oder einer anderen existierenden
Exception erben
– üblich ist ein Konstruktor, dem der Grund als String
übergeben werden kann
• Konzept der Exception-Nutzung muss einheitlich im Projekt
geklärt werden
Grundlagen Programmierung
Stephan Kleuker
480
Nutzung existierender Exception (1/2)
public void datenSpeichern3(String datei)
throws FileNotFoundException, IllegalArgumentException {
if(!datei.startsWith("StudSave")){
throw new IllegalArgumentException("Dateianfang "
+ "mit StudSave ignoriert");
}
XMLEncoder file = null;
file = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream(datei)));
file.writeObject(semester);
file.writeObject(studenten);
file.close();
}
Grundlagen Programmierung
Stephan Kleuker
481
Nutzung existierender Exception (2/2)
public void datenSpeichern() {
EinUndAusgabe io = new EinUndAusgabe();
String datei = nichtLeererText("Dateiname "
+"(Abbruch mit \"Ende\")");
if (!datei.toUpperCase().equals("ENDE")) {
try {
datenSpeichern(datei);
io.ausgeben("Speichern erfolgreich.\n");
} catch (FileNotFoundException e) {
io.ausgeben("Speicherproblem: " + e.getMessage()+ "\n");
} catch (IllegalArgumentException e) {
io.ausgeben("Namensproblem: " + e.getMessage()+ "\n");
}
}
(11) Daten speichern
}
(12) Daten laden: 11
Dateiname (Abbruch mit "Ende"): Sicherung
Namensproblem: Dateianfang mit StudSave ignoriert
Grundlagen Programmierung
Stephan Kleuker
482
Eigene Exception
public class DateinamenException extends Exception {
public DateinamenException(){
super("Muss mit StudSave beginnen");
}
public DateinamenException(String grund){
super(grund);
}
}
Grundlagen Programmierung
Stephan Kleuker
483
Nutzung eigener Exception (1/2)
public void datenSpeichern4(String datei)
throws FileNotFoundException, DateinamenException {
if(!datei.startsWith("StudSave")){
throw new DateinamenException();
}
XMLEncoder file = null;
file = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream(datei)));
file.writeObject(semester);
file.writeObject(studenten);
file.close();
}
Grundlagen Programmierung
Stephan Kleuker
484
Nutzung eigener Exception (2/2)
public void datenSpeichern() {
EinUndAusgabe io = new EinUndAusgabe();
String datei = nichtLeererText("Dateiname "
+"(Abbruch mit \"Ende\")");
if (!datei.toUpperCase().equals("ENDE")) {
try {
datenSpeichern4(datei);
io.ausgeben("Speichern erfolgreich.\n");
} catch (FileNotFoundException e) {
io.ausgeben("Speicherproblem: " + e.getMessage()+ "\n");
} catch (DateinamenException e) {
io.ausgeben("Namensproblem: " + e.getMessage()+ "\n");
}
}
(11) Daten speichern
}
(12) Daten laden: 11
Dateiname (Abbruch mit "Ende"): Sicherung
Namensproblem: Muss mit StudSave beginnen
Grundlagen Programmierung
Stephan Kleuker
485
Ausschnitt aus Java-Exception-Klassen
Grundlagen Programmierung
Stephan Kleuker
486
Ausnahmenarten
• Alle neuen Sprachen erlauben Exception Handling
• Ausnahme werfen, wenn nicht erwarte Situation auftritt
• Programmierfehler (z. B. NullPointerException), führt zum
Programmabbruch; nie ernsthaft behandeln, nur z. B. in einer
speziellen Log-Datei notieren
• Echte Fehler (Error) sollen nie behandelt werden
• Exceptions, die von RuntimeExeption erben, müssen nicht
behandelt werden (unchecked Exception) und müssen nicht
(dürfen schon) in throws-Listen stehen
• Andere (checked) Exceptions müssen behandelt werden;
nach außen geben (throws) oder behandeln (try-catch-finally)
Grundlagen Programmierung
Stephan Kleuker
487
Anmerkungen zu try-catch
• Man kann try-catch-Blöcke beliebig ineinander schachteln
• Man kann einen oder mehr catch-Blöcke zu einem try
definieren
• Compiler prüft, ob catch-Blöcke theoretisch erreichbar sind
(nie erst allgemeine, dann spezielle Exception fangen)
• Es können neue Exceptions auch in catch-Blöcken (weiter)
geworfen werden; es beginnt neue Exception-Behandlung
• Exceptions können gefangen und wieder geworfen werden
catch(ExeptionTypX e){
throw e;
• Bei Vererbung darf eine überschreibende Methode in einer
erbenden Klasse nur die Exceptions der überschriebenen
Methode der beerbten Klasse (oder weniger) werfen
Grundlagen Programmierung
Stephan Kleuker
488
Zusammenfassung zu Exceptions
• In größeren Projekten wird festgelegt, wann es sich um
unerwünschte, aber behandelbare Ausnahmen handelt
• Für Ausnahmen werden eigene Klassen geschrieben (erben
von Exception)
• Für Ausnahmen wird festgelegt, wer reagieren kann (wenn
lokal möglich, dann da, sonst weitergeben)
• Für jeden Konstruktor und jede Methode wird
dokumentiert, welche Exceptions sie werfen können
(Erklärung in der Dokumentation)
• Typisch ist, dass Ausnahmen protokolliert werden
• catch (Throwable e){} ist schlechtester Stil
Grundlagen Programmierung
Stephan Kleuker
489
Klassenvariablen und
Klassenmethoden
Grundlagen Programmierung
Stephan Kleuker
490
Objekte und Klassen
• Bisher: Wir Programmieren das Verhalten von Objekten
• Objekte können über Objektmethoden
– verändert werden
– Ergebnisse, d.h. neue Objekte, berechnen
• Klassen beschreiben nur Objekte und erlauben über
Konstruktoren die Erstellung beliebig vieler Objekte
• außer Konstruktoren bieten Klassen selbst bisher nichts an
• bisher nur recht aufwändig machbar: Vergabe eindeutiger
Matrikelnummern
• "letzte vergebene Matrikelnummer" ist keine ObjektEigenschaft, sondern Eigenschaft der Klasse
Grundlagen Programmierung
Stephan Kleuker
491
Klassenvariablen
• Klassenvariable ist Eigenschaft einer Klasse, z. B. ein Zähler
wieviele Objekte existieren, Schlüsselwort static
private static Integer letzteNummer;
• Klassenvariablen gehören zur Klasse und können damit
ohne Objekte existieren
• Klassenvariablen können in Objektmethoden genutzt
werden
• d. h. Objektvariablen kann der Wert von Klassenvariablen
zugeordnet werden
• einer Klassenvariable kann nicht ein zu einer
Objektvariablen gehöriges Objekt zugewiesen werden (da
Objekte gelöscht werden können)
Grundlagen Programmierung
Stephan Kleuker
492
Klassenmethoden
• Klassenmethoden sind Methoden, die nur zur Klasse
gehören und auch ohne Objekte ausgeführt werden können
• In Klassenmethoden kann auf Klassenvariablen lesend und
schreibend, andere Klassenmethoden und Parameter (auch
Objekte) zugegriffen werden
• Um deutlich zu machen, dass eine Klassenmethode
aufgerufen wird, kann der Name der Klasse vor dem
Methodennamen mit einem Punkt getrennt stehen
<Klassenname>.<Klassenmethodenname>()
• gleiche Schreibweise auch bei Klassenvariable möglich
• wird Klassenmethode in anderer Klasse oder Objekt einer
anderen Klasse genutzt, muss diese Schreibweise genutzt
werden
Grundlagen Programmierung
Stephan Kleuker
493
Nutzung von Klassenvariablen und -methoden (1/2)
public class Student{
private static Integer letzteNummer = 99999;
protected String vorname ="Eva";
protected String nachname ="Mustermann";
...
public Student(){
Student.letzteNummer = Student.letzteNummer+1
this.matrikelnummer = Student.letzteNummer;
}
;
public static Integer leseLetzteNummer(){
return Student.letzteNummer;
}
public static void schreibeLetzteNummer(Integer m){
Student.letzteNummer = m;
}
Grundlagen Programmierung
Stephan Kleuker
494
Nutzung von Klassenvariablen und -methoden (2/2)
@SuppressWarnings("unchecked")
public void datenLaden(String datei) {
EinUndAusgabe io = new EinUndAusgabe();
XMLDecoder file = null;
try {
file = new XMLDecoder( new BufferedInputStream(
new FileInputStream(datei)));
this.semester = (String) file.readObject();
this.studenten = (ArrayList<Student>) file.readObject();
for(Student s: this.studenten){
if(s.getMatrikelnummer()>Student.leseLetzteNummer()){
Student.schreibeLetzteNummer(s.getMatrikelnummer());
}
}
io.ausgeben("Daten geladen.\n");
} catch (FileNotFoundException e) {
...
Grundlagen Programmierung
Stephan Kleuker
495
Beispiel: Ausgabe nächster Matrikelnummer
// in Studentenverwaltung
+ "(13) n\u00e4chste Matrikelnummer: ");
case 13: {
naechsteMatrikelnummer();
break;
}
public void naechsteMatrikelnummer(){
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben(" n\u00e4chste: "+Student.naechste());
}
// in Student
public static Integer naechste(){
return Student.letzteNummer+1;
}
Grundlagen Programmierung
Stephan Kleuker
496
Nutzung einer Klassenmethode ohne Objekt
Grundlagen Programmierung
Stephan Kleuker
497
Analysebeispiel Vererbung (1/4)
public class K1{
protected Integer objv;
protected static Integer klav = 0;
public K1(){
this.objv = K1.klav;
K1.klav = K1.klav+1;
}
public static Integer klav(){
return K1.klav;
}
@Override
public String toString(){
return"K1: "+this.objv;
}
}Grundlagen Programmierung
Stephan Kleuker
498
Analysebeispiel Vererbung (2/4)
public class KSpielerei{
}
public void analyse1(){
K1[] ka = {new K1(), new K1(), new K1()};
for(K1 k:ka){
System.out.println(k);
}
K1: 0
System.out.println(K1.klav());
K1: 1
}
K1: 2
3
Grundlagen Programmierung
Stephan Kleuker
499
Analysebeispiel Vererbung (3/4)
public class K2 extends K1{
public K2(){
super();
klav = klav+1; // besser K1.klav schreiben
}
//darf kein @Override stehen
public static Integer klav(){
return K2.klav; // schlechtester erlaubter Stil
}
@Override
public String toString(){
return"K2: "+super.objv;
}
}
Grundlagen Programmierung
Stephan Kleuker
500
Analysebeispiel Vererbung (4/4)
• in KSpielerei
public void analyse2(){
K1[] ka = {new K2(), new K1(), new K2()};
for(K1 k:ka){
System.out.println(k);
K2: 0
}
K1: 2
System.out.println(K1.klav());
K2: 3
System.out.println(K2.klav());
5
}
5
Grundlagen Programmierung
Stephan Kleuker
501
Anmerkung zu Sichtbarkeiten
• Grundsätzlich sind Klassenvariablen auch private oder
protected, Klassenmethoden public (oder auch private oder
proteced)
• theoretisch kann man Objektvariablen und Klassenvariablen
auch public machen, so dass man direkt über die
Punktnotation darauf zugreifen kann
• zentrale Coding-Guideline: NIEMALS Objektvariablen und
maximal nur konstante Klassenvariablen public machen
• Java wird seit 1991 entwickelt, wenige historisch unsaubere
Stellen, für Kompatibilität drin gelassen
• public Objektvariable bei Array a: a.length
• public Klassenvariable in System: System.out
Grundlagen Programmierung
Stephan Kleuker
502
Wann sind Klassenmethoden sinnvoll?
• Klassenmethoden werden dann eingesetzt, wenn
ausschließlich Klassenvariablen und andere
Klassenmethoden betroffen sind
• Klassenmethoden sind typischerweise Hilfsmethoden, die
mit dem Konzept der Objektorientierung unmittelbar wenig
zu tun haben
• Grundsätzlich muss ein Entwickler in Objekten und ihrer
Bearbeitung mit Objektmethoden denken
• Erst wenn man feststellt, dass keine Objekte benötigt
werden, kann man über die Erstellung von
Klassenmethoden nachdenken
• typisches Beispiel für Klasse mit ausschließlich
Klassenmethoden ist java.lang.Math
Grundlagen Programmierung
Stephan Kleuker
503
Ausschnitt der Klassenmethoden von Math
Modifier and Type Method and Description
static double
abs(double a) Returns the absolute value of a double value.
static double
cos(double a) Returns the trigonometric cosine of an angle.
exp(double a) Returns Euler's number e raised to the power of
static double
a double value.
log(double a) Returns the natural logarithm (base e) of a
static double
double value.
pow(double a, double b) Returns the value of the first
static double
argument raised to the power of the second argument.
random() Returns a double value with a positive sign, greater
static double
than or equal to 0.0 and less than 1.0.
round(double a) Returns the closest long to the argument, with
static long
ties rounding up.
sqrt(double a) Returns the correctly rounded positive square
static double
root of a double value.
static double
tan(double a) Returns the trigonometric tangent of an angle.
Quelle: http://docs.oracle.com/javase/7/docs/api/index.html?overview-summary.html
Grundlagen Programmierung
Stephan Kleuker
504
Definition von Konstanten
•
•
•
•
Konstanten sinnvoll in Klassenvariablen abgelegt
diese Variablen sind dann public
damit unveränderbar, wird Schlüsselwort final ergänzt
damit Konstanten schnell erkennbar, werden sie
ausschließlich in Großbuchstagen geschrieben
• Beispiele in Math:
Grundlagen Programmierung
Stephan Kleuker
505
Beispiel: Nutzung der Math-Klassenmethoden
public class MathAnalyse{
public void analyse(){
System.out.println(Math.PI);
System.out.println(Math.E);
// Math.PI = 42.0; wg. final nicht ok
System.out.println(Math.random());
System.out.println(Math.pow(10,Math.pow(10,10)));
System.out.println(Math.round(-0.5));
System.out.println(Math.round(0.5));
System.out.println(Math.sqrt(256.));
System.out.println(Math.log(Math.exp(42)));
}
3.141592653589793
}
2.718281828459045
0.7704010465910343
Infinity
0
1
16.0
42.0
Grundlagen Programmierung
Stephan Kleuker
506
Beispiel: Nutzung von Konstanten (1/3)
• Auslagerung der Konstanten in eine neue Klasse (hier ggfls.
auch Hilfsmethoden)
public class Firma{
public static final String NAME = "Abmahnwahn KO";
public static final Double ZINS = 1.30;
public static final Integer FRIST = 7;
}
public class Post{
public static void oeffnungsbrief(Schuldner s){
System.out.println("Ey "+s.getName()+",\n"
+"Du hast "+s.getKohle()+" bei "+Firma.NAME
+" geliehen.\nRück "+s.getKohle()*Firma.ZINS
+" bis in "+Firma.FRIST+" Tagen raus,\n"
+"sonst Stress.\n\tMfG ein Freund");
}
}
Grundlagen Programmierung
Stephan Kleuker
507
Beispiel: Nutzung von Konstanten (2/3)
public class Schuldner{
private String name;
private Double kohle;
public Schuldner(String n, Double k){
this.name = n;
this.kohle = k;
}
public String getName(){
return this.name;
}
public Double getKohle(){
return this.kohle;
}
}
Grundlagen Programmierung
Stephan Kleuker
508
Beispiel: Nutzung von Konstanten (3/3)
Ey Donald,
Du hast 100.0 bei Abmahnwahn KO
geliehen.
Rück 130.0 bis in 7 Tagen raus,
sonst Stress.
MfG ein Freund
Grundlagen Programmierung
Stephan Kleuker
509
Analyse des Ansatzes
• Recht einfache Änderung z. B. des Firmennamens, da nur
eine Datei angepasst werden muss
• Nachteil bleibt, dass Programm verändert wird und deshalb
neu übersetzt werden muss
• Flexiblerer Ansatz, wenn Firmendaten nur in einer mit
normalen Editor änderbaren Datei stehen
• Ansatz: Konstanten werden durch Klassenmethoden
geliefert, bei erster Nutzung sollen die Werte aus einer
Datei eingelesen werden
Grundlagen Programmierung
Stephan Kleuker
510
Optimierter Umgang mit Konstanten (1/6)
public class Post{
public static void oeffnungsbrief(Schuldner s){
System.out.println("Ey "+s.getName()+",\n"
+ "Du hast "+s.getKohle()+" bei "+Firma.name()
+ " geliehen.\nRück "+s.getKohle()*Firma.zins()
+ " bis in "+Firma.frist()+" Tagen raus,\n"
+ "sonst Stress.\n\tMfG ein Freund");
}
}
Grundlagen Programmierung
Stephan Kleuker
511
Optimierter Umgang mit Konstanten (2/6)
import
import
import
import
import
import
import
java.beans.XMLDecoder;
java.io.BufferedInputStream;
java.io.FileInputStream;
java.io.FileNotFoundException;
java.beans.XMLEncoder;
java.io.BufferedOutputStream;
java.io.FileOutputStream;
public class Firma{
public static String NAME;
public static Double ZINS;
public static Integer FRIST;
public static Boolean gelesen = false;
public static final String DATEI ="config.xml";
Grundlagen Programmierung
Stephan Kleuker
512
Optimierter Umgang mit Konstanten (3/6)
public static String name(){
Firma.lesen();
return Firma.NAME;
}
public static Double zins(){
Firma.lesen();
return Firma.ZINS;
}
public static Integer frist(){
Firma.lesen();
return Firma.FRIST;
}
Grundlagen Programmierung
Stephan Kleuker
513
Optimierter Umgang mit Konstanten (4/6)
public static void schreiben(){
EinUndAusgabe io = new EinUndAusgabe();
XMLEncoder file = null;
try {
file = new XMLEncoder( new BufferedOutputStream(
new FileOutputStream(Firma.DATEI)));
System.out.print("Name: ");
file.writeObject(io.leseString());
System.out.print("Zins: ");
file.writeObject(io.leseDouble()/100+1);
System.out.print("Frist: ");
file.writeObject(io.leseInteger());
Firma.gelesen = false;
} catch (FileNotFoundException e) { // unsauber
} finally {
if(file!=null){
file.close();
}
Grundlagen
Stephan Kleuker
} Programmierung
}
514
Optimierter Umgang mit Konstanten (5/6)
public static void lesen(){
if(!Firma.gelesen){
XMLDecoder file = null;
try {
file = new XMLDecoder( new BufferedInputStream(
new FileInputStream(Firma.DATEI)));
Firma.NAME = (String) file.readObject();
Firma.ZINS = (Double) file.readObject();
Firma.FRIST = (Integer) file.readObject();
Firma.gelesen = true;
} catch (FileNotFoundException e) { // unsauber
} finally {
if(file!=null){
file.close();
}
}
}
} Programmierung
Grundlagen
Stephan Kleuker
}
515
Optimierter Umgang mit Konstanten (6/6)
Name: B. Trug
Zins: 35
Frist: 5
Ey Uta,
Du hast 10.0 bei B. Trug geliehen.
Rück 13.5 bis in 5 Tagen raus,
sonst Stress.
MfG ein Freund
Grundlagen Programmierung
Stephan Kleuker
516
Start von Java-Programmen
Grundlagen Programmierung
Stephan Kleuker
517
Bisher
• In BlueJ wurde Objekt erzeugt und dann Methode
ausgewählt
• alternativ könnte man jetzt direkt auf Klasse eine noch zu
schreibende Klassenmethode ausführen
• Ansatz weiter gedacht: Klasse heißt ausführbar, wenn sie
eine Methode mit folgender Signatur hat
public static void main(String[] arg){…
Grundlagen Programmierung
Stephan Kleuker
518
Nutzung einer Main-Klasse
• sinnvoll ist es, eigene Klasse Main zu ergänzen, die
ausschließlich zum Start des Programmes genutzt wird
• Erstellung notwendiger Objekte und Aufruf von Methoden,
damit Objekte "sich kennen"
• Start einer Hauptmethode
public class Main{
public static void main(String[] arg){
Studentenverwaltung s = new Studentenverwaltung();
s.steuern();
}
}
Grundlagen Programmierung
Stephan Kleuker
519
Aufruf von main in BlueJ
• Klassenmethode
auswählen
• Array kann direkt
eingegeben werden
(meist ohne Bedeutung,
dann leer lassen)
Grundlagen Programmierung
Stephan Kleuker
520
Vom Source Code zum ausführbaren Programm
Java Source
(Punkt.java)
Java Bytecode
(Punkt.class)
Java Compiler
(javac)
Just-in-time
Compiler
Java Virtual
Machine (java)
• Source Code wird vom Compiler in Bytecode übersetzt
• Bytecode wird von JVM ausgeführt (d.h. interpretiert)
• Ggf. werden über den JIT-Compiler bestimmte
Befehlssequenzen in nativen Code übersetzt
Grundlagen Programmierung
Stephan Kleuker
521
Kompilierung mit der Konsole - Ausgangssituation
Grundlagen Programmierung
Stephan Kleuker
522
Kompilierung mit der Konsole - Kompilieren
Grundlagen Programmierung
Stephan Kleuker
523
Kompilierung mit der Konsole - Ausführen
man erkennt,
dass die Shell
kein UTF-8
"spricht"
Grundlagen Programmierung
Stephan Kleuker
524
ausführbares Programm in BlueJ (1/4)
• Annahme: gibt
Klasse Main mit
main-Methode
• Packen des
Programms in eine
jar-Datei
(vergleichbar einer
zip-Datei mit einem
bestimmten Aufbau)
Grundlagen Programmierung
Stephan Kleuker
525
ausführbares Programm in BlueJ (2/4)
• Auswahl der Startklasse (könnte mehrere main geben)
Grundlagen Programmierung
Stephan Kleuker
526
ausführbares Programm in BlueJ (3/4)
• Speichern der jar-Datei
• jar-Datei unter jedem Betriebssystem nutzbar
Grundlagen Programmierung
Stephan Kleuker
527
ausführbares Programm in BlueJ (4/4)
• Kommando-Zeile (oder Batch-Datei)
• wenn graphisch (AWT oder Swing) und im Betriebssystem
konfiguriert, dann Start durch Doppelklick
Grundlagen Programmierung
Stephan Kleuker
528
Nutzung von Übergabeparametern (1/2)
public class MainAnalyse{
public static void main(String[] s){
if(s==null){
System.out.println("null");
} else {
if(s.length==0){
System.out.println("kein Parameter");
} else {
for(Integer i=0; i<s.length; i =i+1){
System.out.println(i+": "+s[i]);
}
}
}
}
}Grundlagen Programmierung
Stephan Kleuker
529
Nutzung von Übergabeparametern (2/2)
Grundlagen Programmierung
Stephan Kleuker
530
Entwicklungsumgebungen
Grundlagen Programmierung
Stephan Kleuker
531
Programmentwicklung in Java
• Grundsätzlich reicht ein beliebiger Texteditor zur
Programmerstellung, der Inhalt unformatiert speichert
• Klasse K muss in Datei K.java stehen
• java und javac benötigt
• Problem: viele projekteinheitlich zu lösende Aufgaben
müssen individuell geregelt werden
– welche Einrückungen
– woher kommen benötigte Klassen anderer
– wer kompiliert Gesamtprojekt
– wer erstellt wie die Dokumentation
– ………
Grundlagen Programmierung
Stephan Kleuker
532
Entwicklungsumgebung BlueJ
BlueJ übernimmt einige typische Aufgaben:
• Code-Formatierung (Einrückungen)
• Syntax-Highlighting von Schlüsselwörtern
• Einfaches Manövrieren in Klassen
• Unmittelbare Möglichkeit zur Ausführung
• Testklassendefinition und Testausführung (JUnit)
• Einfach Debug-Möglichkeiten
• aber, Entwicklungsumgebungen für Profis können
wesentlich mehr
• aber, nur BlueJ kann direkt mit Objekten kommunizieren
• Fazit: BlueJ sehr gut zum Lernen geeignet, da man
gezwungen wird, alles selbst zu tippen; für größere Projekte
eher ungeeignet
Grundlagen Programmierung
Stephan Kleuker
533
Entwicklungsumgebung Eclipse
•
•
•
•
•
•
•
•
•
•
•
•
Editor mit Syntax-Highlighting und Formatierung
Anzeige aller Fehler
einfaches Starten von Programmen
einfaches Einbinden anderer Programme und Bibliotheken
einfaches Ausführen von JUnit-Tests
viele Möglichkeiten zur Code-Generierung: get-, set- Methoden,
Varianten von Konstruktoren, equals, hashCode, toString
Einbau umgebender try-catch-Blöcke
mächtige Code-Completion (<Strg>+<Space>)
einfache Nutzung eines sehr mächtigen Debuggers
schnelles Manövrieren zu nutzenden und genutzten Methoden
………
Achtung: man benötigt zunächst nur sehr wenige der vielen
Möglichkeiten, Schritt für Schritt vortasten
Grundlagen Programmierung
Stephan Kleuker
534
Beispiel: Studierendenverwaltung (1/4) - Eingabe
Grundlagen Programmierung
Stephan Kleuker
535
Beispiel: Studierendenverwaltung (2/4) - Ausführen
Grundlagen Programmierung
Stephan Kleuker
536
Beispiel: Studierendenverwaltung (3/4) - Debugging
Grundlagen Programmierung
Stephan Kleuker
537
Beispiel: Studierendenverwaltung (4/4) - Testen
Grundlagen Programmierung
Stephan Kleuker
538
Erweiterbarkeit von Eclipse
• Eclipse kann einfach durch Plug Ins erweitert werden
• viele verschiedene Programmiersprachen und Werkzeuge z.
B. zur Datenbankverwaltung möglich
• Vorwegwarnung: Jedes Plug In macht Eclipse langsamer
• Einige weitere Unterstützung bei der Programmierung
• statische Quellcode-Analyse
– detaillierte Prüfungen von Style-Guides (Einrückungen
bis magic Numbers)
– Bewertung der Komplexität von Programmen (Anzahl
der Verzeigungen)
• Messung von Testüberdeckungen (wird Anweisung oder
Zweig geprüft)
• ………
Grundlagen Programmierung
Stephan Kleuker
539
Beispiel: Eclemma für Testüberdeckung
Grundlagen Programmierung
Stephan Kleuker
540
Eclipse als IDE
• IDE = Integrated Development Environment
• Gesamter Entwicklungsprozess umfasst Phasen
– Anforderungsanalyse
– Design
– Programmierung
– Test
• eine IDE unterstützt mehrere dieser Phasen
• eine IDE unterstützt die Verwaltung der Ergebnisse
(Versionsmanagement)
• eine IDE unterstützt den Zusammenbau und die Installation
der Software (Build-Management)
• trotzdem bleibt IDE nur ein [zentraler] Teil der Entwicklung
Grundlagen Programmierung
Stephan Kleuker
541
Pakete
Grundlagen Programmierung
Stephan Kleuker
542
Idee von Paketen
• Große Mengen von Klassen oft sehr unübersichtlich
• Ähnlich zu Dateisystemen ist eine logische Ordnung in
verschiedenen Ordnern sinnvoll
• Ordner werden in Java Paket (package genannt)
• Paketzugehörigkeitsdeklaration steht immer am Anfang der
Klasse
package de.ossoft.gui;
public class Maske{
• Datei Maske.java muss im Unterordner de/ossoft/gui des
Projekts liegen
• Nutzung von Klassen aus anderen Paketen über import
import de.ossoft.gui.Maske;
Grundlagen Programmierung
Stephan Kleuker
543
Ausschnitt: Java-Pakete der Klassenbibliothek
java.util
Contains the collections framework, legacy collection classes,
event model, date and time facilities, internationalization, and
miscellaneous utility classes (a string tokenizer, a randomnumber generator, and a bit array).
java.util.
concurrent
Utility classes commonly useful in concurrent programming.
java.util.
A small toolkit of classes that support lock-free thread-safe
concurrent.atomic programming on single variables.
java.util.
concurrent.locks
java.util.jar
java.util.logging
Interfaces and classes providing a framework for locking and
waiting for conditions that is distinct from built-in
synchronization and monitors.
Provides classes for reading and writing the JAR (Java ARchive)
file format, which is based on the standard ZIP file format with
an optional manifest file.
Provides the classes and interfaces of the JavaTM 2 platform's
core logging facilities.
Grundlagen Programmierung
Stephan Kleuker
544
Pakete in BlueJ
• etwas aufwändig über das Menü
Grundlagen Programmierung
Stephan Kleuker
545
Klassen in Pakete verschieben (1/2)
• leider funktioniert hier kein Drag & Drop in BlueJ
Grundlagen Programmierung
Stephan Kleuker
546
Klassen in Pakete verschieben (2/5)
• Trick: Paketdeklaration direkt in Klasse eintragen
Grundlagen Programmierung
Stephan Kleuker
547
Klassen in Pakete verschieben (3/5)
• Frage bei "Compile" bestätigen mit "Move" bestätigen
Grundlagen Programmierung
Stephan Kleuker
548
Klassen in Pakete verschieben (4/5)
• Generell müssen Pakete erst angelegt werden, sonst
Grundlagen Programmierung
Stephan Kleuker
549
Klassen in Pakete verschieben (5/5)
• Später Paket (Ordner) mit Doppelklick öffnen
Grundlagen Programmierung
Stephan Kleuker
550
Beispiel: einfache Software-Architektur (1/3)
• bisher bei Studentenverwaltung alle
Klassen in einem (dem default-) Paket
eine typische Aufteilung:
• entity-Paket: alle zu verwaltenden
Datenklassen (typisch fast nur get- und
set- Methoden)
• control-Paket: Verwaltungsklassen, die
Sammlungen von Entity-Objekten
verwalten; Zugriff auf Entity-Objekte
nur über Control-Klassen
• boundary-Paket: externer Zugriff auf
Verwaltungsklassen, z. B.
Nutzungsoberfläche
Grundlagen Programmierung
Stephan Kleuker
551
Beispiel: einfache Software-Architektur (2/3)
entity
control (Zugriff auf entity-Objekte)
Grundlagen Programmierung
Stephan Kleuker
552
Beispiel: einfache Software-Architektur (3/3)
• boundary (Zugriff auf control-Objekte)
• fehlt: Aufteilung von Boundary und Control
Grundlagen Programmierung
Stephan Kleuker
553
Pakete und Imports
package boundary;
import control.Studentenverwaltung;
public class Studentendialog {
private Studentenverwaltung verwaltung
= new Studentenverwaltung();
package control;
import entity.Student;
import entity.Austauschstudent;
// weitere Imports
public class Studentenverwaltung {
private ArrayList<Student> studenten;
private String semester = "Semester XXXX";
Grundlagen Programmierung
Stephan Kleuker
554
Aufteilung in Boundary und Control-Funktionalität (1/2)
//alt in Studentenverwaltung
public void anzahlAustauschstudentenAusgeben() {
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("Es gibt "
+ anzahlAustauschstudenten()
+ " Austauschstudenten\n");
}
public Integer anzahlAustauschstudenten() {
Integer ergebnis = 0;
for (Student s : this.studenten) {
ergebnis = ergebnis + s.zaehlenAlsAustauschstudent();
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
555
Aufteilung in Boundary und Control-Funktionalität (2/2)
// neu: boundary (StudentenDialog)
public void anzahlAustauschstudentenAusgeben() {
EinUndAusgabe io = new EinUndAusgabe();
io.ausgeben("Es gibt "
+ verwaltung.anzahlAustauschstudenten()
+ " Austauschstudenten\n");
}
// neu: control (Studentenverwaltung)
public Integer anzahlAustauschstudenten() {
Integer ergebnis = 0;
for (Student s : this.studenten) {
ergebnis = ergebnis + s.zaehlenAlsAustauschstudent();
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
556
Aufteilung in Boundary und Control-Funktionalität (1/4)
//alt in Studentenverwaltung
public void studentSuchen() {
EinUndAusgabe io = new EinUndAusgabe();
Integer mat = zahlZwischen("Matrikelnummer"
, 99999, 1000000);
Student s = studentSuchen(mat);
if (s != null) {
io.ausgeben("Daten: " + s + "\n");
} else {
io.ausgeben("nicht gefunden\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
557
Aufteilung in Boundary und Control-Funktionalität (2/4)
//alt in Studentenverwaltung
public Student studentSuchen(Integer mat) {
Student ergebnis = null;
for (Student s : this.studenten) {
if (s.getMatrikelnummer().equals(mat)) {
ergebnis = s;
}
}
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
558
Aufteilung in Boundary und Control-Funktionalität (3/4)
// neu: boundary (StudentenDialog)
public void studentSuchen() {
EinUndAusgabe io = new EinUndAusgabe();
Integer mat = zahlZwischen("Matrikelnummer"
, 99999, 1000000);
String s = verwaltung.studentAusgeben(mat);
if (s != null) {
io.ausgeben("Daten: " + s + "\n");
} else {
io.ausgeben("nicht gefunden\n");
}
}
Grundlagen Programmierung
Stephan Kleuker
559
Aufteilung in Boundary und Control-Funktionalität (4/4)
// neu: control (Studentenverwaltung)
private Student studentSuchen(Integer mat) {
Student ergebnis = null;
for (Student s : this.studenten) {
if (s.getMatrikelnummer().equals(mat)) {
ergebnis = s;
}
}
return ergebnis;
}
public String studentAusgeben(Integer mat){
Student s=studentSuchen(mat);
if(s==null){
return null;
}
return s.toString();
} Programmierung
Grundlagen
Stephan Kleuker
560
alle Studieren in Control-Klasse
public ArrayList<String> studentenAusgeben() {
ArrayList<String> ergebnis = new ArrayList<String>();
for (Student s : this.studenten) {
ergebnis.add(s.toString());
}
return ergebnis;
}
• Beispiel zeigt deutlich, dass Boundary-Klassen keinen
direkten Zugriff auf Entity-Klassen erhalten
• (Anmerkung: Ansatz wird nicht immer so konsequent
eingehalten)
• Ansatz erlaubt leichte Erstellung einer grafischen Oberfläche
Grundlagen Programmierung
Stephan Kleuker
561
Ergänztes Main-Paket
package main;
import boundary.Studentendialog;
public class Main{
public static void main(
String[] arg){
Studentendialog s =
new Studentendialog();
s.steuern();
}
}
Grundlagen Programmierung
Stephan Kleuker
562
Kompilieren und Ausführen in der Konsole
Grundlagen Programmierung
Stephan Kleuker
563
Beispiel: Pakete und Compilieren
\home\blubb\a
package a;
import a.d.D;
import a.b.c.C;
public class A{
dies ist File
\home\blubb\a\A.java
\home\blubb\a\d
\home\blubb\a\b
package a.d;
import a.b.B;
public class D{
private B b=null;
}
package a.b;
public class B {…}
class Ghost {…}
\home\blubb\a\b\c
package a.b.c;
import a.d.D;
public class C {}
Grundlagen Programmierung
Compiliert wird im Verzeichnis
oberhalb von a (also in blubb) mit
javac a\A.java
Ausführung (auch in blubb)
java a.A
Stephan Kleuker
564
Nutzung von CLASSPATH
• Damit Java Verzeichnisse mit Paketen findet, sollte die
Umgebungsvariable CLASSPATH gesetzt werden
• Diese Variable enthält die Start-Verzeichnisse, in denen bei
einem Aufruf nach Klassen oder Paketen gesucht wird
• Beim Aufruf >java C durchsucht das Laufzeitsystem
sämtliche in CLASSPATH angegebenen Verzeichnisse nach
C.class und führt diese aus
• Beim Aufruf >java a.b.c.C sucht das Laufzeitsystem
C.class in den Unterverzeichnissen a\b\c von
Verzeichnissen aus CLASSPATH
• Voreingestellt ist meist CLASSPATH=. (oder nichts), in
Eclipse zusätzlich das Projektverzeichnis
Grundlagen Programmierung
Stephan Kleuker
565
Beispiel: Paketnutzung (1/2)
package verwaltung.resourcen;
import
import
import
import
import
java.text.DateFormat;
java.text.ParseException;
java.text.SimpleDateFormat;
java.util.Date;
java.util.Locale;
public class Person {
private Date geburt;
private String name;
private Locale loc;
public Person(String geburt, String name)
throws ParseException{
DateFormat df = new SimpleDateFormat("dd.MM.yyyy");
this.geburt = df.parse(geburt);
this.name = name;
}
Benutzeroberflächen und
Software-Ergonomie
Stephan Kleuker
566
Beispiel: Paketnutzung (2/2)
public Person(String name){
this.geburt = new Date();
this.name=name;
}
public void setLoc(Locale loc){ this.loc=loc;}
@Override public String toString(){
return name+": "+DateFormat.getDateInstance(
DateFormat.LONG, loc).format(geburt);
}
}
public static void main(String[] s) throws ParseException{
Person[] pers={new Person("31.2.2000","Ute"),
new Person("Mischa")};
Locale[] loc={Locale.GERMAN, Locale.US, Locale.ITALIAN};
for(Person p:pers){
Ute: 2. März 2000
for(Locale l:loc){
Ute: March 2, 2000
p.setLoc(l);
Ute: 2 marzo 2000
System.out.println(p);
Mischa: 6. Februar 2012
}
}
Mischa: February 6, 2012
Benutzeroberflächen und
Stephan Kleuker
567
} Software-Ergonomie
Mischa: 6 febbraio 2012
Einige Realitätsbeichten
Grundlagen Programmierung
Stephan Kleuker
568
Bisher
• Konsequente Orientierung an Objektorientierung
• folgende Vokabeln auf alle objektorientierten Sprachen
übertragbar: Klasse, Objekt, Objektvariable,
Objektmethode, Sichtbarkeit, abstrakte Klasse,
Klassenvariable, Klassenmethode, Paket
• konsequente Orientierung an Klassen, deshalb Nutzung von
Integer, Double, Boolean
• Integer x=42; x ist echtes Objekt mit Methoden
• Objekte der oben genannten Klassen (auch String) sind
Konstanten, d. h. es können mit Methoden ihre Inhalte nicht
verändert werden (gibt keine set-Methoden)
Grundlagen Programmierung
Stephan Kleuker
569
Java ist nicht konsequent objektorientiert
• gleiches gilt für C++ und C#
Hintergrund
• C++ zunächst nur als Erweiterung von C konzipiert
• Kompromiss, es sollten alle C-Programme weiter laufen
• Resultat, C hatte einfache Datentypen, die keine Klassen sind
und diese wurden nach C++ übernommen
• Resultat, die durchgehende sehr saubere Idee der
Objektorientierung wird mit Füßen getreten, es entsteht ein
Mixed-Stil
• Java sollte auch für C++-Entwickler schnell nutzbar sein,
deshalb einfache, nicht objektorientierte Typen übernommen
Hinweis: gibt echte objektorientierte Sprachen: Smalltalk (seit
1970er), Ruby
Grundlagen Programmierung
Stephan Kleuker
570
primitive Datentypen
Typ
repräsentiert
boolean
true or false
char
Unicode-Zeichen
byte
ganze Zahl mit Vorzeichen
Größe
1 bit
16 bits
8 bits
short
- ´´ -
16 bits
int
- ´´ -
32 bits
long
- ´´ -
64 bits
float
IEEE 754-Fließkommazahl
double
void
Prof. Dr. Stephan Kleuker
32 bits
- ´´ -
64 bits
-
Stephan Kleuker
571
Beispielnutzung
public class Analyse{
}
public static void schleife(){
double[] arr = {0.2, 3., 7e300, 42.42};
for(int i=0; i<4; i=i+1){
System.out.println(i+" :"+ (arr[i]*i));
}
0 :0.0
}
1 :3.0
2 :1.4E301
3 :127.26
Grundlagen Programmierung
Stephan Kleuker
572
Einfache Typen vor Java 5
• einfache Typen nicht in Sammlungen nutzbar
• vor Java 5: Werte von Hand umwandeln (casten)
public static void sammlung(){
ArrayList<Integer> al = new ArrayList<Integer>();
int x = 42;
Integer xo = new Integer(x);
al.add(xo);
int y = (int)al.get(0);
42
System.out.println(y);
}
Grundlagen Programmierung
Stephan Kleuker
573
Ab Java 5: Autoboxing
• Kompiler wandelt bei Bedarf von int nach Integer und
Integer nach int um
• eher workaround, nicht wirklich sauber und auch langsam
Integer x = 42;
int y = x;
Integer z = y;
• einfache Typen können keine null-Werte annehmen
• fieser Laufzeitfehler:
Integer n = null;
int m = n;
Grundlagen Programmierung
Stephan Kleuker
574
Beispiel: Autoboxing
public static void boxen(){
ArrayList<Integer> al = new ArrayList<Integer>();
Integer x = new Integer(99999);
al.add(42); // int nach Integer
al.add(42+1);
al.add(x);
al.add(x+1); // Integer nach int, int nach Integer
al.add(al.get(3)-1);
for(int i:al){
System.out.print(i+" ");
}
boolean identisch = (al.get(2)==al.get(4));
System.out.println("\n identisch: "+ identisch);
System.out.println(" gleich: "+ al.get(2).equals(al.get(4)));
}
42 43 99999 100000 99999
identisch: false
gleich: true
Grundlagen Programmierung
Stephan Kleuker
575
Zahlenbereiche und Genauigkeiten: int
• einfache Datentypen und zugehörige Klassen können nur
endlich viele Werte annehmen
public static void intgenau(){
Integer max = Integer.MAX_VALUE;
for(int i=0; i<3; i=i+1){
System.out.println(max+i);
}
Integer min = Integer.MIN_VALUE;
for(int i=0; i<3; i=i+1){
System.out.println(min-i);
}
}
Grundlagen Programmierung
Stephan Kleuker
2147483647
-2147483648
-2147483647
-2147483648
2147483647
2147483646
576
Zahlenbereiche und Genauigkeiten: double (1/3)
• sehr großer Zahlenbereich, Zahlen wie 1E12 ist 1*1012
• nicht jede Zahl darstellbar
• bekannte besondere Werte Infinity, -Infinity, NaN
public static void doubleGenau(){
Double max = Double.MAX_VALUE;
for(double i=250; i<=300; i=i+10){
System.out.print(Math.pow(10,i)+" ");
System.out.println(max+Math.pow(10,i));
}
}
1.0E250 1.7976931348623157E308
9.999999999999999E259 1.7976931348623157E308
1.0E270 1.7976931348623157E308
1.0E280 1.7976931348623157E308
1.0E290 1.7976931348623157E308
1.0E300
Infinity
Grundlagen Programmierung
Stephan Kleuker
577
Zahlenbereiche und Genauigkeiten: double (2/3)
public static void doublegenau2(){
Double winz = Double.MIN_NORMAL;
System.out.println(winz);
for(double i=10; i<=16; i=i+1){
System.out.println(Math.pow(10,-i)+": "+winz*Math.pow(10,-i));
}
System.out.println(winz/0);
System.out.println(0./0); 2.2250738585072014E-308
}
1.0E-10: 2.225074E-318
1.0000000000000001E-11: 2.22507E-319
1.0E-12: 2.2253E-320
1.0E-13: 2.223E-321
1.0E-14: 2.2E-322
1.0E-15: 2.5E-323
1.0E-16: 0.0
Infinity
NaN
Grundlagen Programmierung
Stephan Kleuker
578
Zahlenbereiche und Genauigkeiten: double (3/3)
public static void verschwindendeMillionen(){
Double konto = 0.0;
Double abziehen = 1E6;
konto = konto + 1E20 -abziehen - 1E20;
System.out.println(konto);
konto = 0.0;
konto = konto + 1E21 -abziehen - 1E21;
System.out.println(konto);
konto = 0.0;
konto = konto + 1E22 -abziehen - 1E22;
System.out.println(konto);
}
-999424.0
-1048576.0
0.0
Grundlagen Programmierung
Stephan Kleuker
579
Bearbeitung von Geldsummen
• Beispiele zeigen: kein Double für Geldsummen
• Beispiele zeigen: Integer (Long) eventuell zu klein
• Ansatz: Schreibe eigene Klasse Geld
• naiv: basierend auf Strings: "1234" + "567" = "1801"
• alternativ ArrayList<Integer> mit den einzelnen Ziffern der
Zahlen
• Java bietet Klassen BigInteger und BigDecimal an
• natürlich sehr viel langsamer als einfache Typen
Grundlagen Programmierung
Stephan Kleuker
580
Beispielnutzung von BigInteger
import java.math.BigInteger;
// …
public static void big(){
BigInteger b = new BigInteger("12345");
for(int i=0; i<4; i=i+1){
b = b.multiply(b);
System.out.println(b);
}
}
152399025
23225462820950625
539422123247359763587428687890625
290976227048689786699404610508159269970874403200651318511962890625
Grundlagen Programmierung
Stephan Kleuker
581
Inkrement- und Dekrementoperatoren
Operator
Bedeutung
x++
ergibt x und erhöht x um 1
++x
ergibt x+1 und erhöht x um 1
x--
ergibt x und verringert x um 1
--x
ergibt x-1 und verringert x um 1
Prof. Dr. Stephan Kleuker
Stephan Kleuker
582
Beispiele für Operatorennutzung
public class IncTest {
public static void main(String args[]){
int i = 1;
System.out.println(“i: “+ i);
i: 1
System.out.println(“++i: “+ ++i);
++i:
System.out.println(“i++: “+ i++);
i++:
System.out.println(“i: “+ i);
i: 3
System.out.println(“--i: “+ --i);
--i:
System.out.println(“i--: “+ i--);
i--:
System.out.println(“i: “+ i);
i: 1
}
2
2
2
2
}
Prof. Dr. Stephan Kleuker
Stephan Kleuker
583
Typkonvertierungen (elementare Typen)
Generell: Variablen von Typ x dürfen nur Elemente dieses Typs
zugewiesen werden
Bei Datentypen findet automatisch eine Konvertierung in
größeren Typen statt (niemals automatisch in Gegenrichtung)
byte short int long float double
char
• Umwandlung in die andere Richtung mit Casten (Typ in
Klammern)
int x=
double
double
// int
int z3
4;
y= 2;
z1= x/y;
z2= x/y; gibt Fehler
= (int) (x/y);
Prof. Dr. Stephan Kleuker
Stephan Kleuker
584
Logische Operatoren
Operator
Bedeutung
&
Und mit vollständiger Auswertung
|
Oder mit vollständiger Auswertung
^
wahr, wenn Operanden unterschiedlich sind
!
Negation
&&
Und mit Kurzschlussauswertung
||
Oder mit Kurzschlussauswertung
Prof. Dr. Stephan Kleuker
Stephan Kleuker
585
Beispielauswertung logischer Operatoren (1/2)
public static boolean effekt(String s){
System.out.println("Aha "+s);
return true;
}
public static void seiteneffekt(){
boolean wahr = true;
boolean falsch = false;
if(wahr || effekt("A")){
}
if(wahr | effekt("B")){
}
if(false && effekt("C")){
}
if(false & effekt("D")){
}
}
Grundlagen Programmierung
Stephan Kleuker
Aha B
Aha D
586
Beispielauswertung logischer Operatoren (2/2)
public static void seiteneffekt2(){
if(effekt("E") ^ effekt("F")){
System.out.println("Hoho");
}
if(effekt("G") ^ !effekt("H")){
System.out.println("Haha");
}
if(!effekt("I") ^ effekt("J")){
System.out.println("Huhu");
}
if(!effekt("K") ^ !effekt("L")){
System.out.println("Hihi");
}
}
Grundlagen Programmierung
Stephan Kleuker
Aha E
Aha F
Aha G
Aha H
Haha
Aha I
Aha J
Huhu
Aha K
Aha L
587
Code-Formatierungen
• bisherige Code-Formatierungen können so beibehalten
werden, da sie Lesbarkeit garantieren
• Möglichkeit: Weglassen von this und super
• Möglichkeit: Weglassen geschweifter Klammern, wenn nur
ein Befehl folgt
• Möglichkeit: Direkter Zugriff auf Objektvariablen, wenn
Objekte gleicher Klassen betrachtet werden
• Anmerkung: Viele Coding-Guidelines in Unternehmen
verbieten zumindest die ersten beiden Möglichkeiten
• Rat: Wenn Sie bisherige Regeln anwenden, ändern Sie Ihren
Stil nicht !!!
Grundlagen Programmierung
Stephan Kleuker
588
Beispiel: Klasse Punkt im Minimalstil (1/2)
public class Punkt {
private int x;
private int y;
public Punkt (int xWert, int yWert){
x = xWert;
y = yWert;
}
public boolean istNullpunkt(){
if (x==0 && y==0)
return true;
else
return false;
}
Grundlagen Programmierung
Stephan Kleuker
589
Beispiel: Klasse Punkt im Minimalstil (2/2)
public boolean equals(Object o){
if (o==null || !(o instanceof Punkt))
return false;
Punkt p = (Punkt) o;
if (x==p.x && y==p.y)
return true;
else
return false;
}
}
Grundlagen Programmierung
Stephan Kleuker
590
Programmieren ohne echte
Klassen
Grundlagen Programmierung
Stephan Kleuker
591
Braucht man Objektorientierung?
• Ja, da so eine wesentliche Möglichkeit zur Strukturierung
von Programmen geschaffen wird
• Objekte sollen Ihre Aufgaben selbst erledigen, keine
Hauptklasse, die alles über get- und set-Methoden steuert
• Nein, da frühere Programmiersprachen (z. B. Fortran, Cobol,
PL/1) keine Objektorientierung haben
• da gab es aber massive Probleme mit großen Programmen
• Nein, da für hardware-nahe Systeme oft keine objektorientierten Sprachen zur Verfügung stehen (aber C)
Grundlagen Programmierung
Stephan Kleuker
592
Programme ohne Objektorientierung
• Anschaulich stehen nur Klassenvariablen und
Klassenmethoden zur Verfügung
• Weiterhin gibt es Klassen (Strukturen), die zur Beschreibung
von Datenstrukturen genutzt werden (ähnlich zur
Objektorientierung, Erzeugung einer neuen Struktur mit
new)
public class Punkt{
public int x; // in OO nie erlaubt
public int y; // direkter Kündigungsgrund
}
Grundlagen Programmierung
Stephan Kleuker
593
Beispiel: Datenbearbeitung (1/3)
public class Punktbearbeitung{
public static Punkt neuerPunkt(int x, int y){
Punkt ergebnis = new Punkt();
ergebnis.x = x;
ergebnis.y = y;
return ergebnis;
}
public static Boolean gleich(Punkt p1, Punkt p2){
return (p1.x==p2.x && p1.y==p2.y);
}
Grundlagen Programmierung
Stephan Kleuker
594
Beispiel: Datenbearbeitung (2/3)
public static Boolean istNullpunkt(Punkt p){
return p.x==0 && p.y==0;
}
public static void verschieben(Punkt p, int dx, int dy){
p.x = p.x + dx;
p.y = p.y + dy;
}
public static void ausgeben(Punkt p){
System.out.print("["+p.x+","+p.y+"]");
}
}
Grundlagen Programmierung
Stephan Kleuker
595
Beispiel: Datenbearbeitung (3/3)
public class Main{
public static void punktanalyse(){
Punkt p1;
p1 = Punktbearbeitung.neuerPunkt(6,9);
Punktbearbeitung.ausgeben(p1);
System.out.println("\n"
[6,9]
+Punktbearbeitung.istNullpunkt(p1));
false
Punkt p2 = Punktbearbeitung.neuerPunkt(3,6);
[3,6]
Punktbearbeitung.ausgeben(p2);
false
System.out.println("\n"
true
+Punktbearbeitung.gleich(p1,p2));
false
Punktbearbeitung.verschieben(p2,3,3);
System.out.println(Punktbearbeitung.gleich(p1,p2));
System.out.println((p1==p2));
}
Grundlagen Programmierung
Stephan Kleuker
596
Neue Datenstruktur: Liste (1/5)
public class Punktliste{
public Punkt inhalt;
public Punktliste weiter=null;
//
//
//
//
//
ähnlich zu Punkt und Punktbearbeitung wäre auch
eine Aufteilung in Punktliste und
Punktlistenbearbeitung sinnvoll,
generell könnten auch alle Klassenmethoden
in einer Datei (Klasse) stehen.
public static Punktliste neuePunktliste(Punkt p){
Punktliste ergebnis = new Punktliste();
ergebnis.inhalt = p;
return ergebnis;
}
Grundlagen Programmierung
Stephan Kleuker
597
Neue Datenstruktur: Liste (2/5)
public static void ausgeben(Punktliste pl){
Punktliste tmp = pl;
System.out.print("[");
while(tmp != null){
Punktbearbeitung.ausgeben(tmp.inhalt);
tmp = tmp.weiter;
}
System.out.println("]");
}
Grundlagen Programmierung
Stephan Kleuker
598
Neue Datenstruktur: Liste (3/5)
public static Punktliste anhaengen(Punktliste pl, Punkt p){
Punktliste tmp = pl;
if(tmp == null){
return Punktliste.neuePunktliste(p);
}
while(tmp.weiter != null){
tmp = tmp.weiter;
}
tmp.weiter = Punktliste.neuePunktliste(p);
return pl;
}
}
Grundlagen Programmierung
Stephan Kleuker
599
Neue Datenstruktur: Liste (4/5)
// in Main
public static void listenanalyse(){
Punkt p1 = Punktbearbeitung.neuerPunkt(6,9);
Punkt p2 = Punktbearbeitung.neuerPunkt(3,6);
Punktliste pe = null;
Punktliste.ausgeben(pe);
pe = Punktliste.anhaengen(pe,p1);
Punktliste.ausgeben(pe);
// weiter nächste Folie
[]
[[6,9]]
Grundlagen Programmierung
Stephan Kleuker
600
Neue Datenstruktur: Liste (5/5)
pe = Punktliste.anhaengen(pe
,Punktbearbeitung.neuerPunkt(6,9));
pe = Punktliste.anhaengen(pe,p2);
Punktliste.ausgeben(pe);
pe = Punktliste.anhaengen(pe,p1);
Punktliste.ausgeben(pe);
p1.x = 9;
Punktliste.ausgeben(pe);
}
}
Grundlagen Programmierung
[[6,9][6,9][3,6]]
[[6,9][6,9][3,6][6,9]]
[[9,9][6,9][3,6][9,9]]
Stephan Kleuker
601
Laden und Speichern
Grundlagen Programmierung
Stephan Kleuker
602
Die Klasse File
• Objekt von File wird zur Abfrage von Informationen über
Dateien und Verzeichnisinhalte genutzt
• Die Klasse File enthält z. B. Methoden zum
– Auflisten von Dateien und Verzeichnissen
– Prüfen, ob eine Datei existiert/lesbar/sichtbar schreibbar
– Umbenennen / Löschen von Dateien bzw. Verzeichnissen
• Beispiel: Wir wollen mit einem File arbeiten, dessen relativer
Pfad unter Windows „ .\z\Hi.txt “ lautet
– 1. Möglichkeit:
File f= new File("./z/Hi.txt");
– man muss das Trennsymbol von Unix nutzen
– 2. Möglichkeit:
File f= new File(".\\z\\Hi.txt");
• Backslash (\) leitet in Java Sonderzeichen ein, deshalb \\
• 3. Möglichkeit: systemspezifischer Trenner in Klassenvariable
String tr= File.separator;
File f= new File("."+tr+"z"+tr+"Hi.txt");
Grundlagen Programmierung
Stephan Kleuker
603
Einige Methoden der Klasse File (ohne Parameter)
• boolean canRead() - testet, ob die Datei lesbar ist
• boolean canWrite() - testet, ob die Datei beschreibbar ist
• boolean delete() - löscht die Datei (bzw. das Verzeichnis)
• boolean exists() - testet, ob die Datei existiert
• boolean renameTo(File) - benennt die Datei um
• boolean mkdir() - erzeugt ein Verzeichnis
• boolean mkdirs() - erzeugt einen Verzeichnisbaum
• String[] list() - liefert Liste von Dateien des Verzeichnisses
• String getAbsolutePath(), String getPath() - liefert den
entsprechenden Pfad der durch File beschriebenen Datei zurück
• String getName() - gibt den Namen der Datei zurück
• boolean isFile(), boolean isDirectory() - Abfrage der Dateiart
Grundlagen Programmierung
Stephan Kleuker
604
Dateianalyse (1/6)
import java.io.File;
import java.io.IOException;
public class FileAnalyse{
public FileAnalyse(){
this.dialog();
}
public void datei(File datei){
if(datei.canRead()){
System.out.println("lesbar");
}
if(datei.canWrite()){
System.out.println("beschreibbbar");
}
if(datei.canExecute()){
System.out.println("ausfuehrbar");
}
}
Grundlagen Programmierung
Stephan Kleuker
605
Dateianalyse (2/6)
public void dialog(){
EinUndAusgabe io = new EinUndAusgabe();
String datei = "";
File file;
while(!datei.toLowerCase().equals("ende")){
System.out.print("zu untersuchende Datei: ");
datei = io.leseString();
file = new File(datei);
if (!file.exists()){
System.out.println("existiert nicht");
} else {
this.allgemein(file);
if(file.isDirectory()){
this.verzeichnis(file);
} else {
this.datei(file);
}
}
}
Grundlagen
Stephan Kleuker
} Programmierung
606
Dateianalyse (3/6)
public void allgemein(File datei){
try{
System.out.println(" Pfad: "+datei.getAbsolutePath()
+"\n Pfad: " + datei.getCanonicalPath()
+"\n Pfad: " + datei.getPath()
+"\n oben: " + datei.getParentFile()
+"\n versteckt: " + datei.isHidden()
+"\n veraendert: " + datei.lastModified()
+"\n Laenge: " + datei.length());
} catch (IOException e){
System.out.println("Fehler: "+e);
}
}
public void verzeichnis(File datei){
System.out.println("Enthaelt:");
for(String d: datei.list()){
System.out.println(" " + d);
}
Grundlagen
Stephan Kleuker
} Programmierung
}
607
Dateianalyse (4/6)
zu untersuchende Datei: .
Pfad: F:\workspaces\BlueJWork11\FileAnalyse\.
Pfad: F:\workspaces\BlueJWork11\FileAnalyse
Pfad: .
oben: null
versteckt: false
veraendert: 1324637498000
Laenge: 0
Enthaelt:
package.bluej
README.TXT
FileAnalyse.java
EinUndAusgabe.java
EinUndAusgabe.class
EinUndAusgabe.ctxt
FileAnalyse.class
FileAnalyse.ctxt
Grundlagen Programmierung
Stephan Kleuker
608
Dateianalyse (5/6)
zu untersuchende Datei: C:\bootmgr
Pfad: C:\bootmgr
Pfad: C:\bootmgr
Pfad: C:\bootmgr
oben: C:\
versteckt: true
veraendert: 1162461237049
Laenge: 438840
lesbar
ausfuehrbar
Grundlagen Programmierung
Stephan Kleuker
609
Dateianalyse (6/6)
zu untersuchende Datei:
F:\workspaces\BlueJWork11\FileAnalyse\FileAnalyse.java
Pfad: F:\workspaces\BlueJWork11\FileAnalyse\FileAnalyse.java
Pfad: F:\workspaces\BlueJWork11\FileAnalyse\FileAnalyse.java
Pfad: F:\workspaces\BlueJWork11\FileAnalyse\FileAnalyse.java
oben: F:\workspaces\BlueJWork11\FileAnalyse
versteckt: false
veraendert: 1324641712000
Laenge: 1851
lesbar
beschreibbbar
ausfuehrbar
Grundlagen Programmierung
Stephan Kleuker
610
Ein- und Ausgabe in Java
• Basisansatz: Lesen (Input) oder Schreiben (Output) einzelner
Bytes ( machbar, aber für Datentypen, die größer als Byte
sind, unhandlich)
Schreiben
Lesen
• Es handelt sich um Streams
• Streams sind immer unidirektional
• Das Paket java.io stellt verschiedene Klassen zur Verfügung,
die auf dem Streamkonzept basieren
• Hinweis: wir arbeiten hier hauptsächlich mit 8-Bit-Versionen
(gibt gleiche Klassen für Uni-Code, 16 Bit)
Grundlagen Programmierung
Stephan Kleuker
611
Einfaches Schreiben eines Files – Beispiel (1/2)
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Analyse {
public static void fileOutput()
throws FileNotFoundException, IOException{
FileOutputStream o = new FileOutputStream("xxx");
String s="Hello again";
for(int i=0; i<s.length(); i++){
o.write(s.charAt(i));
}
o.close();
}
}Grundlagen Programmierung
Stephan Kleuker
612
Einfaches Schreiben eines Files – Beispiel (2/2)
Grundlagen Programmierung
Stephan Kleuker
613
Einfaches Schreiben eines Files - Analyse
FileOutputStream o = new FileOutputStream("xxx");
String s="Hello again";
for(int i=0; i<s.length(); i++){
o.write(s.charAt(i));
}
o.close();
•
•
•
•
Im Konstruktor wird ein Filename (oder File) übergeben
Es kann nur Byte-Weise geschrieben werden
nur verschiedene einfache Varianten von write() verfügbar
Generell ist es wichtig, beim Arbeiten mit Files diese am
Ende zu schließen ( close() )
• es gibt verschiedene Konstruktoren, z.B.:
public FileOutputStream(String name, boolean append)
Grundlagen Programmierung
Stephan Kleuker
614
Einfaches Lesen eines Files
FileInputStream i= new FileInputStream("xxx");
int in = i.read();
while(in!=-1) {
System.out.print((char)in);
in=i.read();
}
i.close();
• Alle Bytes werden grundsätzlich als int eingelesen, müssen
bei Bedarf in byte oder char gewandelt werden
• Das File-Ende wird durch den Wert -1 erkannt
• Vorgestelltes Lesen und Schreiben ineffizient, da jede
Methode erneut auf das Betriebssystem zugreifen muss
Grundlagen Programmierung
Stephan Kleuker
615
Beispiel: Datei kopieren
// mehrere Imports weggelassen
public class Copy{
public static void main(String[] s) throws IOException{
FileInputStream in = new FileInputStream(s[0]);
FileOutputStream out= new FileOutputStream(s[1]);
int zeichen=0;
while(zeichen!=-1){
zeichen=in.read();
if (zeichen!=-1) {
out.write(zeichen);
}
}
in.close();
out.close();
}
}Grundlagen Programmierung
Stephan Kleuker
616
Schnellere Ein- und Ausgabe in Java
• einzulesende (bzw. auszugebende) Daten zwischenpuffern
und bei vollem Puffer verarbeiten
Ausgabe
Puffer
out(a) a
out(b)
a b
out(c)
a b c
out(d)
abc
d
Grundlagen Programmierung
Stephan Kleuker
617
Die Klasse BufferedOutputStream
• Daten werden in einen Puffer geschrieben, dessen Inhalt nur
dann in den Stream geschrieben wird, wenn er voll ist
BufferedOutputStream o = new BufferedOutputStream(
new FileOutputStream("xxa"),4);
String s="Hello again";
for(int i=0;i<s.length();i++) {
o.write(s.charAt(i));
}
o.close();
• BufferedOutputStream ermöglicht Daten zu schreiben, ohne
bei jeden Aufruf physikalisch auf das Gerät zuzugreifen
• explizites Leeren des Puffers mit flush()
Grundlagen Programmierung
Stephan Kleuker
618
Die Klasse BufferedInputStream
• Daten werden blockweise in einen Puffer gelesen, auf dem
bei jeder Leseaktion zugegriffen wird
BufferedInputStream i= new BufferedInputStream(
new FileInputStream("xxa"),4);
int in = i.read();
while(in!=-1){
System.out.print((char)in);
in=i.read();
}
• BufferedInputStream ermöglicht Daten zu lesen, ohne bei
jeden Aufruf physikalisch auf das Gerät zuzugreifen
• BufferedInputStream enthält die Methoden
• mark() zum markieren einer Position im Puffer
• reset() zur Zurückführung des Pufferzeigers auf die
letzte Markierung
Grundlagen Programmierung
Stephan Kleuker
619
Beispiel
public static void bufferedIO() throws IOException{
BufferedOutputStream o = new BufferedOutputStream(
new FileOutputStream("xxa"),4);
String s="Hello again";
for(int i=0;i<s.length();i++){
o.write(s.charAt(i));
}
BufferedInputStream i = new BufferedInputStream(
new FileInputStream("xxa"),4);
int in = i.read();
while(in!=-1){
Ausgabe:
System.out.print((char)in);
in=i.read();
Hello ag
}
i.close();
o.close();
}
am Ende aber:
Grundlagen Programmierung
Stephan Kleuker
620
mächtigeres Arbeiten mit Files
• Grundsätzlich kann man beliebige Speicher- und
Lesefunktionalitäten auf FileInputStream und
FileOutputStream aufbauen
• Da sich diese Entwicklung komplexer Speicher- und
Leseansätze sich häufig wiederholt, gibt es in der
Klassenbibliothek verschiedene mächtigere Klassen zur
Zusammenarbeit mit Files
• Ein Ansatz wäre, von den genannten Klassen zu erben und
die so zu erweitern
• Java-Ansatz ist Aggregation, die mächtigeren Klassen haben
ein Objekt der oben genannten Klasse als Objektvariable
und verwalten den Zugriff
Grundlagen Programmierung
Stephan Kleuker
621
Die Klasse DataOutputStream
• Mit Hilfe eines DataOutputStreams können einfache Datentypen
binär geschrieben werden
•
•
•
•
•
•
•
•
writeBoolean();
writeByte();
writeChar();
writeDouble();
writeFloat();
writeInt();
writeLong();
writeShort();
• Konstruktor erwartet einen Outputstream als Parameter
public DataOutputStream(OutputStream os);
• Analog existiert DataInputStream, mit zusätzlicher Methode
readLine() zum Einlesen eines Strings
Grundlagen Programmierung
Stephan Kleuker
622
Beipiel (1/2)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Punkt {
private int x;
private int y;
public Punkt(int a, int b) {this.x = a; this.y = b;}
public void speichern(DataOutputStream o)
throws IOException{
o.writeInt(this.x);
o.writeInt(this.y);
}
public static Punkt lesen(DataInputStream i)
throws IOException{
return new Punkt(i.readInt(),i.readInt());
}
Grundlagen Programmierung
Stephan Kleuker
623
Beispiel (2/2)
public String toString(){
return "X: "+this.x+" Y: "+this.y;
}
}
public static void main(String[] args)
throws IOException {
DataOutputStream o= new DataOutputStream(
new FileOutputStream("aab"));
Punkt p1= new Punkt(300,400);
Punkt p2= new Punkt(500,600);
p1.speichern(o);
p2.speichern(o);
o.close();
DataInputStream i= new DataInputStream(
new FileInputStream("aab"));
Punkt p3= Punkt.lesen(i);
Punkt p4= Punkt.lesen(i);
Ausgabe:
System.out.println(p3+"\n"+p4);
X: 300 Y: 400
i.close();
X: 500 Y: 600
}Grundlagen Programmierung
Stephan Kleuker
624
Ein- und Ausgabe von Objekten (1/2)
• Werden die Werte der Datenfelder eines Objektes in einen
Bytestrom überführt, der sich rekonstruieren lässt, so
spricht man von Objektserialisierung
• Java stellt dazu zwei Klassen zur Verfügung
ObjectOutputStream:
public writeObject(Object o) throws IOException
ObjectInputStream:
public final Object readObject() throws
OptionalDataException, ClassNotFoundException,
IOException
• Objekte werden beim Schreiben und Lesen rekursiv
abgearbeitet (d. h. immer alle Objektvariablen)
Grundlagen Programmierung
Stephan Kleuker
625
Ein- und Ausgabe von Objekten (2/2)
• Schnittstelle Serializable dient zur Kennzeichnung, dass ein
Objekt einer Klasse serialisierbar ist
• Schnittstelle selbst deklariert keine Methoden
• Klasse nur serialisierbar, wenn alle Objektvariablen serialisierbar
• bis auf einige graphische Klassen sind alle wichtigen Klassen der
Klassenbibliothek serialisierbar
• grundsätzlich ist "implements Serializable" immer gute Idee
• Objekt-Serialisierung:
– Vorteile: schnell, recht kompakte Daten
– Nachteile: mit neuen Klassenversionen nicht mehr nutzbar,
können von keinen anderen Programmen gelesen werden
Grundlagen Programmierung
Stephan Kleuker
626
Serialisierungsbeispiel (1/3)
import java.io.Serializable;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class Person implements Serializable{
private String name;
private String vorname;
private static final String DATEI = "text.txt";
private static final long serialVersionUID = 2L;
public Person (String n, String v){
this.name = n;
this.vorname = v;
}
@Override
public String toString(){
return this.vorname+" "+this.name;
} Programmierung
Grundlagen
Stephan Kleuker
627
Serialisierungsbeispiel (2/3)
public static void schreiben() throws IOException{
Person pers1 = new Person ("Maier", "Anja");
ObjectOutputStream out=
new ObjectOutputStream (new FileOutputStream(DATEI));
out.writeObject (pers1);
out.writeObject (new Person ("Schulz", "Oleg"));
out.writeObject ("Hallo");
out.close();
}
public static void lesen() throws IOException,
ClassNotFoundException{
ObjectInputStream in =
new ObjectInputStream (new FileInputStream (DATEI));
for(int i=0; i<3; i=i+1){
Object o = in.readObject(); // sonst casten
System.out.println(o);
}
in.close();
Grundlagen
Programmierung
Stephan Kleuker
628
}
Serialisierungsbeispiel (3/3)
public static void main(String[] s)throws IOException,
ClassNotFoundException{
Person.schreiben();
Person.lesen();
}
Grundlagen Programmierung
Stephan Kleuker
629
SerialVersionUID
• serialisierte Objekte typischerweise nur mit der gleichen
Klasse einlesbar, die auch zum Schreiben genutzt wurde
• Änderungen an Objektvariablen macht serialisierte Objekte
nicht nutzbar
• Lösung: Konverter schreiben
• Lösung: XMLEncoder und XMLDecoder nutzen
• woran erkennt neue Klasse, dass zu alte Objekte gelesen
werden soll?
– Nutzung eine speziellen vorgegebenen Klassenvariable
serialVersionUID
– Nummer wird mit serialisiert
– stimmt sie beim Laden nicht überein, gibt es
Fehlermeldung
Grundlagen Programmierung
Stephan Kleuker
630
serialVersionUID – Warning in Java
• typische Eclipse-Meldung
• Lösungsvorschläge in Eclipse (Linksklick)
• im ersten Fall beginnt Nummerierung mit 1 (1L für long)
• sonst zufällige Nummer
Grundlagen Programmierung
Stephan Kleuker
631
Beispielproblemfall
public class Person implements Serializable{
private String name;
private String vorname;
private static final String DATEI = "text.txt";
private static final long serialVersionUID = 1L;
• Person.schreiben()
• Änderung:
private static final long serialVersionUID = 2L;
• Person.lesen()
Grundlagen Programmierung
Stephan Kleuker
632
transient
Das Schlüsselwort transient:
Unterdrückung von Objektvariablen beim
Speichern
public class person implements Serializable{
private String name;
private String vorname;
private transient int alter;
....
}
Grundlagen Programmierung
Stephan Kleuker
633
Erinnerung: Uni-Code
• Java als Sprache des Internets nutzt Uni-Code
• Uni-Code ist echte Obermenge von ASCII und ISO 8859-1
(Latin 1)
• In Java gibt es 8-Bit-Klassen (etwas schneller, einfacher)
und 16-Bit-Klassen zum File-Handling (und Klassen, um 8Bit-Welt mit 16-Bit-Welt zu verknüpfen)
• In Java hat Byte-Stream und Character-Stream Klassen
Byte-Stream
Character-Stream
FileInputStream
FileReader
FileOutputStream
FileWriter
BufferedInputStram
BufferedReader
BufferedOutputStream
BufferedWriter
Grundlagen Programmierung
Stephan Kleuker
634
Klassenvariablen von System
public static final InputStream in
The "standard" input stream. This stream is already open and
ready to supply input data. Typically this stream corresponds
to keyboard input or another input source specified by the
host environment or user.
public static final PrintStream out
The "standard" output stream. This stream is already open
and ready to accept output data. Typically this stream
corresponds to display output or another output destination
specified by the host environment or user. See the println
methods in class PrintStream.
public static final PrintStream err
The "standard" error output stream. This stream is already
open and ready to accept output data.
Typically this stream corresponds to display output or another
output destination specified by the host environment or user.
Grundlagen Programmierung
Stephan Kleuker
635
Einlesen von der Tastatur
public class EinUndAusgabe {
public String leseString(){
String ergebnis;
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
try {
ergebnis=in.readLine();
} catch (IOException e) {
ergebnis="";
}
return ergebnis;
}
public int leseInt(){
int erg;
try {
erg=Integer.decode(leseString()).intValue();
} catch (NumberFormatException e) {
erg=-1;
}
return erg;
Grundlagen
Programmierung
Stephan Kleuker
}
636
Aufzählungen
Grundlagen Programmierung
Stephan Kleuker
637
Aufzählungen für Anfänger und Klassiker
public class Programmiererfahrung {
private String[] stufen={"nicht vorhanden",
"Grundkenntnisse","alte Projekterfahrung",
"Projektmitarbeiter", "Experte"};
private int stufenwert=0;
...
}
public class Erfahrung {
public final static int NICHT_VORHANDEN=0;
public final static int GRUNDKENNTNISSE=1;
public final static int ALTE_PROJEKTERFAHRUNG=2;
public final static int PROJEKTMITARBEITER=3;
public final static int EXPERTE=4;
}
Zugriff mit:
int meineErfahrung= Erfahrung.NICHT_VORHANDEN;
Grundlagen Programmierung
Stephan Kleuker
638
Aufzählungen mit Enum
• Enum ist spezielle Art von Klasse (kann damit Methoden
beinhalten)
• Werte als einfache Texte, beginnend mit Buchstaben
aufschreiben
public enum Erfahrung {
NICHT_VORHANDEN,
GRUNDKENNTNISSE,
ALTE_PROJEKTERFAHRUNG,
PROJEKTMITARBEITER,
EXPERTE
}
Grundlagen Programmierung
Stephan Kleuker
639
Aufzählungen mit Enum - Nutzung
public class Spielerei {
public static void main (String[] s){
Erfahrung ich= Erfahrung.NICHT_VORHANDEN;
System.out.println(ich);
for(Erfahrung e: Erfahrung.values()){
System.out.println(e);
}
NICHT_VORHANDEN
}
NICHT_VORHANDEN
}
GRUNDKENNTNISSE
ALTE_PROJEKTERFAHRUNG
PROJEKTMITARBEITER
EXPERTE
Grundlagen Programmierung
Stephan Kleuker
640
Weitere Methoden von enum-“Klassen“ (1/2)
Erfahrung ich= Erfahrung.NICHT_VORHANDEN;
System.out.println(ich.getClass());
System.out.println(ich.compareTo(Erfahrung.NICHT_VORHANDEN));
System.out.println(ich.compareTo(Erfahrung.EXPERTE));
System.out.println(ich.equals(0));
System.out.println(ich.equals(1));
System.out.println(ich.equals(Erfahrung.NICHT_VORHANDEN));
class Erfahrung
0
-4
false
false
true
Grundlagen Programmierung
Stephan Kleuker
641
Weitere Methoden von enum-“Klassen“ (2/2)
System.out.println(ich.getDeclaringClass());
System.out.println(ich.name());
System.out.println(ich.ordinal());
System.out.println(Erfahrung.valueOf("EXPERTE"));
try{
System.out.println(Erfahrung.valueOf("Experte"));
}catch (IllegalArgumentException e){
System.out.println(e);
}
System.out.println(Erfahrung.valueOf(Erfahrung.class,"EXPERTE"));
class Erfahrung
NICHT_VORHANDEN
0
EXPERTE
java.lang.IllegalArgumentException: No enum const Experte
EXPERTE
Grundlagen Programmierung
Stephan Kleuker
642
Objekte von enum-Klassen
• Mit enum werden besondere Klassen definiert, sind final
(keine Vererbung möglich), keinen von außen nutzbaren
Konstruktor
• Durch Erfahrung ich= Erfahrung.NICHT_VORHANDEN; erhält
man ein Objekt der Klasse Erfahrung
• D. h. Enum-Klassen können zusätzlich „normale“
Exemplarmethoden und Exemplarklassen enthalten (auch
z. B. toString())
• Klassenmethodenaufruf Erfahrung.klassenmethode();
• Methodenaufruf: ich.exemplarmethode();
Grundlagen Programmierung
Stephan Kleuker
643
Erweiterte Möglichkeiten mit enum (1/2)
• Aufzählungswerte können Parameter haben, die im
Konstruktor verarbeitet werden
public enum Coin {
PENNY(1),
NICKEL(5),
DIME(10),
QUARTER(25);
private final int value;
Coin(int value) {
this.value = value;
}
public int value() {
return value;
}
}
Grundlagen Programmierung
Stephan Kleuker
644
Erweiterte Möglichkeiten mit enum (2/2)
public class CoinAnalyse {
private enum CoinColor { COPPER, NICKEL, SILVER }
public static void main(String[] args) {
for (Coin c : Coin.values()){
System.out.println(c +":"+c.value()+"c "+color(c));
}
}
PENNY:1c COPPER
private static CoinColor color(Coin c) { NICKEL:5c NICKEL
DIME:10c SILVER
switch(c) {
case PENNY: return CoinColor.COPPER; QUARTER:25c SILVER
case NICKEL: return CoinColor.NICKEL;
case DIME:
case QUARTER: return CoinColor.SILVER;
default:
throw new AssertionError("Unknown coin: " + c);
}
}
}Grundlagen Programmierung
Stephan Kleuker
645
Kartenstapel (1/3)
public enum Farbe {
KARO, HERZ, KREUZ, PIK;
@Override
public String toString(){
switch(this){
case KARO: return("Karo");
case HERZ: return("Herz");
case KREUZ: return("Kreuz");
case PIK: return("Pik");
default: return("");
}
}
}
Prof. Dr. Stephan Kleuker
Stephan Kleuker
646
Kartenstapel (2/3)
public enum Wert {
SIEBEN("7"), ACHT("8"), NEUN("9"), ZEHN("10"),
BUBE("Bube"), DAME("Dame"), KOENIG("Koenig"), AS("As");
private String text;
Wert(String text){
this.text=text;
}
@Override
public String toString(){
return text;
}
}
Prof. Dr. Stephan Kleuker
Stephan Kleuker
647
Kartenstapel (3/3)
public class Karte {
private Farbe farbe;
private Wert wert;
...
public class Kartenstapel {
private ArrayList<Karte> stapel=new ArrayList<Karte>();
public static Kartenstapel gibAlleKarten(){
Kartenstapel k= new Kartenstapel();
for(Farbe f: Farbe.values())
for(Wert w: Wert.values())
k.add(new Karte(f,w));
return k;
}
//...
Prof. Dr. Stephan Kleuker
Stephan Kleuker
648
Frames, Knöpfe und
Ereignisbehandlung
Grundlagen Programmierung
Stephan Kleuker
649
AWT: Motivation
• (AWT: Abstract Windowing Toolkit).
• Einer der großen Vorteile von Java ist die PlattformUnabhängigkeit
• Java bietet SW für integrierte graphische
Benutzerschnittstelle, die auf allen Plattformen, auf denen
eine Java-VM implementiert ist, ohne jede Änderung
benutzt werden kann.
• Bei bisherigen Programmierumgebungen galt eine
eventuelle Plattform-Unabhängigkeit immer nur für das
Kernsystem, also für die Programmiersprache, nicht aber für
graphische Benutzerschnittstellen
Grundlagen Programmierung
Stephan Kleuker
650
Swing
• Zu 100% in Java programmiert
• AWT nutzt HW-Ressourcen, Swing unabhängig von HW,
Gleiches Look-And-Feel auf allen Plattformen
• Look-And-Feel kann vom Benutzer angepasst bzw. neu
durch Swing-Komponenten erstellt werden
• Vordefinierte Swing-Komponenten ermöglichen die
Verwendung der Stil-Familien wie „Java“, „X-Windows“ und
„Microsoft-Windows“
• Große Anzahl an graphischen Komponenten, die im
Aussehen und Verhalten geändert werden können
• vereinfachtes MVC-Entwurfsmuster benutzen
• Langsamer als das AWT, nicht Thread-save
• Eclipse nutzt eigene Bibliothek SWT
Grundlagen Programmierung
Stephan Kleuker
651
Ein erstes Fenster in Swing
import javax.swing.JFrame;
public class ErstesFenster extends JFrame{
public ErstesFenster(){
super("Ich habe einen Titel");
setSize(200,50);
setLocation(100,30);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new ErstesFenster();
}
}
Grundlagen Programmierung
Stephan Kleuker
652
Analyse des ersten Programms (1/3)
import javax.swing.JFrame;
public class ErstesFenster extends JFrame{
public ErstesFenster(){
super("Ich habe einen Titel");
...
}
...
• Swing-Klassen beginnen mit einem J (z.B. JButton, JLabel,
JApplet)
• Fenster werden typischerweise von JFrame oder JDialog
abgeleitet, oder Programm nutzt Objekt vom Typ JFrame
• Zentrale Definitionen stehen im Konstruktor (oder dort
aufgerufenen Methoden)
• Konstruktor (genauer Methoden) der Oberklasse werden
mit super(...) aufgerufen
Grundlagen Programmierung
Stephan Kleuker
653
Analyse des ersten Programms (2/3)
public class ErstesFenster extends JFrame{
...
public static void main(String[] args) {
new ErstesFenster();
}
}
• Ausführbare Klassen enthalten main-Methode
• Erzeugung eines Fensters (also Aufruf des Konstruktors)
durch new
• Danach können Methoden von JFrame und ErstesFenster
genutzt werden
d.h. eine Oberfläche muss nicht von JFrame erben, es reicht
wenn sie eine Objektvariable vom Typ JFrame hat
Grundlagen Programmierung
Stephan Kleuker
654
Analyse des ersten Programms (3/3)
public ErstesFenster()
setSize(200,50);
setLocation(100,30);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
• verschiedene Methoden, damit ein Frame (auch JFrame)
dargestellt wird, z. B.:
– Größe
– Position auf dem Bildschirm
– Reaktion auf Beenden-Knopf
, ohne wird
Programm inaktiv, läuft aber weiter
– Sichtbarkeit (immer zum Schluss)
Grundlagen Programmierung
Stephan Kleuker
655
Anmerkungen
Einige Programmanteile dieser Vorlesungen sind ab
hier als Teile des Konstruktors anzusehen. Das
umgebende Programm wird nicht mehr angegeben.
• Überlegen Sie sich bei angegebenen Methoden, zu welchen
Klassen sie gehören (können)
• Nutzen Sie die Java-Dokumentation und lesen Sie, welche
Methoden welche Klassen anbieten
• Versuchen Sie die Java-Klassenbibliothek genauer zu
verstehen (welche Klasse erbt von wem, warum)
Grundlagen Programmierung
Stephan Kleuker
656
Aufbau eines JFrame (1/2)
• Ein JFrame besteht aus den folgenden Komponenten innerhalb
der sogenannten RootPane:
Menu-Pane (JMenuBar)
Content-Pane (Container)
Layer-Pane (JLayerPane)
Glass-Pane (Component)
Grundlagen Programmierung
Stephan Kleuker
657
Aufbau eines JFrame (2/2)
• MenuPane: Platzierung des Hauptmenüs, falls vorhanden
• ContentPane: Anordnung der Buttons, Texte, ...  zentrale
Fensterfläche
• GlassPane: Popup-Menüs, Abfangen von Ereignissen, ... 
nicht Bestandteil der Vorlesung
• LayerPane: Anordnung zusätzlicher Komponenten auch in zRichtung (Schichtung der Komponenten übereinander) 
nicht Bestandteil der Vorlesung
• Grundidee: Panes sind Containter, die Sammlungen von
GUI-Elementen aufnehmen, Methode: add
Grundlagen Programmierung
Stephan Kleuker
658
Label mit Beispielfunktionalität
public class Labelanalyse extends JFrame{
public Labelanalyse(){
JLabel jl = new JLabel("Fisch",
new ImageIcon("bild.png"),4);
jl.setBorder(BorderFactory.createTitledBorder("Hai"));
jl.setFont(new Font("Monospaced", Font.PLAIN, 20));
jl.setForeground(Color.BLUE);
jl.setToolTipText("Nur ein kleiner Label");
add(jl);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack(); // ordentlich layouten
}
public static void main(String[] s) {
new Labelanalyse();
}
}
Grundlagen Programmierung
Stephan Kleuker
659
Implementierung eines Knopfes (V 1) (1/2)
import javax.swing.JButton;
import javax.swing.JFrame;
public class EinKnopfV1 extends JFrame {
private int count = 0;
private JButton jb = new JButton("Gedrückt: " + count);
public EinKnopfV1() {
super("Ich habe einen Titel");
jb.addActionListener(new MyListener(this));
add(jb);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
public void gedrueckt() {
jb.setText("Gedrückt: " + (++count));
}
public static void main(String[] args) {
new EinKnopfV1();
Grundlagen
Programmierung
Stephan Kleuker
}
}
660
Implementierung eines Knopfes (V 1) (2/2)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyListener implements ActionListener {
private EinKnopfV1 knopf;
public MyListener(EinKnopfV1 einKnopfV1) {
knopf = einKnopfV1;
}
public void actionPerformed(ActionEvent ev) {
knopf.gedrueckt();
}
}
• Varianten denkbar, z. B. JButton an MyListener übergeben
Grundlagen Programmierung
Stephan Kleuker
661
Implementierung eines Knopfes (V 2)
public class EinKnopfV2 extends JFrame implements ActionListener{
private int count=0;
private JButton jb= new JButton("Gedrückt: "+count);
public EinKnopfV2(){
super("Knopf V2");
jb.addActionListener(this);
add(jb);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
public void actionPerformed(ActionEvent ev){
jb.setText("Gedrückt: "+(++count));
}
public static void main(String[] args) {
new EinKnopfV2();
}
}
Grundlagen Programmierung
Stephan Kleuker
662
Implementierung eines Knopfes (V 3)
public class EinKnopfV3 extends JFrame{
private int count=0;
private JButton jb= new JButton("Gedrückt: "+count);
public EinKnopfV3(){
super("Ich habe einen Titel");
jb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
jb.setText("Gedrückt: "+(++count));
}
});
add(jb);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
}
public static void main(String[] args) {
new EinKnopfV3();
}
Grundlagen Programmierung
Stephan Kleuker
663
Grober Vergleich der Varianten
• Variante 2 und Variante 3:
+ schneller zu erstellen
+ weniger Klassen
+ Zugriff aus der Ereignis-Methode auf private
Objektvariablen und Methoden der umgebenden Klasse
- starke Tendenz zum Spaghetti-Code, da es viele Auslöser
für ein Action-Event geben kann.
• Variante 1:
- teilweise aufwändiger zu erstellen
- mehr Klassen
+ häufig flexibler bei vielen verschiedenen Ereignistypen
+ Widerverwendbarkeit von Ereignis-Code in anderen
Klassen
Grundlagen Programmierung
Stephan Kleuker
664
Sauberer Start
• bisher:
new EinKnopfV3();
• es werden viele GUI-Komponenten angelegt, die eventuell
bei Erstellung mit anderen Komponenten „reden“
• Event-Verwaltung findet in unabhängigen Prozessen statt
(genauer: Threads -> Betriebssysteme)
• Problem: Komponenten reden mit noch nicht erzeugten
Komponenten ( -> NullPointerException)
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new EinKnopfV3();
}
});
Grundlagen Programmierung
Stephan Kleuker
665
Model-View-Controller
• Allgemeiner Aufbau des MVC:
View
GUI-Komponente
Model
Controller
• Aufbau des MVC in Swing:
View
GUI-Komponente
Model
Controller
Delegate
Grundlagen Programmierung
Stephan Kleuker
666
Button - Hierarchie
• Klassenhierarchie für alle Buttons:
JComponent
AbstractButton
JToggleButton
JButton
JMenuItem
JCheckBox
JMenu
JRadioButton
JCheckBoxMenuItem
JRadioButtonMenuItem
Grundlagen Programmierung
Stephan Kleuker
667
JButton (1/4)
• Ein JButton unterstützt u. a. die Ereignistypen ChangeEvent
und ActionEvent der Basisklasse AbstractButton
• Reihenfolge der Ereignisse beim JButton:
Benutzer drückt die Taste (Maus oder Tastatur)
1. ChangeEvent (armed = true)
2. ChangeEvent (armed = true, pressed = true)
Benutzer lässt die Taste (Maus oder Tastatur) wieder los
3. ActionEvent
4. ChangeEvent (armed = true, pressed = false)
5. ChangeEvent (armed = false, pressed = false)
• Hinweis: armed zeigt an, ob der Mauszeiger bei gedrückter
Maustaste noch über dem Button ist
Grundlagen Programmierung
Stephan Kleuker
668
JButton (2/4)
Ablauf der Ereignisse für einen JButton
• Der Mauszeiger wurde über dem Button losgelassen
JButton
ButtonModel
Mouse Pressed
ChangeListener
ActionListener
armed=true
pressed=true
Mouse Released
pressed=false
activated
armed=false
Grundlagen Programmierung
Stephan Kleuker
669
JButton (3/4)
Ablauf der Ereignisse für einen JButton
• Die Maustaste ist gedrückt während der Mauszeiger den
Button verlässt und wieder betritt.
JButton
ButtonModel
Mouse Pressed
ChangeListener
ActionListener
armed=true
pressed=true
Mauszeiger verlässt
Button
Mauzeigers betritt
Button wieder
armed=false
armed=true
• Möglichkeit zum Zugriff auf das Modell für ChangeEvent e:
AbstractButton source=(AbstractButton)e.getSource();
ButtonModel model = source.getModel();
Grundlagen Programmierung
Stephan Kleuker
670
JButton (4/4)
Ablauf der Ereignisse für einen JButton
• Die Maustaste wurde gedrückt
• Der Mauszeiger verlässt den Button
• Die Maustaste wird losgelassen
JButton
ButtonModel
Mouse Pressed
ChangeListener
ActionListener
armed=true
pressed=true
Mauszeiger verlässt
Button
Mouse Released
Grundlagen Programmierung
armed=false
pressed=false
Stephan Kleuker
671
Unterscheidung von Komponenten
• Häufig möchte man verschiedene Knöpfe gerne in
actionPerformed unterscheiden. Ein Ansatz ist es, jedem Knopf
ein Kommando zuzuordnen:
JButton jb4 = new JButton("Aloa");
jb4.setActionCommand("k4");
• Dieser zugewiesene Text kann vom Event abgefragt werden
public void actionPerformed(ActionEvent ev){
if(ev.getActionCommand().equals("k4"))...
• Der Programmierer ist für die Eindeutigkeit der KommandoNamen zuständig ; Konstanten nicht direkt im Code
• auch sehr häufig genutzt: bestimme Quelle und nutze sie
AbstractButton source = (AbstractButton) ev.getSource();
ButtonModel model = source.getModel();
Grundlagen Programmierung
Stephan Kleuker
672
Menüs bestehen aus Knöpfen (1/2)
public class MenueBeispiel extends JFrame implements
ActionListener {
private JLabel label = new JLabel("ein Text");
private JMenuItem machItem(String text){
JMenuItem menuItem = new JMenuItem(text);
menuItem.addActionListener(this);
return menuItem;
}
@Override
public void actionPerformed(ActionEvent e) {
label.setText(((AbstractButton)e.getSource()).getText());
}
public static void main(String[] args) {
new MenueBeispiel();
}
Grundlagen Programmierung
Stephan Kleuker
673
Menüs bestehen aus Knöpfen (2/2)
public MenueBeispiel(){
add(label);
JMenuBar menuBar = new JMenuBar();
JMenu menu=new JMenu("Hauptmenue1");
menu.add(machItem("Punkt1.1"));
menu.add(machItem("Punkt1.2"));
menuBar.add(menu);
menu = new JMenu("Hauptmenue2");
menu.add(machItem("Punkt2.1"));
JMenu menu2=new JMenu("Submenue2.2");
menu2.add(machItem("Punkt2.2.1"));
menu2.add(machItem("Punkt2.2.2"));
menu.add(menu2);
menuBar.add(menu);
setJMenuBar(menuBar);
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(800, 100);
setVisible(true);
pack();
Grundlagen Programmierung
Stephan Kleuker
674
Layout, hierarchischer
GUI-Aufbau
Grundlagen Programmierung
Stephan Kleuker
675
Layoutmanager – Null-Layout (1/5)
• Bisher wurden Komponenten (z.B. JButton) mit der
Methode add zur Content-Pane hinzugefügt
• Wie können mehrere Komponenten angeordnet werden
(Position, Größe, ...)?
• Plattformabhängige Lösung: absolute Position und Größe
der Komponente werden direkt angegeben
Grundlagen Programmierung
Stephan Kleuker
676
Layoutmanager – Null-Layout (2/5)
Problem 1: Unterschiedliche Plattformen
• Der folgende Quelltext zeigt eine Anwendung, in der zwei
Buttons absolut positioniert werden 
Problem: verschiedene Zeichensätze auf unterschiedlichen
Plattformen und verschiedene Java-Versionen.
Grundlagen Programmierung
Stephan Kleuker
677
Layoutmanager – Null-Layout (3/5)
public class Nulllayout extends JFrame {
public Nulllayout() {
super("Titeltext");
setLayout(null);
JButton okButton = new JButton("Weiter");
JButton cancelButton = new JButton("Abbrechen");
okButton.setBounds(0, 0, 100, 25);
cancelButton.setBounds(100, 0, 100, 25);
add(okButton);
add(cancelButton);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(50, 50, 250, 60);
}
Grundlagen Programmierung
Stephan Kleuker
678
Layoutmanager – Null-Layout (4/5)
public static void main( String args[] ) {
NullLayout nl = new NullLayout();
nl.setVisible( true );
}
}
Bildschirmausgabe (Windows 2000, Windows 7):
Bildschirmausgabe (SuSE LinuX 7.2,
KDE 2, J2SDK 1.4)
Bildschirmausgabe (SuSE LinuX 7.2,
KDE 2, J2SDK 1.3):
Grundlagen Programmierung
Stephan Kleuker
679
Layoutmanager – Null-Layout (5/5)
Problem 2: Interaktive Größenänderungen der Dialoge
• Der Anwender ändert die Fenstergröße interaktiv  der
Inhalt passt sich nicht automatisch an (Platzverschwendung
oder „Verschwinden“ von Inhalten):
Grundlagen Programmierung
Stephan Kleuker
680
Analyse des Null-Layouts
Konsequenzen:
• Plattformunabhängige Programmierung ist mit absoluten
Layouts nicht sinnvoll möglich (unterschiedliche
Zeichensätze oder Zeichengrößen)
– Portierung einer Anwendung in mehrere Sprachen
erfordert bei absoluten Layouts manuelle Nacharbeiten
 nicht praktikabel
– Niemals ohne Layoutmanager mit Swing
Benutzeroberflächen erstellen!
Grundlagen Programmierung
Stephan Kleuker
681
GridLayout (1/4)
• GridLayout ordnet Komponenten im festen Zellenraster an
• Jede Komponente füllt ihre eigene Zelle komplett aus
Komp. 1
Komp. 2
Komp. 3
Komp. 4
Komp. 5
...
Komp. 6
...
Komp. n-1 Komp. n
• Reihenfolge der Komponenten wird durch die Reihenfolge
des Einfügens festgelegt (zeilenweise)
• Darstellung im Raster wird durch die Sprachausrichtung des
Containers festgelegt
• Raster-Abstand zwischen den Komponenten kann
eingestellt werden
Grundlagen Programmierung
Stephan Kleuker
682
GridLayout (2/4)
Berechnung der Komponentengrößen
• alle Zeilen des Rasters gleich hoch, alle Spalten gleich breit
• Die Komponentengrößen entsprechen:
– Breite: Breite des Containers / Anzahl Spalten
– Höhe: Höhe des Containers / Anzahl Zeilen
Einstellung des Layouts durch Konstruktor
• GridLayout(): Ausrichtung aller Komponenten in einer Zeile.
• GridLayout(int rows, int cols): Erzeugt ein Layout mit der
angegebenen Anzahl Zeilen und Spalten; sind beide Werte !=0,
wird cols ignoriert und durch die Anzahl Komponenten
bestimmt, cols wird nur ausgewertet, wenn rows==0 ist
• GridLayout(int rows, int cols, int hgap, int vgap): Zusätzlich
horizontaler Zeilenabstand von hgap Pixeln, vertikaler
Zeilenabstand von vgap Pixeln eingefügen
Grundlagen Programmierung
Stephan Kleuker
683
GridLayout (3/4)
public class Gridlayout extends JFrame {
public Gridlayout() {
super("GridLayout");
setLayout(new GridLayout(0, 3, 2, 2));
for(int i= 1; i<=4; i=i+1){
add(new JButton("K "+i, new ImageIcon("Knopf"+i+".gif")));
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack(); // optimale Groesse selbst berechnet
setVisible(true);
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Gridlayout();
}
});
}
Grundlagen
Programmierung
Stephan Kleuker
}
684
GridLayout (4/4)
Bildschirmausgaben (Start, manuell verkleinert und verzerrt):
Grundlagen Programmierung
Stephan Kleuker
685
Ermittlung von Größen (1/3)
• Woher kennt Layoutmanager die Größen der Komponenten?
– Komponenten kennen ihre Größen
– Layoutmanager fragt die Komponenten ab
– Größenangaben können vom Layoutmanager ignoriert
werden
– Swing-Komponenten erben von Basisklasse Component
Grundlagen Programmierung
Stephan Kleuker
686
Ermittlung von Größen (2/3)
• Component hat Methoden, um die folgenden Größen
auslesen bzw. schreiben zu lassen:
Eigenschaft
Dimension
preferredSize
Dimension
minimumSize
Dimension
maximumSize
Methoden
Dimension
getPreferredSize()
setPreferredSize(
Dimension dim )
Dimension
getMinimumSize()
setMinimumSize(
Dimension dim)
Dimension
getMaximumSize()
setMaximumSize(
Dimension dim )
Grundlagen Programmierung
Beschreibung
Liest die bevorzugte Größe der
Komponente
Schreibt die bevorzugte Größe der
Komponente
Liest die minimale Größe der
Komponente
Schreibt die minimale Größe der
Komponente
Liest die maximale Größe der
Komponente
Schreibt die maximale Größe der
Komponente
Stephan Kleuker
687
Ermittlung von Größen (3/3)
• Dimension: Klasse, die zwei öffentlich les- und schreibbare
Attribute enthält:
– width: Breite in Pixeln
– height: Höhe in Pixeln
• minimumSize: Layoutmanager versucht Komponente nicht
kleiner als ihre minimale Größe werden zu lassen
• maximumSize: Layoutmanager versucht Komponente nicht
größer als ihre maximale Größe werden zu lassen
• preferredSize: Layoutmanager versucht eine Komponente
so groß wie ihre bevorzugte Größe werden zu lassen
(solange dieses möglich ist); die preferredSize ergibt sich
beispielsweise bei einem JButton aus dem Text des Buttons
sowie eventuell vorhandenen Bildern und Rändern
Grundlagen Programmierung
Stephan Kleuker
688
BorderLayout (Überblick)
• BorderLayout ist der Layoutmanager, der als Standard für ein
Content-Pane eingestellt ist
• BorderLayout besitzt 5 Bereiche, in die jeweils eine
Komponente eingetragen werden kann (default ist Center)
North
West
Center
East
South
setLayout( new BorderLayout());
add( new JLabel("North-Label"),BorderLayout.NORTH);
Grundlagen Programmierung
Stephan Kleuker
689
BoxLayout (Überblick)
• BoxLayout kann beliebig viele Komponenten vertikal oder
horizontal anordnen.
Komp. 1
Komp. 2
Komp. 3
...
Komp. 1 Komp. 2
...
Komp. n
Komp. n
• Reihenfolge der Komponenten wird durch die Reihenfolge
des Einfügens festgelegt
• Abstand zwischen den Komponenten ist 0 Pixel groß
• BoxLayout berücksichtigt - im Gegensatz zu BorderLayout minimumSize und maximumSize.
Grundlagen Programmierung
Stephan Kleuker
690
Verschachtelung von Layouts (1/5)
• Bisher wurde der Content-Pane immer ein Layoutmanager
zugeordnet, in der Content-Pane wurden alle Komponenten
angeordnet
• Ansatz ist für komplizierte Layouts nicht flexibel genug
• Ergänzung: Als Komponenten können auch andere
Container eingesetzt werden, die ihrerseits wiederum einen
eigenen Layoutmanager besitzen und Komponenten
aufnehmen können  hierarchische Schachtelung
Content-Pane
(GridLayout)
Komp. 1
Grundlagen Programmierung
Komp. 2
Stephan Kleuker
JPanel
(BoxLayout) in
der Ecke
691
Verschachtelung von Layouts (2/5)
• JPanel:
– Container für andere Komponenten
– Keine eigene Darstellung (außer Hintergrund)
– Hintergrund kann transparent gesetzt werden
– Ein JPanel kann wie eine andere Komponente einem
Container hinzugefügt werden
– Unterstützt das Schachtel in Schachtel in Schachtel ... –
Prinzip
– Wichtig: ein JPanel hat ein eigenes Layout!
Grundlagen Programmierung
Stephan Kleuker
692
Verschachtelung von Layouts (3/5)
public class Schachtelung extends JFrame {
public Schachtelung(){
setLayout(new GridLayout(2,2));
add(box());
add(grid());
add(border());
add(nulll());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true); pack();
}
public static void main(String[] args) {
new Schachtelung();
}
private JPanel box(){
JPanel jp = new JPanel();
jp.setLayout(new BoxLayout(jp, BoxLayout.X_AXIS));
for(int i=0;i<4;i++)
jp.add(new JButton("42"));
return jp;
Grundlagen
Programmierung
Stephan Kleuker
}
693
Verschachtelung von Layouts (4/5)
private JPanel grid(){
JPanel jp= new JPanel(new GridLayout(2,2));
for(int i=0;i<4;i++)
jp.add(new JButton("43"));
return jp;
}
private JPanel border(){
JPanel jp= new JPanel(new BorderLayout());
jp.add(new JButton("44"),BorderLayout.NORTH);
jp.add(new JButton("44"));
jp.add(new JButton("44"),BorderLayout.EAST);
return jp;
}
private JPanel nulll(){
JPanel jp= new JPanel(null);
for(int i=0;i<3;i++){
JButton jb = new JButton("45");
jb.setBounds(50+20*i, 10*i, 60, 40);
jp.add(jb);
}
return jp;
}
Grundlagen
Programmierung
Stephan Kleuker
}
694
Verschachtelung von Layouts (5/5)
Grundlagen Programmierung
Stephan Kleuker
695
GridBagLayout – Übersicht (1/3)
• GridBagLayout ist der flexibelste und komplexeste
Standardlayoutmanager in Swing
• GridBagLayout platziert die Komponenten in einem Raster
aus Zeilen und Spalten
• Komponenten dürfen sich über mehrere Zeilen und/oder
Spalten erstrecken
• Zeilen dürfen unterschiedliche Höhen, Spalten
unterschiedliche Breiten besitzen
• GridBagLayout platziert die Komponenten in rechteckigen
Zellen, wobei die bevorzugten Größen (preferredSize) der
Komponenten verwendet werden, um die Ausmaße der
Zellen zu bestimmen
Grundlagen Programmierung
Stephan Kleuker
696
GridBagLayout – Übersicht (2/3)
• Übersicht:
Komp. 1
Komp. 2
Komp. 7
Komp. 3
Komp. 8
Komp. 6
Grundlagen Programmierung
Komp. 5 Komp. 4
Stephan Kleuker
697
GridBagLayout – Übersicht (3/3)
• Die Komponenten werden durch Angabe einer
Zellenposition platziert (z.B. Zelle 2,3)
• Der Ursprung (die Zelle 0,0) hängt von der Textausrichtung
des Containers ab:
– links  rechts: Ursprung liegt in linker, oberer Ecke
– rechts  links: Ursprung liegt in rechter, oberer Ecke
• Wird eine Komponente zu einem Container hinzugefügt, so
muss ein sogenanntes GridBagConstraints-Objekt mit
übergeben werden
• Das Constraints-Objekt beschreibt, in welche Zelle die
Komponente eingefügt werden soll und welche weiteren
Bedingungen gelten sollen
Grundlagen Programmierung
Stephan Kleuker
698
GridBagLayout – Constraints (1/4)
• GridBagConstraints unterstützt die folgenden Attribute:
int gridx
int gridy
Spalten- und Zeilenindex der Zelle, in die die
Komponente eingefügt werden soll
Besonderheit: GridBagConstraints.RELATIVE 
Komponente wird direkt auf den folgenden Index
der zuletzt eingefügten Komponente gesetzt
Default: GridBagConstraints.RELATIVE
int gridwidth Anzahl Spalten (gridwidth) oder Zeilen
int gridheight (gridheight), die die Komponente belegen soll.
Default: 1
int ipadx
Anzahl Pixel, die jeweils links und rechts (ipadx)
int ipady
bzw. oben und unten (ipady) zur Minimumgröße
der Komponente hinzugefügt werden
Default: 0
Grundlagen Programmierung
Stephan Kleuker
699
GridBagLayout – Constraints (2/4)
int fill
Wenn die Zelle größer als die bevorzugte Größe der
Komponente ist, enthält fill das Verhalten der
Komponente:
GridBagConstraints.NONE: Komponente nicht
verändern
GridBagConstraints.HORIZONTAL: Komponente
horizontal auf Zellenbreite ausdehnen
GridBagConstraints.VERTICAL: Komponente vertikal auf
Zellenhöhe ausdehnen
GridBagConstraints.BOTH: Komponente horizontal und
vertikal auf Zellengröße ausdehnen
Default: GridBagConstraints.NONE
Grundlagen Programmierung
Stephan Kleuker
700
GridBagLayout – Constraints (3/4)
double Bei Vergrößerung des Containers: Gewichtung zwischen
weightx 0.0 und 1.0, anhand derer der neue Platz auf die
double Komponenten verteilt werden soll:
weighty
0.0 oder fill==NONE: Komponente nicht vergrößern
Insets
insets
> 0.0 und fill!=NONE: Anteil, die die Komponente vom
neuen Platz erhalten soll
Default: 0 (meist nicht sinnvoll!)
Extra Platz, der zwischen den Rändern der Komponente
und dem Zellenrand eingefügt wird (leerer Rand um die
Komponente)
Insets.bottom: Freie Pixel unter der Komponente
Insets.top: Freie Pixel über der Komponente
Insets.left: Freie Pixel links von der Komponente
Insets.right: Freie Pixel rechts von der Komponente
Grundlagen Programmierung
Stephan Kleuker
701
GridBagLayout – Constraints (4/4)
int
anchor
Position, auf der die Komponente platziert werden soll,
wenn sie kleiner als die Zelle ist:
GridBagConstraints.NORTH: oben zentriert
GridBagConstraints.SOUTH: unten zentriert
GridBagConstraints.WEST: links, vertikal zentriert
GridBagConstraints.EAST: rechts, vertikal zentriert
GridBagConstraints.NORTHWEST: oben links
GridBagConstraints.NORTHEAST: oben rechts
GridBagConstraints.SOUTHWEST: unten links
GridBagConstraints.SOUTHEAST: unten rechts
GridBagConstraints.CENTER: mittig zentriert (Default)
Weitere (bezogen auf die Textausrichtung des
Containers, siehe API-Dokumentation)
Grundlagen Programmierung
Stephan Kleuker
702
Anmerkungen zu Constraints (1/2)
• Einsatz einiger Attribute:
gridx/gridy
anchor
Komponente
Insets.bottom
Insets.right
gridheight
Insets.left
Insets.top
Zelle
gridwidth
Grundlagen Programmierung
Stephan Kleuker
703
Anmerkungen zu Constraints (2/2)
• Beispiel (Bildschirmausgabe):
• Zellenaufbau:
gridwidth = 3
3
gridheight = 2
insets
Grundlagen Programmierung
Stephan Kleuker
704
Beispiel GridBagLayout (1/3)
public class GridBagSpielerei extends JFrame {
public GridBagSpielerei(){
GridBagLayout gbl= new GridBagLayout();
setLayout(gbl);
for(int i=0;i<5;i++){
addItem(gbl,new JButton(""+i),0,i,1,1);
addItem(gbl,new JButton(""+(i+5)),i+1,0,1,1);
}
addItem(gbl,new JButton("10"),1,1,5,1);
addItem(gbl,new JButton("11"),1,2,3,1);
addItem(gbl,new JButton("12"),4,2,2,3);
addItem(gbl,new JButton("13"),1,3,3,2);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(800, 100);
setVisible(true);
pack();
}
Grundlagen Programmierung
Stephan Kleuker
705
Beispiel GridBagLayout (2/3)
private void addItem(GridBagLayout gbl, Component c,
int x,int y, int b, int h) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = b;
gbc.gridheight = h;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.ipadx = 0;
gbc.ipady = 0;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.fill = GridBagConstraints.BOTH;
gbl.setConstraints(c, gbc);
add(c);
}
Grundlagen
Programmierung
Stephan Kleuker
706
Beispiel GridBagLayout (3/3)
Grundlagen Programmierung
Stephan Kleuker
707
GUI-Builder (1/2)
• Fazit: manuelle Anwendung des GridBagLayout ist aufwändig
• Die Programmierung von Oberflächen in Java ist zwar recht
strukturiert möglich, viele Arbeitsschritte wiederholen sich
aber monoton
• GUI-Builder stellen einen anderen Ansatz zur Entwicklung
von Oberflächen vor, Oberflächen werden per Drag-andDrop zusammengestellt
• Die weitere Programmierung findet durch den Entwickler
„unterhalb“ der GUI-Elemente statt, jeder Code muss einer
Komponente zugeordnet werden
• GUI-Builder eignen sich damit sehr gut, schnell einen GUIPrototypen zu erstellen, um mit den späteren Nutzern das
Look-and-Feel zu diskutieren
Grundlagen Programmierung
Stephan Kleuker
708
GUI-Builder (2/2)
• GUI-Builder haben aber auch Nachteile:
– Software häufig nicht GUI-gesteuert entwickelbar, je
komplexer das „Innenleben“ ist, desto weniger steht das
GUI in der Entwicklung im Mittelpunkt
– wer nicht weiß, wie ein GUI funktioniert, programmiert
nur Fragmente und kennt das Zusammenspiel nicht
– ohne GUI-Builder entwickelte Oberflächen können oft
nicht mit dem GUI-Builder weiter bearbeitet werden
– GUI-Builder geben die Struktur des Codes vor, d.h. man
muss sich auf die Programmiereigenheiten des GUIBuilders zu 100% einlassen
• Fazit: Einsatz eines GUI-Builders sollte nur in Betracht
gezogen werden, wenn man die Grundsätze zur GUIEntwicklung in der jeweiligen Programmiersprache
verstanden hat, danach muss getestet werden, ob man mit
dem resultierenden Code leben kann
Grundlagen Programmierung
Stephan Kleuker
709
Layoutmanager – Live-Update
• Seit JDK 1.4 kann für Dialoge ein sogenanntes Live-Update
eingeschaltet werden:
– Aufruf (Paket java.awt):
Toolkit tk = Toolkit.getDefaultToolkit();
tk.setDynamicLayout( true )
– Nutzung: Z. B. im GUI-Konstruktor unmittelbar vor
setVisible
– bei Größenänderung des Dialogs werden permanent die
Komponenten durch die Layout-Manager neu
angeordnet
– Vorteil: Sofortiger Eindruck der Änderungen
– Nachteil: Relativ langsam (gerade bei großen Dialogen
mit GridBagLayout)
Grundlagen Programmierung
Stephan Kleuker
710
Klassen Toolkit und UIManager andiskutiert
• Flexible Einstellungsmöglichkeiten, z. B. Bildschirmgröße
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
System.out.println(d);
Ausgabe: java.awt.Dimension[width=1024,height=600]
• Applikation auf gesamten Bildschirm, statt pack():
setLocation( 0, 0 );
resize( Toolkit.getDefaultToolkit().getScreenSize() );
• Änderung der Font-Größe für alle Label-Objekte (weitere
Einstellungen möglich)
UIDefaults uiDefaults = UIManager.getDefaults();
uiDefaults.put( "Label.font",
((Font)uiDefaults.get("Label.font")).deriveFont(30f) );
Grundlagen Programmierung
Stephan Kleuker
711
Layoutmanager – Platzhalter (1/3)
• Problem: Die Buttons sollen rechtsbündig erscheinen, wie
kann ein variabler Zwischenraum eingefügt werden?
• Ziel: Buttons können ihre bevorzugte Größe einnehmen,
Zwischenraum füllt den Rest
• Lösung: Die Klasse Box enthält statische Methoden, die
verschiedene unsichtbare Komponenten erzeugen können
• Andere Lösung: Rechtsbündiges FlowLayout (soll hier nicht
besprochen werden).
Grundlagen Programmierung
Stephan Kleuker
712
Layoutmanager – Platzhalter (2/3)
Rigid Area
• unsichtbare Komponente der angegebenen Größe
• Erzeugung:
– Component Box.createRigidArea( Dimension dim )
– dim: Größe. (ist ein Maß = 0  irrelevant)
K1
K2
K1
Rigid
Area
K2
Glue
• Komponente, die den restlichen freien Platz aufnimmt
• Erzeugung:
Component Box.createGlue()
K1
K2
Grundlagen Programmierung
K1
Stephan Kleuker
Glue
K2
713
Layoutmanager – Platzhalter (3/3)
Custom filler
• Erzeugt eine unsichtbare Komponente der mit angegebenen
Minimum-, Maximum- und Preferred-Size
• Erzeugung:
– new Box.Filler( Dimension min, Dimension pref,
Dimension max )
– min, pref, max: Entsprechende Größen
– Filler ist eine statische innere Klasse (Innerclass) von Box
K1
K2
Grundlagen Programmierung
K1
Stephan Kleuker
Custom K2
Filler
714
Personal Look and Feel (1/4)
• In Swing kann man die Gestaltung der Oberfläche relativ
leicht als Standard ändern
• Individuelle Design-Grundlagen für die Oberflächen sind
ebenfalls realisierbar, aber recht aufwändig
• Das folgende Programm zeigt einige Einstellmöglichkeiten
• Look and Feels können selbst geschrieben werden
• Look and Feels stehen nicht auf jedem Betriebssystem zur
Verfügung
• Default-Look and Feel „Metal“ kann durch „Themes“ noch
verändert werden
• „Synth“ als leicht über XML konfigurierbares Layout
Grundlagen Programmierung
Stephan Kleuker
715
Personal Look and Feel (2/4)
public class LookAndFeels extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private String[][] looks =
{{"javax.swing.plaf.metal.MetalLookAndFeel", "Metal"},
{"javax.swing.plaf.synth.SynthLookAndFeel","Synth"},
{"com.sun.java.swing.plaf.motif.MotifLookAndFeel","Motif"},
{"com.sun.java.swing.plaf.windows.WindowsLookAndFeel",
"Windows"},
{"com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel",
"Windows Classic"},
{"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel", "Nimbus"},
{"javax.swing.plaf.mac.MacLookAndFeel","Mac"},
{"com.sun.java.swing.plaf.gtk.GTKLookAndFeel","GTK"},
{"javax.swing.plaf.multi.MultiLookAndFeel","Multi"}};
private JPanel jp = new JPanel(new GridLayout(names.length, 1));
Grundlagen Programmierung
Stephan Kleuker
716
Personal Look and Feel (3/4)
public LookAndFeels() {
for (int i = 0; i < looks.length; i++) {
JButton jb = new JButton(looks[i][1]);
jb.addActionListener(this);
jp.add(jb);
}
add(jp);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
@Override public void actionPerformed(ActionEvent ev) {
for (int i = 0; i < looks.length; i++){
if (looks[i][1].equals(ev.getActionCommand())) {
try {
UIManager.setLookAndFeel(looks[i][0]);
SwingUtilities.updateComponentTreeUI(this);
pack();
} catch (Exception e) {
System.out.println("L&F nicht anwendbar");
}
Grundlagen
Stephan Kleuker
} Programmierung
}
717
Personal Look and Feel (4/4)
Grundlagen Programmierung
Stephan Kleuker
718
Java – Was fehlt noch
einfachere Frage: was ist schon da
• fehlt: Rekursion
• fehlt: Reflektion, Objekt kennt eigene Variablen und
Methoden
• fehlt: generische Programmierung, class X<T extends Y>
• fehlt: Entwicklung und Nutzung von Annotationen
• fehlt: Möglichkeit Bilder zu malen (paint), Java3D
• fehlt: Nutzung vieler SW-Pakete, die in Java enthalten sind
• fehlt: Nutzung vieler weiterer SW-Pakete und Frameworks
(teilweise basierend auf Java-Standards)
• fehlt: …
Grundlagen Programmierung
Stephan Kleuker
719