© APSIS GmbH |
Seite 144
Seite 144
heute = heute.next(); // von Dienstag nach Mittwoch wechseln // nicht in Java aufzaehlungsobjekt = aufzaehlungsobjekt.first(); // erster Aufzählungswert
Getraenk getraenk = Getraenk.WEIN; // Vorbesetzungswert // (7.1) getraenk = (Getraenk)getraenk.erster(); // Getraenk.WASSER ¬ getraenk = (Getraenk)getraenk.letzter(); // Getraenk.WEIN Farbe farbe = Farbe.ROT; farbe = (Farbe)farbe.letzter(); // Farbe.BLAU ¬ farbe = (Getraenk)getraenk.erster(); // Typfehler bei der Übersetzung farbe = (Farbe)getraenk.erster(); // ebenso
getraenk = Getraenk.WASSER; Getraenk anderesGetraenk = (Getraenk)getraenk.vorheriger(); // throws BereichAusn
Eimer.meldung(getraenk.text()); // WASSER oder WEIN im Fenster System.out.println(getraenk.text()); // WASSER oder WEIN auf der Konsole
System.out.println(getraenk.toString()); // interne Repräsentation ausgeben System.out.println(getraenk); // toString wird automatisch aufgerufen ¬
catch (Exception ausnahme) { System.err.println(ausnahme); // ausnahme.toString() }
Seite 146
import lehrbuch.*; // (7.2) public class GetraenkVerwandeln { public static void getraenkVerwandeln(Eimer eimer) { Getraenk getraenk = Getraenk.WASSER; try { getraenk = (Getraenk)eimer.inhalt().naechster(); // ¬ // inhalt throws LeerAusn; naechster throws BereichAusn; eimer.entleeren(); // throws LeerAusn, wurde aber schon erkannt eimer.fuellen(getraenk); } catch (Exception ausnahme) { // LeerAusn oder BereichAusn try { // geschachteltes try eimer.fuellen((Getraenk)getraenk.erster()); // throws VollAusn ¬ } catch (VollAusn a) {} // dann eben lassen } }
public static void main(String[] args) { try { Eimer eimer1 = new Eimer(), eimer2 = new Eimer(); ... // evtl. Eimer anzeigen new lehrbuch.kapitel6.EimerMenue().menue(eimer1, eimer2); getraenkVerwandeln(eimer1); Eimer.meldung(eimer1.inhalt().text()); // verwandeltes Getränk ¬ eimer1.inhalt().meldung(); // Alternative: meldung von Getraenk } catch (Exception ausnahme) { System.err.println(ausnahme); } // Notmeldung } }
Seite 147
class Farbe extends lehrbuch.Aufz { // eigene Farbklasse mit vier Werten // (7.3) public static final Farbe ROT = new Farbe(); // const ¬ // spezielles Objekt für die Darstellung des Wertes "Rot" public static final Farbe GELB = new Farbe(); // diesmal nicht GRUEN public static final Farbe BLAU = new Farbe(); public static final Farbe LILA = new Farbe(); }
public class FarbeDemo { // geerbte Methoden der Aufzählungsklasse werden benutzt public static void main(String[] args) { try { Farbe farbe = Farbe.ROT; // ¬ Farbe andereFarbe = farbe; // Zuweisung: andereFarbe ist jetzt ROT ¬ andereFarbe = Farbe.GELB; // Wertzuweisung: andereFarbe ist jetzt GELB farbe = (Farbe)farbe.naechster(); // GELB System.out.println(farbe.text()); farbe = (Farbe)farbe.letzter(); // LILA farbe = (Farbe)farbe.wert("BLAU"); farbe = (Farbe)farbe.wert(andereFarbe.text()); // GELB farbe = (Farbe)farbe.erster(); // ROT farbe = (Farbe)farbe.vorheriger(); // throws BereichAusn } catch (lehrbuch.BereichAusn ausnahme) { System.out.println("Erwartete Ausnahme"); } } }
package lehrbuch; // (7.4) public abstract class Aufz { public Aufz erster(); // liefert den ersten Aufzählungswert public Aufz letzter(); // liefert den letzten Aufzählungswert public Aufz naechster() throws BereichAusn; // Nachfolgewert /** liefert den nächsten Aufzählungswert, wenn gültig; Ausnahme beim letzten */ public Aufz vorheriger() throws BereichAusn; // Vorgänger; Ausnahme beim Ersten public String text(); // const // Name des Werts public Aufz auswahl(); // Auswahlliste public Aufz eingabe() throws BereichAusn; // Eingabefenster public void meldung(); // const // aktueller Wert im Meldungsfenster ... // Vergleichsmethoden im Programm (7.11) }
farbe = farbe.vorheriger(); // Typfehler, da nicht Abwärtskompatibel farbe = (Farbe)farbe.vorheriger(); // explizite Abwärtskompatibilität ist nötig
Übung 7.1: Schreiben Sie ein Dialogprogramm, das den Folgetag eines Wochentags berechnet. Definieren Sie dazu eine Aufzählungsklasse für die Wochentage. Fordern Sie den Bediener Ihres Programms auf, einen Wochentag von der Auswahlliste auszuwählen. Errechnen Sie den Folgetag mit Hilfe von naechster; fangen Sie dabei die zu erwartenden Ausnahmen in einem geschachtelten Block auf. Zeigen Sie den Folgetag in einem Meldungsfenster an.
Übung 7.2: Erweitern Sie Ihr Programm aus der vorherigen Übung, mit dem Sie durch Menüauswahl über die Wochentage navigieren können. Sie sollen dabei den aktuellen Tag auf einen beliebigen Tag setzen sowie vorwärts und rückwärts navigieren können.
Stellen Sie sich zuerst einen Plan Ihres Menüs mit angehängten Rückrufprozeduren auf. Ein Menüpunkt soll dem Benutzer ermöglichen, einen Wochentag über eine Auswahlliste einzugeben. Über einen zweiten Menüpunkt kann der Bediener den Folgetag berechnen. Zeigen Sie ihm diesen Tag in einem Meldungsfenster an. Eine weitere Auswahl dieses Menüpunktes errechnet jeweils den nächsten Wochentag, den Sie immer wieder über das Meldungsfenster anzeigen. Den Folgetag des letzten Wochentags sollten Sie über die Ausnahme BereichAusn auffangen: Dieser ist dann der erste Wochentag. Über einen weiteren Menüpunkt sollen Sie auch noch den Vorgängertag ähnlich errechnen.
Nachdem Ihr Plan fertig ist, generieren Sie das Menü mit Hilfe von Menuegenerator und programmieren Ihre Prozeduren. Alternativ können Sie auch mit Standardmenüs arbeiten, wie es im Kapitel 6.5.5. auf Seite 141 vorgestellt wurde.
Seite 149
package lehrbuch; // (7.5) class Getraenk extends Aufz { public static final Getraenk WASSER = new Getraenk(); public static final Getraenk WEIN = new Getraenk(); } class Gefuellt extends Aufz { public static final Gefuellt NEIN = new Gefuellt(); public static final Gefuellt JA = new Gefuellt(); } public class EinEimer { private static Aufz eimerGefuellt = Gefuellt.NEIN; // oder JA private static Getraenk eimerInhalt = Getraenk.WASSER; // oder WEIN // eimerInhalt kann auch vom Typ Aufz vereinbart werden, kein Unterschied // öffentliche Konstanten: public static final Getraenk WASSER = Getraenk.WASSER; public static final Getraenk WEIN = Getraenk.WEIN; // Mutatoren: public static void fuellen(final Getraenk getraenk) throws VollFehler{ try { eimerGefuellt = eimerGefuellt.naechster(); // throws BereichAusn ¬ // keine Typkonvertierung nötig, weil eimerGefuellt vom Typ Aufz vereinbart wurde eimerInhalt = getraenk; } catch (BereichAusn ausnahme) { // bei JA throw new VollFehler(); // ¬ } } public static void fuellen() throws VollFehler { fuellen(WASSER); } public static void entleeren() throws LeerFehler { try { eimerGefuellt = eimerGefuellt.vorheriger(); // throws BereichAusn ¬ // keine Typkonvertierung nötig, weil eimerGefuellt vom Typ Aufz vereinbart wurde } catch (BereichAusn ausnahme) { // bei NEIN throw new LeerFehler(); // ¬ } }
// Informator: public Getraenk inhalt() throws LeerFehler { try { attrappe = eimerGefuellt.vorheriger(); // BereichAusn ¬ // attrappe ist global, damit der Compiler es nicht wegoptimiert // keine Typkonvertierung nötig, weil eimerGefuellt vom Typ Aufz vereinbart wurde return eimerInhalt; } catch (BereichAusn ausnahme) { throw new LeerFehler(); // ¬ } } private static Gefuellt attrappe; }
Übung 7.3: Implementieren Sie die Logik des statischen Datenbehälters EinKreis mit einer ähnlichen Spezifikation wie Kreis (s. Übungen 2.16 auf Seite 46 und
auf Seite 99). Testen Sie Ihre Klasse mit ihrer eigenen main-Methode.
Seite 150
Seite 151
java.lang.Boolean log = java.lang.Boolean.TRUE; // (7.6)
lehrbuch.Bool log = lehrbuch.Bool.TRUE; log = (lehrbuch.Bool)log.erster(); // alle Aufzählungsmethoden verfügbar
new lehrbuch.Bool(log).meldung(); // anonymes Bool-Objekt
Übung 7.4: Schreiben Sie ein Programm mit drei lehrbuch.Bool-Objekten. Füllen Sie Ihre Objekte mit Hilfe der Methode auswahl der Klasse lehrbuch.Bool. Zeigen Sie das Ergebnis am Bildschirm an.
Seite 151
log = new lehrbuch.Bool(true); // gleichwertig mit new lehrbuch.Bool(lehrbuch.Bool.TRUE)
Boolean log = new Boolean(true); // java.lang implizit
log = new Boolean("true"); // gleichwertig
log = new Boolean(); // Fehler
Seite 152
boolean log; // new ist – wie bei Aufzählungsklassen – nicht nötig // (7.7) log = true; // Wert im Behälter gespeichert boolean log2 = false; // andere Variable log = log2; // Inhalt kopiert; alter Inhalt geht verloren
package lehrbuch; // (7.8) public class Bool { private boolean inhalt; // Datenkomponente ¬ public static final Bool TRUE = new Bool(true); // zwei Wertereferenzen public static final Bool FALSE = new Bool(false); public Bool(final boolean wert) { // Wertekonstruktor inhalt = wert; } public Bool(final Bool quelle) { // const quelle // Kopierkonstruktor inhalt = quelle.inhalt; } public Bool(final Boolean quelle) { // const quelle inhalt = quelle.booleanValue(); // Boolean exportiert booleanValue } public void setzen(final boolean wert) { inhalt = wert; } ... // weitere Methoden wie Aufzählungsmethoden, usw. }
new Bool(log).meldung();
Seite 153
Eimer eimer = new Eimer(); // (7.9) ... // Eimer evtl. anzeigen, Zustand "gefüllt" oder "leer" einstellen Bool fuellZustand = new Bool(eimer.gefuellt()); // ¬ // das Ergebnis wird in einer logischen Variable gespeichert fuellZustand.meldung(); // oder der Inhalt des gelieferten Objekts angezeigt Eimer.meldung(new lehrbuch.Bool(eimer.gefuellt()).text()); // ¬
Seite 154
boolean vergleichswert = eimer1.gleich(eimer2); // (7.10) new lehrbuch.Bool(vergleichswert).meldung(); // Methode von lehrbuch.Bool System.out.println(vergleichswert); // auch möglich
vergleichswert = eimer1.equals(eimer2);
public boolean equals(Object object);
boolean b = eimer.equals(kreis);
public boolean gleich(Eimer eimer); // liefert boolean-Wert
Farbe f1 = Farbe.ROT, f2 = Farbe.BLAU; boolean b = f1.kleiner(f2); // true ¬ b = f1.nichtGroesser(Farbe.BLAU); b = f1.ungleich(Kreis.gruen());
package lehrbuch; // (7.11) public abstract class Aufz { ... // Anfang im Programm (7.4) public boolean gleich(Aufz aufz); public boolean ungleich(Aufz aufz); public boolean kleiner(Aufz aufz); public boolean nichtKleiner(Aufz aufz); public boolean groesser(Aufz aufz); public boolean nichtGroesser(Aufz aufz); }
Seite 155
Seite 155
char zeichen = ':';
zeichen = '\u00A3'; // 00A3 hexadezimal = 58 dezimal = Doppelpunkt // (7.12) zeichen = '\u0431'; // 0431 hexadezimal = russisches 'B' zeichen = '\u2297'; // 2297 hexadezimal = das Zeichen Ä zeichen = '\u0000'; // das Null-Zeichen (auch nicht auf der Tastatur)
zeichen = '\t'; // Tabulator
'\t' | Tabulator | \u0009 |
'\n' | Zeilenvorschub | \u000a |
'\b' | "backspace" | \u0008 |
'\r' | "return" | \u000d |
'\\' | "backslash" | \u005c |
'\'' | Apostroph | \u0027 |
'\"' | Anführungszeichen | \u0022 |
Abb. 7.1: Sonderliterale
Seite 156
char zeichen; // (7.13) zeichen = 'x'; // das Zeichen x in der Variable gespeichert char zweitesZeichen = 'y'; // neue Variable, mit Vorbesetzungswert zeichen = zweitesZeichen; // alter Inhalt geht verloren zeichen = (char)System.in.read(); // ein Zeichen von der Konsole lesen ¬
Übung 7.5: Schreiben Sie ein Programm mit einer geeigneten Anzahl von char-Variablen: Lesen Sie in diese die Buchstaben Ihres Vornamens als Literale, Ihres Nachnamens von der Tastatur ein. Geben Sie sie in umgekehrter Reihenfolge auf der Konsole aus.
Seite 157
package lehrbuch; // (7.14) public class Char { protected char inhalt; // Datenkomponente ¬ public Char(char zeichen) { ... } // Konstruktor besetzt inhalt mit zeichen ... // Methoden ähnlich wie im Programm (7.8)
java.lang.Character zeichenBehaelter = new java.lang.Character('Z'); // (7.15) // java.lang kann weggelassen werden, da implizit importiert
Übung 7.6: Schreiben Sie eine Version Ihres Programms aus der Übung 7.5 auf Seite 156 mit Char-Objekten.
Seite 157
Seite 158
Abb. 7.2: Eingebettete Variablen und referierte Objekte
Klasse | Basistyp | |
Benutzung | Objekt | Variable |
Zugriff | über Referenz | direkt |
Operation | Methode | Operator |
Wert | Wertereferenz | Literal |
Definition | frei | Bestandteil der Sprache |
Abb. 7.3: Klassen und Basistypen
Seite 159
Seite 159
zielreferenz.methode()
operator zielvariable zielvariable operator
zielreferenz.methode(parameter)
zielvariable operator parameter
zielvariable = wert; // Zuweisung als Prozedur methode(new Klasse()); // Objekterzeugung als Funktion
char z1, z2; // (7.16) ... // Werte eingeben boolean b1 = z1 == z2; // true, wenn gleiche Zeichen eingegeben wurden boolean b2 = z1 == 'a'; // true, wenn zuerst ein kleines a eingegeben wurde ¬ boolean b3 = b1 == b2; // true, wenn beide true oder beide false b3 = z1 == z1; // immer true b3 = 'a' == 'b'; // immer false
b2 = z1 != 'a'; // false, wenn zuerst ein kleines a eingegeben wurde b3 = b1 != b2; // false, wenn beide true oder beide false, sonst true b3 = z1 != z1; // immer false b3 = 'a' != 'b'; // immer true
b1 = eimer1 == eimer2; // true, wenn zuvor eimer1 = eimer2 durchgeführt wurde b2 = eimer1.equals(eimer2);
Seite 160
boolean b = z1 < z2; // die Unicode-Reihenfolge wird bewertet
Seite 161
linker Wert | rechter Wert | &
"und" |
|
"oder" |
^ "entweder oder" |
true |
true |
true |
true |
false |
true |
false |
false |
true |
true |
false |
true |
false |
true |
true |
false |
false |
false |
false |
false |
Abb. 7.4: Diadische logische Operatoren
b1 = b2 & b3; // true, wenn beide true, sonst false // (7.17) b1 = b2 | b3; // false, wenn beide false, sonst true b1 = b2 ^ b3; // true, wenn ungleich, false wenn gleich b1 = b2 != b3; // für boolean gleichwertig mit ^ b1 = b2 = b3; // true, wenn gleich; false, wenn ungleich
b1 = inf1() && inf2(); // inf2 wird nicht berechnet, wenn inf1 == false b1 = inf1() || inf2(); // inf2 wird nicht berechnet, wenn inf1 == true
b1 &= b2; // Abkürzung für b1 = b1 & b2; b1 |= b2; // Abkürzung für b1 = b1 | b2; b1 ^= b2; // Abkürzung für b1 = b1 ^ b2;
Wert |
! "nicht" (Negation) |
true |
false |
false |
true |
Abb. 7.5: Monadischer logischer Operator
b1 = ! b2; // b1 wird true wenn b2 false ist
Seite 162
Seite 162
int zahl; // Ganzzahlvariable // (7.18) zahl = 5; // Ganzzahlliteral int zweiteZahl = 6; // Vorbesetzung zahl = zweiteZahl; // Zuweisung
a1 += a2; // Abkürzung für a1 = a1 + a2; ... // ähnlich für -=, *=, /= und %= a ++; // Abkürzung für a = a + 1; // ¬ a --; // Abkürzung für a = a - 1; // ¬
a1 = a2 ++; // nicht empfohlen a1 = a2 = a3; // ausnahmsweise verwendbar
a1 = ++ a2; // auch nicht empfohlen: Der inkrementierte Wert wird übertragen
a2 ++; a1 = a2;
a1 = a2; a2 ++; // intuitiv eindeutig
Typ | Wertebereich |
byte | -128 bis 127 |
short | -32768 bis 32767 |
int | -2147483648 bis 2147483647 |
long | -9223372036854775808 bis 9223372036854775807 |
char | '\u0000' bis '\uffff', d.h. 0 bis 65535 |
Abb. 7.6: Ganzzahltypen in Java
int ganzzahl = System.in.read();
long ganzzahl = (long)System.in.read(); // explizite Typkonvertierung
Seite 164
public class Eimer { // (7.19) // drei Objektkomponenten: private boolean eimerGefuellt; private Getraenk eimerInhalt; // WASSER oder WEIN private int eimerPos; // Position des Eimers 0 .. 4 // Klassenkomponente: private static int naechstePos; // Position des letzten angezeigten Eimers ¬ static { // Vorbesetzung der Klassenkomponente im Klasseninitialisator: ¬ naechstePos = 0; // noch kein Eimer wurde angezeigt } public Eimer() { // Vorbesetzung der Objektkomponenten im Konstruktor ¬ eimerGefuellt = false; eimerPos = 0; } public boolean gleich (final Eimer eimer) { // const quelle // vergleicht Füllzustand und Inhalt return (! eimerGefuellt && ! eimer.eimerGefuellt) || // beide leer, oder eimerGefuellt && eimer.eimerGefuellt && // beide voll, und eimerInhalt.gleich(eimer.eimerInhalt); // gleicher Inhalt } ... // Implementierung weiterer Operationen im Kapitel 10.1.5.
Seite 165
int t = 41; // Temperatur in Celsius // (7.20) int s = 41; // Schuhgröße
t = s; // logischer Typfehler, Compiler und Interpreter entdecken ihn nicht
class Temperatur extends lehrbuch.Int {} class Schuhgroesse extends lehrbuch.Int {} Temperatur t = new Temperatur(); Schuhgroesse s = new Schuhgroesse();
public Temperatur waerme(Schuhgroesse schuh);
t = waerme(t); // Typfehler
t = (Temperatur)(lehrbuch.Int)s; // kein Typfehler t = waerme((Schuhgroesse)(lehrbuch.Int)t); // kein Typfehler
package lehrbuch; // (7.21) public class Int { public Int(); public Int(final int wert); // Wertekonstruktor public Int(final Int quelle); // Kopierkonstruktor public void setzen(final int wert); public void setzen(final Int quelle); public void setzen(final String name) throws BereichAusn; public int wert(); public Int erster(); ... // usw. Aufzählungsmethoden wie üblich public boolean gleich(Int i); // entspricht == ... // usw., Vergleichsfunktionen wie üblich public Int plus(Int i); // arithmetische Funktion entspricht + public Int minus(Int i); // entspricht - public Int mal(Int i); // entspricht * public Int durch(Int i); // entspricht / public Int rest(Int i); // entspricht % }
Seite 166
Typ | Darstellung |
float |
32 Bits |
double |
64 Bits |
Abb. 7.7: Bruchtypen in Java
float f1 = .25e3; // Typfehler // (7.22) float f2 = (float)25.e-3; // oder float f3 = 2.5f;
public class GleitGefahr { // (7.23) // Zwei mathematisch gleichwertige Formeln werden wiederholt berechnet: // x = (1+r)*x - r*x*x = x + r*x*(1-x); ihr Quotient sollte daher immer 1 sein. // Durch die Ungenauigkeit des Rechners ergibt sich aber eine Abweichung. final static double aufhoeren = 100.0; // aufhören, wenn Abweichung größer public static void main (String [] args) { double x1 = 0.01, x2 = 0.01, quotient = 1.0; final double r = 3.0; int zaehler = 0; while (quotient < aufhoeren) { // ein kleiner Vorgriff auf Kapitel 10.2.: Schleife zaehler ++; x1 = (1+r)*x1 - r*x1*x1; // ¬ x2 = x2 + r*x2*(1-x2); // ¬ quotient = x1 / x2; // sollte immer 1.0 sein System.out.println (zaehler + ". " + quotient); // 1.0 ¬ } // Block wird wiederholt, solange quotient < aufhoeren } }
Übung 7.7: Schreiben Sie ein Programm, das in Fahrenheit angegebenen Temperaturen (wie es in Amerika üblich ist) in Celsius umrechnet. Die Formel für die Umrechnung ist:
Seite 167
Seite 167
grafik.drawImage(getImage(getCodeBase(), "Hallo.gif"), 0, 0, this); // (7.24)
grafik.drawImage(getImage(getCodeBase(), "Hallo.gif"), x, y+1, this); // int x, int y sind Koordinaten im Fenster
grafik.drawImage(getImage(getCodeBase(), "Hallo.gif"), 1+x/2, (y+1)/2, this);
Operatoren | Gruppe | |
[] . () ++ -- | Postfix-Operatoren | höchste Priorität |
++ -- + - ~ ! | unäre Operatoren | |
new () | Erzeugung/Typkonversion | |
* / % | multiplikative Operatoren | |
+ - | additive Operatoren | |
<< >> >>> | Verschiebungsoperatoren | |
< <= > >= | Vergleich | |
== != | Gleichheit | |
& | Konjunktion | |
^ | Exklusion | |
| | Disjunktion | |
&& | kurze Konjunktion | |
|| | kurze Disjunktion | |
?: | Bedingungsoperator | |
= += usw. | Zuweisungen | niedrigste Priorität |
Abb. 7.8: Bindungsstärke von Operatoren
b1 < b2 & ! b2 < b3
b1 < b2 & ! (b2 < b3)
a1 + a2 – a3 ist gleichwertig mit (a1 + a2) – a3
Seite 169
kalt & sonnig | nass
kalt & sonnig | nass kalt & sonnig | nass
kalt |
sonnig |
nass |
kalt & sonnig |
kalt
& sonnig |
sonnig | nass |
kalt
& |
false |
true |
true |
false |
true |
true |
false |
Abb. 7.9: Operatoren gleicher Priorität
Seite 169
public void operation(...); // requires logischerAusdruck1; ensures logischerAusdruck2
class EinEimer { // (7.25) public void fuellen(Getraenk getraenk); // requires ! gefuellt(); ensures gefuellt() & inhalt() = getraenk; public void entleeren(); // requires gefuellt(); ensures ! gefuellt(); public Getraenk inhalt(); // requires gefuellt(); public boolean gefuellt(); // keine Zusicherungen, d.h. bedingungslos ...
// invariant ! gefuellt() | (gefuellt() & getraenk == WASSER) | (gefuellt() & getraenk == WEIN)
© APSIS GmbH |