Gestern haben Sie eine Anwendung und ein Applet unter Java geschrieben. Heute werden Sie die Sprache genauer kennenlernen, so daß Sie die grundlegenden Konstrukte kennen und wissen, wie sie für die Programmierung in Java eingesetzt werden.
Die folgenden Konstrukte stellen die elementaren Bausteine Ihrer Java-Programme dar, etwa Variablen, Typen, Ausdrücke, Operatoren, Arrays, Strings, Bedingungen und Schleifen. Heute lernen Sie die folgenden Dinge kennen:
In einer Programmanweisung erfolgt die eigentliche Arbeit. Es gibt drei Kategorien von Anweisungen: einfache Anweisungen, zusammengesetzte Anweisungen und Kommentare. Einfache und zusammengesetzt Anweisungen werden kompiliert und werden Teil der Binärdarstellung Ihrer Anwendung. Alle kompilierten Anweisungen müssen mit einem Semikolon enden (;). Kommentare werden nicht kompiliert und sind nur im Quellcode sichtbar. Sie können jedoch Monate später Bedeutung erlangen, wenn Sie (oder jemand, der Ihren Code warten soll) versuchen, herauszufinden, was der Code bewirken soll.
Einfache Anweisungen können Werte zuweisen, eine Aktion ausführen oder eine Methode aufrufen.
currpoint = new Point(x,y);
if (i==8) j = 4;
g.drawString("Hello world!", 10, 30);
repaint();
Java unterstützt verschiedene Anweisungstypen, unter anderem Zuweisung, Block, Bedingung, Deklaration, Schleifen und Methodenaufrufe. Bis auf die Methodenaufrufe werden all diese Typen heute beschrieben, die Methodenaufrufe folgen morgen.
Eine Block-Anweisung (oder einfach ein Block) ist eine Gruppe anderer Programmanweisungen,
die in geschweifte Klammern eingeschlossen ist ({}). Es handelt sich dabei um dieselbe Klammerung wie in
C/C++ und sie ist analog zu dem begin..end-Paar in Pascal/Delphi. Manchmal spricht man auch von einer
zusammengesetzten Anweisung.
Hier folgt ein Beispiel, das die unterschiedlichen Gültigkeitsbereiche demonstriert. In der folgenden Methodendefinition wird y zweimal deklariert: einmal für die Methode als Ganzes, einmal innerhalb des Blocks:
void testblock() {
int x = 10;
int y = 35;
[ // Blockanfang
int y = 50;
System.out.println("Im Block:");
System.out.println("x:" + x);
System.out.println("y:" + y); // einmal
] // block end
System.out.println("y:" + y); // zweimal
}
Wenn y zum ersten Mal ausgegeben wird, liegt der Gültigkeitsbereich innerhalb des Blocks, wo y redefiniert wurde, sein Wert ist also 50. Wenn y zum zweiten Mal ausgegeben wird, liegt der Gültigkeitsbereich innerhalb der Methode aber außerhalb des Blocks, der Wert von y ist also 35.
Blöcke werden in der Regel nicht so eingesetzt, wie in diesem Beispiel gezeigt. Häufig finden sie in Kontrollstrukturen Verwendung, die Sie später noch kennenlernen werden.
Kommentare sind Anweisungen, die nicht kompiliert werden, und die beliebige Texte enthalten können, die Sie dem Code zur Information mitgeben wollen. Java stellt drei Arten von Kommentaren zur Verfügung: einzeilige, mehrzeilige und Dokumentations-Kommentare.
Kommentare sind eine praktische interne Dokumentation Ihres Programms. Sie können Kommentare einfügen, um zu beschreiben, wie ein bestimmter Teil eines Programms entwickelt wurde, warum eine bestimmte Datenstruktur gewählt wurde oder welche Abhängigkeiten der Code aufweist. Wenn Sie eine externe Dokumentation besitzen, können Sie in Kommentaren darauf verweisen und so interne und externe Dokumentation verknüpfen.
Ein einzeiliger Kommentar kann in einer eigenen Zeile plaziert werden. Er wird durch zwei Schrägstriche (//) am Zeilenanfang gekennzeichnet werden:
// So sieht ein einzeiliger Kommentar aus
Ein einzeiliger Kommentar kann auch am Ende einer Codezeile plaziert werden, hinter dem Semikolon. Das wird manchmal auch als Inline-Kommentar bezeichnet:
x = y; // Dies ist ein Inline-Kommentar
Ein mehrzeiliger Kommentar wird durch eine Kombination aus Schrägstrich und Stern (/*) am Anfang
gekennzeichnet und endet mit einem Ste /* Für diese Berechnung wird die Anzahl der Tage Hier eine alternative Darstellung mehrzeiliger Kommentare:
/* Die Prozedur AvgDailyBal berechnet den durchschnittlichen Beachten Sie, daß die Sterne am Anfang der Mittelzeile in diesem Beispiel nur dem visuellen Effekt dienen.
Sie können einen beliebigen Stil für Ihre mehrzeiligen Kommentare verwenden, solange sie mit /* beginnen
und mit */ enden. Der Compiler ignoriert einfach alles, was zwischen diesen Zeichenpaaren steht.
Dokumentations-Kommentare sind speziell darauf ausgelegt, eine öffentliche Klassendokumentation im
HTLM-Format zu erzeugen. Auch die HTML-Seiten, die Java dokumentieren, wurden unter Verwendung
dieser Technik erzeugt, indem Dokumentations-Kommentare in den Quellcode aufgenommen wurden.
Alles, was zwischen Schrägstrich-Stern-Stern (/**) und Stern-Schrägstrich (*/) steht, wird als Teil dieses
speziellen Kommentars betrachtet. Diese Kommentare werden mit dem Utility javadoc aus dem Code
extrahiert, die auch bestimmte Schlüsselwort-Variablen versteht, die mit dem At-Zeichen (@) beginnen, wie
etwa @author oder @version:
/** Diese öffentliche Klasse soll die Dokumentations-Kommentare werden in der Regel unmittelbar vor der Klassendeklaration plaziert, wie in
diesem Beispiel gezeigt.
Variablen sind Platzhalter mit Namen, in denen während der Programmausführung Werte gespeichert
werden. Bevor Sie eine Variable verwenden können, müssen Sie festlegen, welche Art Wert sie aufnehmen
soll. Das hängt davon ab, welchen Datentyp Sie für die Deklaration der Variablen verwenden. Nachdem
eine Variable deklariert wurde, kann sie durch Zuweisung eines Werts initialisiert und in Ausdrücken
verwendet werden. Bei dem zugewiesenen Wert kann es sich um einen literalen Wert (eine Zahl, einen
Buchstaben oder einen String) oder um das Ergebnis eines Ausdrucks handeln.
Java kennt drei Kategorien von Variablen: Klassenvariablen, Instanzvariablen und lokale Variablen. Alle
drei werden auf dieselbe Weise deklariert. Allerdings erfolgt der Zugriff auf Klassen- und Instanzvariablen
etwas anders als auf lokale Variablen. Klassen- und Instanzvariablen werden in der nächsten Lektion
beschrieben. Heute lernen Sie die lokalen Variablen kennen, die in Methoden deklariert und verwendet
werden.
Wenn Sie eine Variable mit einem bestimmten Datentyp deklarieren, definieren Sie, welche Art von Werten
dort abgelegt werden können. Eine Variable beispielsweise, die mit dem Typ byte deklariert wurde, kann
einen Wert zwischen -128 und 127 aufnehmen. Es gibt acht Wert-Datentypen und zwei
Referenz-Datentypen.
Die acht Werttypen beinhalten Integer-, Fließkomma-, Boolesche und Zeichen-Datentypen, wie in Tabelle
2.1 gezeigt. Sie werden manchmal auch als elementare Typen bezeichnet. Alle Datentypen in Java haben
Standardwerte sowie konsistente Eigenschaften über alle Plattformen hinweg.
Tabelle 2.1: Die Wert-Datentypen von Java
Alle Integer-Typen (byte, short, int, long) sind vorzeichenbehaftet. Fließkomma-Werte (float und double)
folgen dem IEEE-Standard 754 für Zahlen mit einfacher und doppelter Genauigkeit. Neben den normalen
numerischen Werten können Fließkomma-Operationen vier spezielle Werte zurückgeben, die als
Konstanten definiert sind: POSITIVE_INFINITY, NEGATIVE_INFINITY, NEGATIVE_ZERO und
NaN (Not a Number, keine Zahl). Die boolean-Werte werden nicht zu Integern ausgewertet wie in anderen
Sprachen; sie können nur die Werte true oder false darstellen.
Wenn die char-Zeichenwerte etwas seltsam aussehen, dann, weil Java den
Zwei-Byte-Unicode-Zeichenstandard unterstützt. In diesem Buch werden Sie jedoch nur die ASCII- oder
Latin-1-Untermenge der Unicode-Zeichen verwenden.
Die beiden Referenz-Typen nehmen Objekte (in der nächsten Lektion beschrieben) und Arrays auf. Der
Referenz-Typ object kann eine Klasseninstanz aufnehmen und hat den Standardwert null. Der Referenz-Typ
array kann Elemente beliebiger Werte oder Referenz-Typen aufnehmen und hat als Standardwert den
Standardwert für den Elementtyp. Mit anderen Worten, die Elemente eines byte-Arrays haben die
Standardwerte 0, die Elemente eines object-Arrays haben die Standardwerte null.
Ein Variablenname kann mit einem Buchstaben, einem Unterstrich (_) oder einem Dollarzeichen ($)
beginnen und eine beliebige Kombination aus Buchstaben und Ziffern enthalten. Symbole sind
problematisch, weil viele davon in Java-Operatoren verwendet werden. Außerdem ist es empfehlenswert,
nicht den Unterstrich (_) oder das Dollarzeichen ($) als erstes Zeichen zu verwenden, auch wenn das erlaubt
ist, um Konflikte beim Linken von C/C++-Bibliothekn zu vermeiden.
Der De-facto-Standard ist, in Variablennamen nur Buchstaben und Ziffern zu verwenden, wobei das erste
Wort in Kleinbuchstaben dargestellt wird, das zweite und alle folgenden mit einem großen
Anfangsbuchstaben. Eine Variable beispielsweise, die das Rentenalter angibt, könnte als rentenAlter
bezeichnet werden, eine Variable für einen Versicherungshöchstwert als versWertLimit.
Java-Schlüsselwörter können nicht als Variablennamen verwendet werden. Es gibt zwei Schlüsselwörter,
die Tabelle 2.2 aufgelistet sind, die zwar nicht mehr verwendet aber dennoch von Java reserviert werden.
Sie sind durch das Kreuz (†) markiert.
Tabelle 2.2: Java-Schlüsselwörter
Nachdem Sie wissen, welchen Typ und welchen Namen eine Variable haben soll, können Sie sie
deklarieren. Java bietet mehrere Möglichkeiten zur Variablendeklaration, die an einer beliebigen Stelle in der
Methode plaziert werden kann. Eine Variable ist von dem Moment an, wo sie deklariert wurde, bis zur
nächsten schließenden geschweiften Klammer (}) gültig. Hier hört die Variable auf zu existieren und
verschwindet aus dem Gültigkeitsbereich.
short retireAge; Wenn Sie Variablen desselben Typs deklarieren, können Sie sie in einer einzigen Zeile angeben, abgetrennt
durch Kommata. Die drei Variablen der folgenden Deklaration haben alle den Typ short:
short retireAge, birthYear, stdRetireAge;
Um einer Variablen bei der Deklaration einen Ausgangswert zuzuweisen, verwenden Sie das
Gleichheitszeichen (=), den Zuweisungsoperator von Java, gefolgt von dem gewünschten Wert. Die folgende
Deklarationsanweisung initialisiert insValueLimit mit 10000.00:
float insValueLimit = 10000.00;
Sie können mehrere Variablen initialisieren, indem Sie jeder davon einen Wert zuweisen und sie in einzelnen
Zeilen deklarieren. In der folgenden Deklaration werden isInsured und isCurrent mit true initialisiert:
boolean isInsured = true; Alternativ können Sie mehrere Variablen desselben Typs initialisieren, indem Sie sie in dieselbe Zeile
schreiben und durch Kommata voneinander trennen. Jede dieser Möglichkeiten ist korrekt und nur eine
Frage des Geschmacks und des Stils.
boolean isInsured = true, isCurrent = true;
Im nächsten Beispiel werden retireAge und birthYear nicht initialisiert, aber der letzten Variablen,
stdRetireAge, wird der Wert 65 zugewiesen.
short retireAge, birthYear, stdRetireAge = 65;
Variablen können zwar den Standardwert des Typs annehmen, mit dem sie deklariert werden, aber der
Java-Compiler gibt eine Warnung aus, wenn Sie versuchen, eine lokale Variable zu verwenden, ohne sie
zuvor initialisiert zu haben.
Literale werden in Java verwendet, um Werte darzustellen. Im letzten Abschnitt, der die Zuweisung von
Werten an Variablen beschrieb, sind alle zugewiesenen Werte (10000.00, true und 65) Literale.
Die Booleschen Literale in Java können keine Integer-Werte annehmen. Sie werden nur zu true und false
ausgewertet und haben den Typ boolean.
Ein numerisches Literal ist eine beliebige Zahl, die einem Integer- oder Fließkomma-Typ zugewiesen werden
kann. Der Typ eines Literals wird durch spezielle Typbezeichner spezifiziert, die in Klein- oder
Großbuchstaben dargestellt werden können.
Standardmäßig hat ein Integer-Literal wie etwa 8 den Wert int. Wenn ein Integer-Literal jedoch zu lang ist,
um in einen int zu passen, etwa 3000000000 (3 Milliarden), wird automatisch ein long daraus gemacht. Sie
können auch explizit angeben, daß ein Literal ein long sein soll, indem Sie am Ende der Zahl den
Typbezeichner l oder L einfügen: 8L ist ein long-Literal. Alle Integer-Typen können als negative Zahlen
verwendet werden, indem ihnen ein Minuszeichen vorangestellt wird: -78 ist ein negatives int-Literal.
Integer können auch als oktal oder hexadezimal dargestellt werden. Durch Voranstellen einer 0 wird eine
Zahl zu einem oktalen Literal (Basis 8): 0347. Voranstellen von 0x oder 0X gibt an, daß es sich bei der Zahl
um ein hexadezimales Literal (Basis 16) handelt: 0x2FA3. Sie können zwar das oktale oder hexadezimale
Zahlensystem verwenden, um ein Literal darzustellen, aber im Speicher wird es als einer der
Integer-Datentypen abgelegt, entsprechend der Regeln aus dem vorherigen Absatz.
Fließkomma-Literale haben immer den Typ double, egal, welchen Wert sie haben: 5.67 ist ein
double-Literal. Sie können ein Literal zu einem float machen, indem Sie am Ende der Zahl ein f oder F
einfügen: 5.67f wird zu einem float-Literal. Sie können auch die wissenschaftliche Notation verwenden, um
Fließkomma-Literale darzustellen, indem Sie ein e oder E anfügen, gefolgt von dem Exponenten: 5.964e-4
ist die Darstellung von 0.0005964 in wissenschaftlicher Notation, die als double abgelegt wird. Um sie als
float abzulegen, fügen Sie f oder F am Ende des Literals an: 5.964e-4F.
Zeichen-Literale in Java, dargestellt durch Unicode-Zeichen des Datentyps char, werden in einfache
Anführungszeichen eingeschlossen ('), etwa 'a', '*' oder '8'. Nicht-druckbare Zeichen wie etwa der
Tabulator oder Backspace können ebenfalls als Zeichen-Literale dargestellt werden, indem sogenannte
Escape-Codes verwendet werden.
In dieser Darstellung steht das Zeichen d in oktalen Codes für eine Ziffer (0-7), in hexadezimalen und
Unicode-Zeichencodes für eine hexadezimale Ziffer (0-9, a-f, A-F).
Ein String ist einfach nur eine Kombination aus Zeichen-Literalen. Er wird in doppelte Anführungszeichen (»)
eingeschlossen, z.B. "Hello world!". Um einen Null-String darzustellen - d.h. einen String, der keine
Zeichen enthält -, geben Sie einfach das doppelte Anführungszeichen zweimal hintereinander an, also »«.
Es folgt ein Code-Ausschnitt, dessen Anweisungen je ein String-Literal enthalten:
System.out.println("Dieser String gibt\nmehrere Zeilen aus."); In der ersten Zeile wird das \n-Literal verwendet, daß nach dem Wort gibt ein Neuezeile-Zeichen
ausgegeben werden soll. Im zweiten Beispiel wird mit Hilfe des Literals \" ein doppeltes Anführungszeichen
ausgegeben. Die dritte Zeile verendet ein oktales Literal, \11, um die Zahl 9 in der Ausgabe zu erzeugen.
Und so sieht die Ausgabe aus:
Ausdrücke und Operatoren ermöglichen Ihnen, Auswertungen von Daten vorzunehmen.
Jeder Operator hat eine bestimmte Priorität, die angibt, in welcher Reihenfolge er und seine Operanden in
einem Ausdruck ausgewertet werden. Es gibt bei der Arbeit mit Operatoren noch mehrere andere Aspekte
zu berücksichtigen. Es gibt drei Arten von Operatoren: unäre Operatoren, die einen Operanden
entgegennehmen, binäre Operatoren, die zwei Operanden entgegennehmen, und ternäre Operatoren, die
drei Operatoren entgegennehmen. Unäre Operatoren können auch ein Präfix oder Postfix darstellen und so
ganz andere Ergebnisse bewirken. Binäre und ternäre Operatoren sind Infix-Operatoren.
Java kennt zahlreiche Zuweisungsoperatoren, die Sie später in diesem Kapitel noch kennenlernen werden.
Hier müssen Sie nur wissen, daß der Zuweisungsoperator (=) den Wert des Ausdrucks auf der rechten
Seite der Variablen auf der linken Seite zuweist.
Operationen, die numerische Operanden entgegennehmen und numerische Ergebnisse erzeugen, werden als
arithmetische Operationen bezeichnet. Die unären Operatoren beinhalten Inkrement, Dekrement, Plus und
Minus. Die binären Operatoren umfassen Addition, Subtraktion, Multiplikation, Division und Modulo. Es
gibt sogar eine arithmetische binäre Operation für Strings, die sogenannte Konkatenation.
Die Inkrement- (++) und Dekrement-Operatoren (--) sind sowohl unäre Präfix- als auch unäre
Postfix-Operatoren. Wenn der Operator vor dem Operanden steht (Präfix), erfolgt die Operation, bevor Ihr
Programm den resultierenden Wert weiterverwendet. Wenn der Operator hinter dem Operanden steht
(Postfix), verwendet Ihr Programm den Wert und führt dann erst die Operation aus. Bei der
Inkrementierung eines Werts wird 1 addiert, bei der Dekrementierung wird 1 subtrahiert. Mit anderen
Worten, die Ausdrücken in den beiden:
myAge = myAge + 1; stellen dieselben Werte dar wie die beiden folgenden Ausdrücke:
myAge++; Der Wert kann ein Integer- oder Fließkomma-Wert sein oder ein beliebiger Ausdruck, der einen dieser
numerischen Typen ergibt.
Betrachten Sie beispielsweise den folgenden Programmausschnitt:
int x, y, z = 7; Die Variable z wird zuerst inkrementiert, anschließend wird das Ergebnis, 8, der Variablen x zugewiesen.
Weil z jetzt 8 ist, wird auch y dieser neue Wert zugewiesen. Betrachten Sie jetzt den folgenden
Programmausschnitt:
int x, y, z = 7; Der Wert der Variablen z, wird x zugewiesen. Anschließend wird z inkrementiert und enthält jetzt den Wert
8. Weil z gleich 8 ist, erhält y ebenfalls den Wert 8.
Um einem numerischen Wert oder einem Ausdruck ein Vorzeichen zu geben, stellen Sie ihm einfach das
unäre Plus (+) für positive Zahlen oder das unäre Minus (-) für negative Zahlen voraus. Hier ein Beispiel:
int x, y = +4, z = -7; Diese Gruppe der binären Infix-Operatoren führt die grundlegenden mathematischen Operationen aus, wie
etwa Addition (+), Subtraktion (-), Multiplikation (*), Division (/) und Modulo (%). Die Operationen
werden im folgenden gezeigt:
int x, y = 28, z = 8; Der Divisions-Operator (/) verwirft den Rest der Division und gibt nur den Integer-Bestandteil als Ergebnis
zurück. Der Modulo-Operator (%) gibt nur den Rest der Division als Ergebnis zurück.
Wie kann man Strings addieren? Durch Konkatenation (+) mit dem binären Infix-Operator:
string helloWorld, hello = "Hello", space = " ", world = "World"; string helloWorld = "Hello World!"
Dem Konkatenations-Operator (+) können Sie beliebige Strings oder Zeichen-Literale als Operanden
übergeben.
Alle relationalen Operatoren geben ein Boolesches Ergebnis zurück. Der Ausdruck, den der Operator und
seine Operanden bilden, ist entweder true oder false. Diese Operatoren werden auch als
Vergleichsoperatoren bezeichnet. Neben arithmetischen Werten können Sie auch Objekte und Typen
vergleichen.
Die arithmetischen relationalen Operatoren sind Kleiner (<), Kleiner-Gleich (<=), Größer (>),
Größer-Gleich (>=), Gleich (==) und Ungleich (!=). Hier einige Beispiele für ihre Arbeitsweise:
int w = -8, x = -9, y = 28, z = 8; Es gibt auch relationale Operatoren für den Vergleich von Objekten: Typvergleich (instanceof),
Bezieht-sich-auf-dasselbe-Objekt (==) und Bezieht-sich-auf-ein-anderes-Objekt (!=). Diese beiden letzten
Operatoren sehen aus wie die oben gezeigten Operatoren für den Vergleich auf Gleichheit (==) und
Ungleichheit (!=), aber sie nehmen Objekte als Operanden entgegen.
Der Typvergleichs-Operator (instanceof) stellt fest, ob das Objekt im linken Operanden eine Instanz des
Typs des rechten Operanden ist (oder die Schnittstelle implementiert). Ist dies der Fall, ist das Ergebnis
gleich true, andernfalls oder wenn das Objekt null ist, ist das Ergebnis false.
Der Bezieht-sich-auf-dasselbe-Objekt-Operator (==) stellt fest, ob das Objekt im linken Operanden auf
dieselbe Instanz verweist wie das Objekt im rechten Operanden. Wenn das der Fall ist, ist das Ergebnis
gleich true, andernfalls ist es false.
Der Bezieht-sich-auf-ein-anderes-Objekt-Operator (!=) stellt fest, ob das Objekt im linken Operanden auf
eine andere Instanz als das Objekt im rechten Operanden verweist. Wenn das der Fall ist, ist das Ergebnis
gleich true, andernfalls ist es false.
Logische Operatoren nehmen Boolesche Operanden entgegen und geben ein Boolesches Ergebnis zurück.
Es gibt einen unären logischen Präfix-Operatoren: Logisch NICHT (!). Fast alle anderen sind binäre
Infix-Operatoren: logisch UND (&), logisch ODER (|), logisch XODER (^), bedingtes UND (&&) und
bedingtes ODER (||). Schließlich gibt es noch einen ternären Infix-Operator: if-else (?:).
Das logische NICHT (!) wechselt einfach den Booleschen Wert, dem es vorangestellt wird. Ist der
Operand true, ist das Ergebnis false, ist der Operand false, ist das Ergebnis true, also einfach immer das
Gegenteil.
Der logische UND-Operator (&) wertet beide Operanden aus. Sind beide true, ist das Ergebnis true. Ist
einer der Operanden false, ist das Ergebnis false. Der logische ODER-Operator (|) stellt fest, ob einer der
beiden Operanden gleich true ist, dann ist das Ergebnis true, wenn beide false sind, ist das Ergebnis false.
Der logische XODER-Operator (^) stellt fest, ob die Operanden unterschiedlich sind; einer muß true sein,
der andere muß false sein, und wenn das so ist, ist das Ergebnis true; sind beide true oder beide false, ist
das Ergebnis false. Tabelle 2.4 zeigt diese Ergebnisse.
Tabelle 2.4: Logische Boolesche Operationen und Ergebnisse
Der bedingte UND-Operator (&&) und der bedingte ODER-Operator (||) sind gleich dem logischen UND
(&) und ODER (|), aber die Auswertung erfolgt etwas anders.
Der bedingte UND-Operator (&&) stellt zuerst fest, ob der linke Operand false ist. In diesem Fall ist das
Ergebnis false und die Auswertung wird beendet. Wenn der linke Operand true ist, wird auch der rechte
Operand ausgewertet. Ist der rechte Operand ebenfalls true, ist das Ergebnis true, ist er false, ist das
Ergebnis false.
Der bedingte ODER-Operator (||) stellt zuerst fest, ob der linke Operand true ist. In diesem Fall ist das
Ergebnis true und die Auswertung wird beendet. Wenn der linke Operand false ist, wird auch der rechte
Operand ausgewertet. Wenn der rechte Operand true ist, ist das Ergebnis true, ist er false, ist das Ergebnis
false.
Der ternäre bedingte Infix-Operator (?:) ist eine Abkürzung für die if-else-Anweisung. Wenn der erste
Operand gleich true ist, wird der zweite Operand ausgewertet/ausgeführt, andernfalls der dritte Operand:
isInsured ? payClaim() : doNothing();
Wenn in diesem Beispiel isInsured gleich true ist, wird die Methode payClaim() aufgerufen. Ist isInsured
false, wird die Methode doNothing() aufgerufen. Mehr über Methodenaufrufe erfahren Sie in der nächsten
Lektion.
Bitweise Operationen manipulieren die Bits im Speicherraum der Variablen. Bitweise Operatoren nehmen
Integer-Operanden entgegen und geben ein Integer-Ergebnis zurück. Es gibt einen unären bitweisen
Präfix-Operator: bitweise NICHT (˜). Alle anderen sind binäre Infix-Operatoren: bitweises UND (&),
bitweises ODER (|), bitweises XODER (^), bitweiser Linksshift (<<), vorzeichenbehafteter Rechtsshift (>>)
und Rechtsshift mit Auffüllen durch Nullen (>>>).
Der bitweise NICHT-Operator (˜) wechselt einfach die Bits des Integer-Werts, dem er vorausgestellt
wird. Wenn der Integer-Wert beispielsweise 00101001 ist, würde die Anwendung des NICHT-Operators
(˜) den Integer-Wert 11010110 ergeben.
In einer Programmanweisung wären die beiden Integer-Werte links und rechts vom bitweisen Operator
angesiedelt, des besseren Vergleichs halber ist es aber besser, sie in einem Spaltenformat zu zeigen. Für das
bitweise UND (&), das bitweise ODER (|) und das bitweise XODER (^) vergleichen Sie die Bits gleicher
Positionen im Integer-Wert. Betrachten Sie beispielsweise die beiden folgenden Zahlen:
Das erste Paar ist (0,1), das zweite Paar ist (0,1) und das dritte Paar ist (1,1). Sie müssen die Paare vertikal
in den Spalten bilden, so daß Sie jeweils dieselben Positionen für den Vergleich heranziehen. In diesem
Beispiel stellt die Zahl 00101001 den linken Operanden, die Zahl 11101110 den rechten Operanden dar.
Tabelle 2.5 zeigt die Ergebnisse der möglichen Bit-Paarungen in bitweisen Operationen.
Tabelle 2.5: Bitweise Operationen und ihre Ergebnisse
Die bitweisen Shift-Operatoren sind bitweiser Linksshift (<<), vorzeichenbehafteter Rechtsshift (>>) und
Rechtsshift mit Auffüllen durch Nullen (>>>). Diese Operatoren nehmen als linken Wert einen Integer-Wert
entgegen, als rechten Operanden ein numerisches Literal, das angibt, um wie viele Stellen geshiftet werden
soll.
Der bitweise Linksshift (>>) verschiebt jede Ziffer im Integer-Wert in dem linken Operanden um so viele
Stellen nach links, wie das numerische Literal im rechten Operand angibt. Beim Verschieben »fallen« die
Ziffern links heraus und rechts werden Nullen eingefügt, um die neue Zahl zu bilden. Weil das Vorzeichen
herausfällt, wenn Sie nach links verschieben, sollten Sie bei der Verwendung dieses Operators vorsichtig
sein.
Der vorzeichenbehaftete Rechtsshift (>>) verschiebt jede Ziffer im Integer-Wert im linken Operanden um so
viele Stellen nach rechts, wie im rechten Operanden angegeben. In diesem Fall geht das Vorzeichen jedoch
nicht verloren. Der Inhalt der ganz linken Position bleibt unverändert und die Zahl wird links mit dem Wert
der linken Ziffer aufgefüllt.
Wenn Sie links explizit mit Nullen auffüllen wollen, verwenden Sie den Rechtsshift-Operator mit Auffüllen
durch Nullen (>>>). Weil diese Operation immer Nullen einfüllt, behält sie das Vorzeichen nicht bei.
Java bietet zahlreiche Zuweisungsoperatoren. Der grundlegende Zuweisungsoperator (=) wird durch
mehrere Operatoren übernommen, die Ihnen eine gleichzeitige Operation und Zuweisung ermöglichen. Sie
haben die Form op=, wobei op ein Operator aus der folgenden Menge sein kann:
{ *, /, %, +, -, <<, >>, >>>, &, ^, | }
Statt also beispielsweise die folgenden Anweisungen zu verwenden:
totalCharges = totalCharges + newItemPrice; könnten Sie auch folgendes schreiben:
totalCharges += newItemPrice; Sie nehmen dieselben Operationen vor. Diese Zuweisungsoperatoren können viel Zeit sparen, wenn Sie sehr
lange Namen verwenden, und außerdem wird Ihr Code besser lesbar.
Sie haben jetzt alle Operatoren von Java kennengelernt, aber es bleibt noch ein Aspekt zu berücksichtigen.
Die Priorität der Operatoren legt fest, in welcher Reihenfolge die Argumente eines Ausdrucks ausgewertet
werden. Tabelle 2.6 zeigt die einzelnen Operatoren, aufgelistet ihrer Priorität nach, zusammen mit dem
Operandentyp, den sie entgegennehmen, der ausgeführten Operation sowie der Plazierung des Operators im
Ausdruck. Betrachten Sie beispielsweise den folgenden Programmausschnitt:
int g, x = 6, y = 7, z = 8; Hier ist die Multiplikation von y und z zuerst ausgeführt und ergibt 56. Das Ergebnis wird zu x addiert, was
62 ergibt. Dieses Ergebnis schließlich wird g zugewiesen. Aber was sollten Sie tun, wenn Sie x und y zuerst
addieren und dann mit z multiplizieren wollen? Mit Hilfe von Klammern können Sie die
Auswertungsreihenfolge beeinflussen:
int g, x = 6, y = 7, z = 8; In diesem Fall werden zuerst x und y addiert, ergeben 13, und dieser Wert wird mit z multipliziert, was 104
ergibt. Dieser Wert wird schließlich g zugewiesen. Operatoren derselben Prioritätsstufe werden von links
nach rechts ausgewertet, außer verschachtelte unäre und ternäre Operatoren, die von rechts nach links
ausgewertet
Tabelle 2.6: Operatorpriorität
Neben diesen Operationen gibt es noch zahlreiche mathematische Konstanten und Operationen, die in der
Klasse java.math.lang definiert sind. Diese Funktionen können in diesem Buch nicht erklärt werden. Es gibt
Konstantenwerte für e und Pi, trigonometrische Funktionen (Sinus, Cosinus, Tangens, Arkussinus,
Arkuscosinus, Arkustangens) sowie Funktionen für exponentielles E, den natürlichen Logarithmus,
Quadratwurzel, IEEE-Rest, Oberwert, Unterwert, Umwandlung in Polarkoordinaten, Exponenten,
Rundung, Zufallszahlen, Absolutwert, Maximum und Minimum.
Arrays sind eines der praktischsten Konstrukte in Java. Sie ermöglichen Ihnen, Objekte oder elementare
Typen in einfach zu verwaltenden Strukturen zusammenzufassen. Strings sind ein Sonderfall von Arrays und
voll-funktionale Objekte in Java. In diesem Abschnitt lernen Sie, diese Objekte zu erzeugen und zu
manipulieren.
In Java werden Arrays als voll-funktionale Objekte implementiert, sie können also auch wie Objekte
verglichen oder manipuliert werden. Weil Arrays echte Objekte sind, haben sie Konstruktoren, Methoden
und Variablen, die speziell für die Verwendung in Arrays geschaffen wurden.
Um in Java ein Array zu erzeugen, gehen Sie in drei Schritten vor:
Der erste Schritt beim Erzeugen eines Arrays ist, eine Variable zu erzeugen, die das Array aufnimmt. Die
Deklaration von Array-Variablen kann eines von zwei gleichermaßen möglichen Formaten annehmen. Beide
Formate geben den Namen des Array an, den Typ der Objekte, die das Array aufnimmt, sowie ein leeres
Klammernpaar ([]), das anzeigt, daß es sich bei der neuen Variablen um ein Array handelt. Hier einige
typische Deklarationen von Array-Variablen:
int[] theTenBestGameScores; Die erste Deklaration gibt an, daß Sie ein Array des Typs int mit dem Namen theTenBestGameScores
deklarieren. Die zweite deklariert ein Array vom Typ Date namens games. Die dritte deklariert ein int-Array
namens averageRBI.
Wie Sie sehen, können die Klammern ([]) vor dem Typ oder nach dem Variablennamen angegeben werden.
Der Java-Compiler akzeptiert beide Formen und die beiden Deklarationsstile können einfach kombiniert
werden. Wenn die Klammern unmittelbar hinter dem Typ angegeben werden, sehen Sie sofort, daß Sie ein
Array dieses Typs deklarieren. Der Java-Quellcode verwendet das in den beiden letzten Beispielen gezeigte
Format, das Buch folgt deshalb diesem Standard und plaziert die Klammern unmittelbar hinter dem
Variablennamen.
Im zweiten Schritt erzeugen Sie ein Array-Objekt und weisen es dieser Variablen zu. Es gibt zwei
Möglichkeiten, das zu realisieren:
Wenn Sie ein Array-Objekt mit new erzeugen, müssen Sie explizit angeben, wie viele Elemente das Array
aufnehmen soll:
Damit wird ein neues Array mit Integern mit 10 Elementen erzeugt. In diesem Fall wird jedes der 10
Elemente im Integer-Array mit dem Wert 0 initialisiert. Der initialisierte Wert hängt von dem Arraytyp ab,
den Sie angelegt haben, wie in Tabelle 2.7 gezeigt.
Tabelle 2.7: Standardwerte für die Array-Initialisierung
Sie können ein Array auch gleichzeitig erzeugen und initialisieren, wie das auch für andere Variablen möglich
ist. Statt new zu verwenden, um das Array-Objekt zu erzeugen, schließen Sie die Elemente des Arrays in
geschweifte Klammern ein, getrennt durch Kommata, die die Ausgangswerte darstellen:
float rates[] = { 12.9, 14.5, 16.5, 18.95, 23.0 };
Die Elemente innerhalb der geschweiften Klammern müssen denselben Typ haben wie die Variable, die das
Array aufnimmt. Das Array wird mit einer Anzahl von Einträgen erzeugt, die mit der Anzahl der hier
übergebenen Elemente übereinstimmt. In diesem Beispiel wird also ein Array mit fünf float-Elementen
angelegt und es erhält den Namen rates. Das erste Elemente im Array hat den Wert 12.9, das zweite hat
den Wert 14.5 usw.
Ein Versuch, den falschen Datentyp in einem Array abzulegen, verursacht einen Compiler-Fehler. Die
folgende Codezeile beispielsweise würde bewirken, daß sich der Compiler über einen Typfehler beschwert:
float rates[] = { 'M', 'i', 'a', 'm', 'i' };
Ein Versuch, zur Laufzeit einen falschen Typ im Array abzulegen, verursacht eine ArrayStoreException.
Um das Array für die oben gezeigten Werte korrekt zu deklarieren, müßten Sie ein Array vom Typ char
anlegen:
char chArr[] = { 'M', 'i', 'a', 'm', 'i' };
Nachdem Sie ein Array initialisiert haben, können Sie die Werte in den einzelnen Array-Einträgen auswerten
und ändern. Um auf einen Wert zuzugreifen, der in einem Array gespeichert ist, verwenden Sie den
Index-Ausdruck für das Array.
arrayName ist die Variable, die das Array-Objekt aufnimmt. Der Index ist ein Integer oder ein
Integer-Ausdruck, der den Eintrag des Arrays bestimmt, auf den zugegriffen werden soll.
Betrachten wir das Beispiel noch einmal:
float rates[] = { 12.9, 14.5, 16.5, 18.95, 23.0 };
Hier folgt ein Code-Ausschnitt, der zeigt, wie diese Werte anderen Variablen zugewiesen werden könnten:
float platinumRate == rates[0]; // Der Wert ist 12.9 Alle Array-Indizes werden überprüft, um sicherzustellen, daß sie innerhalb der Array-Grenzen liegen. Sie
müssen also größer oder gleich Null sein, aber kleiner als die Array-Länge. Diese Prüfung findet beim
Kompilieren Ihres Java-Programms oder bei seiner Ausführung statt. In Java ist es nicht möglich, auf einen
Wert in einem Array-Eintrag zuzugreifen, der außerhalb der Array-Grenzen liegt. Betrachten Sie die beiden
folgenden Anweisungen:
int myArr[] = new int[10]; Ein Programm mit dieser Anweisung erzeugt in der zweiten Zeile einen Compiler-Fehler, wenn Sie
versuchen, es zu kompilieren. Das Array in myArr hat nur 10 Einträge, numeriert von 0 bis 9. Das Element
am Index 10 würde in Eintrag Nummer 11 vorliegen, der nicht existiert, deshalb beschwert sich der
Java-Compiler.
Wenn der Array-Index zur Laufzeit berechnet wird (beispielsweise innerhalb einer Schleife) und außerhalb
der Array-Grenzen liegt, erzeugt der Java-Interpreter eine ArrayIndexOutOfBoundsException. Wenn Sie
zur Laufzeit versuchen, ein Array mit weniger als Null Elementen zu allozieren (indem Sie etwa einen
Index-Ausdruck verwenden, der eine negative Zahl ergibt), erhalten Sie eine NegativeArraySizeException.
Um zu vermeiden, daß in Ihren eigenen Programmen versehentlich über das Array-Ende hinaus zugegriffen
wird, ermitteln Sie die Anzahl der Array-Elemente, indem Sie seine Instanzvariable length auswerten. Diese
Variable ist für alle Array-Objekte definiert, unabhängig von deren Typ:
int len = arr.length; // ergibt 10
Um den Wert eines Array-Elements zu verändern, geben Sie einfach hinter dem Array-Zugriffsausdruck
eine Zuweisung an. Hier zwei Beispiele:
myArr[1] = 15; Arrays elementarer Typen wie etwa int oder float können Werte von einem Eintrag in einen anderen
kopieren. Ein Array mit Objekten ist jedoch in Java ein Array mit Verweisen auf diese Objekte (irgendwie
ähnlich den Zeigern). Wenn Sie einem Array-Eintrag einen Wert hinzufügen, erzeugen Sie damit einen
Verweis auf dieses Objekt, so wie für eine einfache Objekt-Variable. Wenn Sie ein Array-Objekt einem
anderen zuweisen, wie etwa in der folgenden Codezeile:
dann weisen Sie einfach den Verweis noch einmal zu. Sie kopieren nicht den Wert von einem Eintrag in
einen anderen. Nachdem diese Codezeile ausgeführt ist, zeigen sentence[10] und sentence[0] auf dieselbe
Speicherstelle.
Arrays mit Verweisen auf Objekte sind im Gegensatz zu den Arrays mit den Objekten selbst besonders
praktisch, weil sie Ihnen ermöglichen, mehrere Verweise auf dieselben Objekte sowohl innerhalb als auch
außerhalb der Arrays zu verwenden. Sie können beispielsweise ein Objekt, das in einem Array enthalten ist,
einer Variablen zuweisen und auf dieses Objekt über die Variable oder über seine Array-Position zugreifen.
In java.lang.System gibt es die Methode arraycopy(), die Ihnen ermöglicht, Daten von einem Array in ein
anderes zu kopieren. Die Syntax für diese Methode lautet:
arraycopy(srcArr, srcOffset, dstArr, dstOffset, copyLength)
Die Argumente sind wie folgt definiert:
Diese Methode alloziert keinen Speicher, das Ziel-Array muß also bereits existieren.
Java unterstützt mehrdimensionale Arrays. Man kann sich ein mehrdimensionales Arrays ganz einfach als
Array mit Arrays vorstellen. In Java deklarieren Sie ein Array mit Arrays (und diese Arrays können
wiederum Arrays enthalten usw.) und greifen auf ihre Elemente zu, indem Sie für jede Dimension einen Index
spezifizieren. Hier folgt ein Beispiel für ein zweidimensionales Array mit Koordinaten:
int coords[][] = new int[12][12]; Mehrdimensionale Arrays können beliebig viele Dimensionen haben, für die Sie jeweils nur ein neues
Klammernpaar ([]) einfügen müssen. Hier folgt ein Beispiel für eine sechsdimensionale Arraydeklaration:
int sixDimArr[][][][][][] = new int [2][4][8][3][][];
In diesem Beispiel wird den ersten vier Dimensionen explizit eine Größe zugewiesen, den beiden letzten
dagegen nicht. Der Speicher wird für die ersten vier Dimensionen alloziert. Die beiden letzten Dimensionen
werden erst später bei der Initialisierung alloziert. Sie können beliebig viele Dimensionen mit explizit
definierter Größe angeben, gefolgt von beliebig vielen Dimensionen ohne Größenangabe, aber in eben dieser
Reihenfolge. Das folgende ist in Java nicht erlaubt:
int threeDimArr[][][] = new int [3][][3]; // invalid
Außerdem müssen die einzelnen Teil-Arrays eines mehrdimensionalen Arrays nicht dieselbe Größe haben.
Betrachten Sie das folgende Beispiel:
byte threeDimByteArr[][][] = new byte [2][4][3];
Dieses Array enthält acht Teil-Arrays, die jeweils drei byte-Elemente enthalten. Das Array threeDimByteArr
enthält zwei Elemente, die Teil-Arrays sind. Diese beiden Teil-Arrays haben je vier Elemente, bei denen es
sich ebenfalls um Teil-Arrays handelt. Diese vier Teil-Arrays haben je drei byte-Elemente. Sie können
mehrdimensionale Arrays auch durch die Vorgabe literaler Werte deklarieren, etwa wie folgt:
String encryptStrArr[][] = new String { Dieses Beispiel erzeugt ein mehrdimensionale String-Array, das vier Teil-Arrays mit 5, 2, 4 und 2
String-Elementen alloziert.
In diesem Abschnitt werden Sie erfahren, wie man Strings deklariert und erzeugt, wie man auf
String-Elemente zugreift und wie die Methoden zur String-Manipulation eingesetzt werden. Darüber hinaus
werden Sie die Klasse StringBuffer kennenlernen.
Die Klasse String repräsentiert konstante Strings. Die String-Klasse stellt einige grundlegende Methoden zur
Manipulation bereit, aber das Ergebnis muß immer einem zweiten String-Objekt zugeordnet werden. Jede
Änderung in einem String-Wert macht eine Zuweisung an einen StringBuffer erforderlich. Die Klasse
StringBuffer ermöglicht Ihnen, Strings direkt zu manipulieren und das Ergebnis der StringBuffer-Variablen
zuzuweisen. Dazu muß in der Regel mehr Speicher alloziert werden, deshalb sollten Sie überall wo es
möglich ist, String-Objekte verwenden.
Die Deklaration einer String- oder StringBuffer-Variablen ist ganz einfach:
String myString; Die Deklaration der Variablen setzt einfach nur den Namen. Für das StringBuffer- oder String-Objekt wird
kein Speicher alloziert. Dazu müssen Sie es unter Verwendung eines String-Literals oder eines
Konstruktoraufrufs initialisieren.
Weil Strings so häufig verwendet werden, definiert die Klasse String in Java mehrere Abkürzungen, damit
Strings ohne den expliziten Aufruf eines Konstruktors aufgerufen werden können. Die gebräuchlichste
Methode zur Allozierung eines String-Objekts ist, der deklarierten Variablen ein String-Literal zuzuweisen:
myString = "Wir sehn uns am Samstag.";
Es werden so viele Zeichen alloziert, wie im Literal enthalten sind. Eine andere Möglichkeit, einen neuen
String zu erzeugen, ist die Verwendung einer der valueOf()-Methoden, um einen Wert eines anderen Typs,
etwa einen Integer, in sein Textäquivalent zu konvertieren:
myString = String.valueOf(17);
Damit wird ein String erzeugt, der zwei Zeichen enthält, 1 und 7. Die Methode valueOf() kann elementare
Typen (boolean, char, int, long, float, double), den Object-Typ sowie char-Arrays konvertieren. Für
char-Arrays stellt die Methode valueOf() zwei Methodensignaturen bereit: eine, die das gesamte Array als
Parameter entgegennimmt, und eine zweite, die ein char-Array, einen Offset sowie einen Zähler als
Parameter entgegennimmt. Hier ein Beispiel für die zweite Methode:
char chArr[] = { 's', 'p', 'o', 'r', 't', 's' }; Dadurch wird ein String namens chString erzeugt, der die in chArr definierten Zeichen enthält, beginnend an
Position 1 (dem Offset) und über 4 Zeichen gehend (dem Zähler). Das resultiert schließlich in dem Wert
port.
Beachten Sie, daß diese Techniken zum Erzeugen von String-Objekten keine explizite Verwendung eines
Konstruktors erforderlich machen. Darüber hinaus definiert die String-Klasse mehrere Konstruktoren, aus
denen Sie auswählen können. Hier einige der gebräuchlicheren Beispiele:
Hier sehen Sie den Standard-Konstruktor, der keine Parameter entgegennimmt:
Er erzeugt ein String-Objekt mit dem Namen strl1 und der Länge length gleich 0.
Dieser Konstruktor nimmt ein String-Literal als Parameter entgegen:
String str2 = new String("Guten Tag");
Er erzeugt das String-Objekt str2 mit dem Wert Guten Tag und einer Länge length von 9.
Der nächste nimmt ein chArr als Parameter entgegen:
char chArr[] = { 'S', 'a', 'm', 's' }; Er erzeugt das String-Objekt str3 mit dem Wert Sams und einer Länge length von 4. (Diese Methode ist im
Ergebnis identisch mit der valueOf()-Methode, die ein char-Array als Parameter entgegennimmt.)
Der nächste nimmt ein char-Array, einen Offset und einen Zähler als Parameter entgegen:
char chArr[] = { 'I', 'n', 't', 'e', 'r', 'n', 'e', 't' }; Er erzeugt das String-Objekt str4 mit dem Wert net und einer Länge length von 3. Dieses Ergebnis wird
beginnend an Offset 5 in chArray und über einen Zähler von 3 Zeichen ermittelt. (Diese Methode ist im
Ergebnis identisch mit der valueOf()-Methode, die ein char-Array, einen Offset und einen Zähler als
Parameter entgegennimmt.)
Der hier folgende letzte Konstruktor nimmt einen StringBuffer als Parameter entgegen:
String str5 = new(myStringBuff);
Er erzeugt das String-Objekt str5 mit dem Inhalt von myStringBuff.
Der Zugriff auf die Elemente eines Strings erfolgt auf dieselbe Weise wie der Zugriff auf Array-Elemente,
und Sie können Integer oder Integer-Ausdrücke als Indizes verwenden, die auf die einzelnen Elemente des
String-Arrays verweisen. Wenn ein String-Index zur Laufzeit außerhalb der Grenzen des Arrays liegt, wirft
der Java-Interpreter eine StringIndexOutOfBoundsException auf.
Hier folgt ein Beispiel für eine for-Schleife, die alle Werte eines Strings mit dem Zeichen A initialisiert, indem
sie auf die einzelnen Array-Elemente zugreift:
String aString[] = new String[3]; Neben dem Zugriff auf die Zeichen als Array-Elemente definiert die String-Klasse mehrere Methoden, die
den Zugriff auf die Werte in Strings vereinfachen sollen. Die Klasse AccessString in Listing 2.1 zeigt einige
dieser Methoden.
Listing 2.1: AccessString.java
1: class AccessString { Nachdem Sie dieses Programm kompiliert und ausgeführt haben, sehen Sie die folgende Ausgabe im
Ausführungsprotokoll-Fenster:
String str = "Hello"; Wenn Sie versuchen, die erste Form zu verwenden, um diese Aufgabe auszuführen, müßten Sie einen
Anfang inklusive Index 3, aber ein Ende exklusive Index 5 angeben. Das wirft aber eine Ausnahme auf, weil
die gültigen Indizes für str nur von 0 bis 4 reichen.
Es gibt noch andere Methoden, die mehrere Formen besitzen (wie etwa indexOf() oder lastIndexOf()), aber
für dieses Beispiel wurde für jede Methode nur eine Form gezeigt. Detailliertere Informationen entnehmen
Sie der Online-Dokumentation für das String-Objekt.
Die String-Klasse bietet Methoden für den Vergleich und die Manipulation von Strings. Wenn Objekte
verglichen werden, wird ein Boolescher Wert zurückgegeben, der angibt, ob die beiden Objekt-Variablen
auf dasselbe Objekt im Speicher verweisen. Wenn Sie zwei String-Literale mit demselben Wert definieren,
verweisen diese auf dieselbe Speicherstelle.
Angenommen, Sie haben new verwendet, um zwei separate Strings zu erzeugen, wie können Sie diese dann
vergleichen? Die Klasse String definiert drei Vergleichsmethoden für diesen Zweck. Die erste Methode,
equals(), berücksichtigt die Groß-/Kleinschreibung, vergleicht die entsprechenden Zeichen aus beiden
Strings und ergibt true, wenn sie identische Werte aufweisen. Darüber hinaus definiert die Klasse String auch
noch eine Version, die die Groß-/Kleinschreibung nicht berücksichtigt, equalsIgnoreCase(), die die
entsprechenden Zeichen ohne Rücksicht darauf vergleicht, ob es sich um Groß- oder Kleinbuchstaben
handelt.
Eine dritte Vergleichsmethode, compareTo(), vergleicht zwei Strings und gibt einen Integerwert zurück, der
den numerischen Unterschied zwischen beiden zurückgibt:
Die Integer-Unicode-Werte der jeweiligen Zeichenpaare werden verglichen, bis eines gefunden wird,
dessen Werte nicht übereinstimmen (die weiteren Zeichen werden ignoriert). In diesem Beispiel stimmt das
erste Zeichenpaar, J und C, nicht überein, und weil die Methode von firstStr aufgerufen wird, subtrahiert die
compareTo()-Methode den Integerwert für C (99) von dem für J (106). Das Ergebnis ist 7, ein positiver
Integer, der anzeigt, daß JBuilder größer als C++Builder ist (wenigstes hinsichtlich des Strings). Ein
negativer Integer weist darauf hin, daß der aufrufende String kleiner als der übergebene String ist. Null zeigt
an, daß die beiden Strings gleich sind.
Strings, von denen Sie wissen, daß sie irgendwann manipuliert werden, sollten zwar in
StringBuffer-Objekten untergebracht werden, aber die Klasse String definiert auch ein paar Techniken zum
Ändern von String-Objekt-Werten. Sie können das Ergebnis jedoch nicht dem ursprünglichen String
zuweisen, sondern Sie müssen einen neuen String definieren, der das Ergebnis dieser Methoden aufnimmt.
Unter anderem handelt es sich um concat(), replace(), trim(), toLowerCase() und toUpperCase().
Die Klasse ChangeString in Listing 2.2 zeigt die Verwendung einiger dieser Methoden.
Listing 2.2: ChangeString.java
1: class ChangeString { Nachdem Sie das Programm kompiliert und ausgeführt haben, sollten Sie die folgende Ausgabe erhalten:
Beachten Sie, daß Java für die Stringkonkatenation den Konkatenations-Operator (+) bereitstellt.
In java.lang.String sind noch weitere Methoden definiert, die hier nicht beschrieben wurden, unter anderem
copyValueOf(), getBytes(), hashCode(), intern() und regionMatches(). Detailliertere Informationen
entnehmen Sie bitte der Online-Java-Referenz des JBuilder.
Für ein StringBuffer-Objekt gibt es neben der Länge length, die angibt, wie viele Zeichen es enthält, auch die
Methode capacity, die angibt, für wie viele Zeichen der Puffer alloziert wurde. Um ein StringBuffer-Objekt
zu erzeugen, verwenden Sie einen der drei Klassen-Konstruktoren, z.B.:
StringBuffer myStrBuff = new StringBuffer(myString);
Dieser Konstruktor nimmt einen String-Parameter entgegen. Er erzeugt den StringBuffer myStrBuff, der den
Inhalt eines Strings namens myString beinhaltet, dessen Länge gleich dem Wert length von myString gesetzt
wird. capacity wird dynamisch alloziert. Für den String-Parameter können Sie auch ein String-Literal
verwenden.
Dieser Konstruktor nimmt keine Parameter entgegen und ist der Standard:
StringBuffer myStringBuff = new StringBuffer();
Er erzeugt den StringBuffer myStringBuff mit einer length von Null. Auch hier wird capacity dynamisch
alloziert.
Der folgende Konstruktor nimmt einen Integer-Parameter entgegen, der length und capacity des
StringBuffer darstellt:
StringBuffer aBuff = new StringBuffer(25);
Dieses Beispiel erzeugt den StringBuffer aBuff mit einer zunächst statisch allozierten capacity von 25,
initialisiert mit Leerzeichen und einer length von 0.
Der Zugriff auf einzelne Elemente von StringBuffer-Objekten kann unter Verwendung von Indizes erfolgen,
so wie in allen anderen Arrays. Weil StringBuffer jedoch wirklich Objekte sind, definiert die Klasse
StringBuffer eigene Methoden, die die Anzahl der Zeichen im Puffer, die Anzahl der Zeichen, die der Puffer
aufnehmen kann, sowie das Zeichen an einer bestimmten Position zurückgeben können. Die Klasse
AccessBuffer aus Listing 2.3 demonstriert diese Methoden.
Listing 2.3: AccessBuffer.java
1: class AccessBuffer { Wenn Sie das Programm kompilieren und ausführen, sollten Sie die folgende Ausgabe erhalten:
The contents of aBuff: Time flies! Die Klasse StringBuffer stellt mehrere Methoden zur Manipulation des Pufferinhalts zur Verfügung. Unter
anderem handelt es sich dabei um setLength(), setCharAt(), append(), insert(), reverse() und toString(). Im
Gegensatz zu String-Objekten, wo das Ergebnis einer String-Manipulation einer zweiten String-Variablen
zugewiesen werden muß, kann ein StringBuffer-Objekt das Ergebnis der Methode direkt dem aufrufenden
StringBuffer zuweisen. Die Klasse ChangeBuffer in Listing 2.4 zeigt diese Methoden zur Manipulation von
Puffern, die in der Klasse StringBuffer definiert sind.
Listing 2.4: ChangeBuffer.java
1: class ChangeBuffer { Nachdem Sie das Programm kompiliert und ausgeführt haben, sollten Sie die folgende Ausgabe sehen:
Hier wurden nicht alle in java.lang.StringBuffer definierten Methoden gezeigt, beispielsweise
ensureCapacity() und getChars(). Weitere Informationen über diese Methoden entnehmen Sie der
Online-Java-Referenz von JBuilder.
Sie könnten mit dem, was Sie bisher gelernt haben, schon Java-Programme schreiben, die jedoch nur wenig
sinnvoll wären. Programme sowohl in Java als auch in anderen Programmiersprachen werden erst durch
Steuerkonstrukte (Schleifen und Bedingungen) für den praktischen Einsatz geeignet. Diese Konstrukte
sorgen dafür, daß basierend auf logischen Tests unterschiedliche Programmteile ausgeführt werden.
Die if-else-Bedingung, die Ihnen ermöglicht, basierend auf einer einfachen Überprüfung verschiedene
Codezeilen auszuführen, ist fast identisch mit den if-else-Anweisungen anderer Sprachen. Und hier die
Syntax:
if bedingung Dem Schlüsselwort if folgt die bedingung, das ist eine Boolesche Auswertung. Der bedingung folgen
unmittelbar anweisung(en) (entweder eine einzelne Anweisung oder ein Anweisungsblock), die ausgeführt
werden, wenn die bedingung true ergibt. Das optionale Schlüsselwort else stellt die anweisung(en) zur
Verfügung, die ausgeführt werden, wenn die bedingung false ist:
if (x < y) Hier folgt ein Beispiel für eine if-else-Bedingung, die einen Block im else-Teil der Anweisung verwendet:
if (engineState == true) Dieses Beispiel verwendet in der ersten if-Anweisung die Prüfung (engineState == true), was eigentlich
redundant und damit ein unnötiger Vergleich ist. Weil es sich bei engineState um eine Boolesche Variable
handelt, können Sie einfach den Wert der Variablen verwenden, statt diesen mit true zu vergleichen:
if (engineState) Wenn Sie if-else-Anweisungen verschachteln, müssen Sie manchmal unterscheiden, zu welchem if das else
gehört. Hier ein Beispiel:
if (bedingung1) In diesem Beispiel sieht der Leser anhand der Einrückung, daß das else zur ersten if-Anweisung gehört und
ausgeführt werden sollte, wenn bedingung1 gleich false ist. Leider ist der Java-Compiler nicht so
scharfsinnig. Er nimmt an, daß das else zu der if-Anweisung gehört, die ihm unmittelbar vorausgeht. Im
obigen Beispiel würde er also annehmen, daß das else zum zweiten if gehört und ausgeführt wird, wenn
bedingung2 false ergibt. Und so sorgen Sie dafür, daß Java die richtige Zuordnung trifft:
if (bedingung1) { Auch wenn die zweite if-Anweisung keinen Block darstellt, können Sie die geschweiften Klammern ({})
verwenden, um das ganze zu erzwingen und seinen Gültigkeitsbereich so anzugeben, als handelte es sich um
einen Block. Das verhindert, daß das else sich dem zweiten if zuordnet, weil durch den Gültigkeitsbereich
dieser neue Block unsichtbar für Anweisungen außerhalb des Blocks wird.
Eine Alternative zu der if-else-Anweisung in einer bedingten Anweisung ist der Bedingungsoperator, ein
ternärer Operator.
Der Bedingungsoperator ist ein Ausdruck, d.h. er gibt einen Wert zurück (anders als die if-else-Anweisung,
die einfach nur die Ausführung steuert). Der Bedingungsoperator ist vor allem für sehr kurze oder einfache
Bedingungen sinnvoll.
Die Syntax für den Bedingungsoperator lautet:
bedingung ? true-ergebnis : false-ergebnis;
Bei der bedingung handelt es sich um einen Boolesche Ausdruck, der true oder false zurückgibt, ähnlich der
bedingung in der if-else-Anweisung. Wenn die bedingung gleich true ist, gibt der
Bedingungsoperator-Ausdruck den Wert von true-ergebnis zurück, ist sie gleich false, gibt er den Wert von
false-ergebnis zurück.
Hier folgt ein Beispiel für eine Bedingung, die die Werte von x und y überprüft, den kleineren von beiden
zurückgibt und diesen Wert der Variablen smaller zuweist:
Der Bedingungsoperator hat eine sehr geringe Priorität. Die einzigen Operatoren, die eine noch geringere
Priorität haben, sind die Zuweisungsoperatoren. Der Bedingungsoperator wird deshalb im allgemeinen erst
ausgewertet, nachdem alle seine Unter-Ausdrücke ausgewertet sind. Weitere Informationen über die
Prioritäten von Operatoren finden Sie in Tabelle 2.6.
Hier folgt die Auswertungsreihenfolge des obigen Beispiels:
Und hier derselbe Vergleich unter Verwendung der if-else-Anweisung:
int smaller; Wie Sie aus diesen Beispielen sehen, können Sie unter Verwendung des Bedingungsoperators mit einer
einzigen Codezeile sehr viel bewerkstelligen. Sie können jedoch keine Zuweisungen oder
Block-Anweisungen als Operanden verwenden. Wenn Sie diese komplexeren Anweisungen brauchen,
müssen Sie die if-else-Anweisung verwenden.
In allen Programmiersprachen ist es üblich, eine Variable mit einem Wert aus einer Wertemenge zu
vergleichen und basierend auf dem Ergebnis unterschiedliche Aktionen auszuführen. Wenn Sie nur
if-else-Anweisungen einsetzen, wird das sehr schnell unübersichtlich, abhängig von der Formatierung und
dem Umfang der Wertemenge, für die die Vergleiche ausgeführt werden. Sie könnten beispielsweise eine
if-else-Anweisung wie die folgende ausführen:
if (oper == '+') Diese Form einer if-else-Anweisung wird auch als verschachteltes if-else bezeichnet, weil jede Anweisung
wiederum ein weiteres if-else enthält usw. In diesem Beispiel werden vier Möglichkeiten abgetestet, deshalb
ist der Code noch relativ übersichtlich. Weil diese Situation jedoch so häufig auftritt, gibt es einen speziellen
Bedingungsausdruck, der sie verarbeitet: switch, manchmal auch als case-Anweisung bezeichnet.
Hier die Syntax für die switch-Bedingung:
switch (ausdruck) { Die switch-Struktur besteht aus mehreren case-Werten (konstante_1, konstante_2 usw.) und einer
optionalen default-Anweisung. Der ausdruck (der einen elementaren Typ wie byte, char, short oder int
zurückgeben muß), wird mit jedem der case-Werte verglichen. Wenn eine Übereinstimmung festgestellt
wird, werden die anweisung(en) für den entsprechenden case-Wert ausgeführt, bis eine break-Anweisung
erkannt wird oder das Ende der switch-Anweisung erreicht ist. Nachdem Sie alle case-Werte überprüft
haben und keine Übereinstimmung festgestellt wurde, wird die default-Anweisung ausgeführt. Die Angabe
der default-Anweisung ist optional, wenn sie also nicht verwendet wird und es keine Übereinstimmung mit
einem der case-Werte gibt, wird die switch-Anweisung beendet, ohne irgendeine Aktion vorgenommen zu
haben.
Wenn nun jemand anderer den Code nach Wochen (oder Monaten) betrachtet, erkennt er sofort,
daß es Absicht war, für die default-Anweisung keine Aktion auszuführen.
Und hier die verschachtelte if-else-Anweisung von vorhin, dargestellt als switch-Anweisung:
switch (oper) Beachten Sie die break-Anweisung am Ende der einzelnen case-Fälle. Ohne das explizite break werden,
nachdem eine Übereinstimmung gefunden ist, die Anweisungen für diese Übereinstimmung und alle weiteren
Anweisungen in dem switch-Block ausgeführt, bis entweder ein break oder das Ende des Blocks erkannt
wird (je nachdem, was zuerst auftritt). Normalerweise ist das nicht das gewünschte Verhalten, Sie sollten
also sicherstellen, das break anzugeben, um einzugrenzen, welche Anweisungen bei einer Übereinstimmung
ausgeführt werden sollen.
Andererseits kann diese Eigenschaft ganz nützlich sein. Betrachten Sie den Fall, wo Sie wollen, daß für
mehrere case-Werte dieselben Anweisungen ausgeführt werden. Die Angabe immer wieder derselben
Anweisung wäre redundant, deshalb bietet Java die Möglichkeit, daß für mehrere case-Werte dieselben
Anweisungen ausgeführt werden. Durch Weglassen der Ergebnis-Anweisung für einen case-Wert »fällt« die
Ausführung durch zum nächsten case-Wert, und von dort zum nächsten, bis eine Anweisung gefunden ist.
Hier ein Beispiel für diese Art Konstrukt:
switch (x) { Die wesentliche Einschränkung des switch in Java ist, daß diese Tests und Werte sich nur auf einfache
elementare Datentypen beziehen können (und dabei nur die elementaren Datentypen, die in einen int
umgewandelt werden können). Sie können keine größeren elementaren Typen (long, float, double), Strings
oder andere Objekte in einer switch-Anweisung verwenden, und Sie können auch nur auf Gleichheit testen.
Dadurch ist switch wirklich nur für die einfachsten Vergleiche sinnvoll. Verschachtelte if-else-Anweisungen
dagegen können für beliebige Tests und beliebige Wertetypen eingesetzt werden.
Die for-Schleife prüft eine Bedingung. Wenn diese Bedingung erfüllt ist, also true ergibt, wird eine
Anweisung oder ein Anweisungsblock wiederholt ausgeführt, bis die Bedingung false wird. Diese Art
Schleife wird häufig für einfache Iterationen verwendet, in denen Sie einen Anweisungsblock mit einer
bestimmten Anzahl von Wiederholungen ausführen und dann beenden, aber Sie können for-Schleifen auch
für jede andere Aufgabe einsetzen.
Hier die Syntax für die for-Schleife:
for (initialisierung; test; inkrement) anweisung(en);
Der Anfang der for-Schleife besteht aus drei Teilen:
Der anweisung(en)-Teil der for-Schleife stellt die Anweisung oder den Anweisungsblock dar, die immer
dann ausgeführt werden, wenn test true ergibt und die Schleife durchlaufen wird. Hier ein Beispiel für eine
for-Schleife, die alle Werte eines String-Arrays mit Null-Strings initialisiert:
String strArray[] = new String[10]; Jede dieser Komponenten der for-Schleife kann leere Anweisungen enthalten, d.h. Sie können einfach ein
Semikolon ohne Ausdruck oder Anweisung einfügen, und dieser Teil der for-Schleife wird dann ignoriert.
Beachten Sie, daß Sie bei der Verwendung einer leeren Anweisung in Ihrer for-Schleife vielleicht die
Initialisierung oder Inkrementierung von Schleifenvariablen oder Schleifeninidzes an anderer Stelle selbst
vornehmen müssen.
Sie können auch eine leere Anweisung für den Rumpf Ihrer for-Schleife angeben, wenn alles, was Sie
bewerkstelligen wollen, bereits im Schleifenanfang passiert. Das folgende Beispiel zeigt, wie die erste
Primzahl größer 4000 gefunden wird. Auch hier ist es am besten, wenn Sie eine Kommentaranweisung
einfügen, wo Sie eine leere Anweisung verwenden, damit offensichtlich wird, daß das bewußt so realisiert
wurde:
for (i = 4001; notPrime(i); i += 2) Achten Sie auf die Plazierung des Semikolons (;) nach der ersten Zeile in der for-Schleife. Betrachten Sie
den folgenden Codeausschnitt:
for (int i = 0; i < 10; i++); Hier wollte man, daß der String Schleife! 10mal ausgegeben wird, aber statt dessen wird die Schleife nur
10mal durchlaufen und macht nichts außer Testen und Inkrementieren, um dann nur einmal Schleife!
auszugeben. Warum? Aufgrund des fehlerhaft plazierten Semikolons (;) am Ende der ersten Zeile der
for-Schleife.
Die while-Schleife wird genutzt, um eine Anweisung oder einen Anweisungsblock so lange zu wiederholen,
wie eine bestimmte Bedingung true ist.
Hier die Syntax der while-Schleife:
while (bedingung) anweisung(en);
Die bedingung ist ein Boolescher Ausdruck, der ein Boolesches Ergebnis zurückgibt. Wenn er true
zurückgibt, führt die while-Schleife die anweisung(en) aus und prüft dann die Bedingung erneut ab, bis die
Bedingung false ergibt. Wenn die Bedingung beim ersten Prüfen false ist, werden die anweisung(en) der
while-Schleife nicht ausgeführt.
Hier folgt ein Beispiel für eine while-Schleife, die die Elemente eines Arrays mit Integern (in arrInt) in ein
Array mit Fließkommazahlen (in arrFloat) kopiert und dabei jedes Element in eine Fließkommazahl
umwandelt. Um das Ganze interessanter zu machen, gibt es zwei Bedingung, die true sein müssen, damit die
Schleife ausgeführt wird:
Um das zu bewerkstelligen, erfolgt in der Schleife ein zusammengesetzter Test, der mehrere Bedingungen
auswertet. Bei der Verwendung des Operators && müssen beide Teile true sein, damit die Bedingung true
ergibt. Diese Schleife verwendet außerdem das Postfix-Inkrement (++), um den Zähler nach jedem
Schleifendurchgang zu erhöhen:
int count = 0; Angenommen, arrInt hat die Länge 20. Wenn keiner der Werte aus arrInt 0 ist, würde diese while-Schleife
20mal ausgeführt, weil die Prüfung true ergibt, während die count-Variable bei der Iteration von 0 bis 19
true ergibt. Ist dagegen einer der arrInt-Werte 0, wird die Schleife zwischen 0- und 19mal ausgeführt,
abhängig von der Position der ersten 0 in dem arrInt.
Bei der Beschreibung der while-Schleife haben wir darauf hingewiesen, daß sie möglicherweise überhaupt
nicht ausgeführt wird, wenn die Bedingung gleich bei der ersten Auswertung false ergibt. Wenn Sie wollen,
daß die Schleife mindestens einmal ausgeführt wird, brauchen Sie eine do-while-Schleife. Sie macht im
wesentlichen dasselbe wie eine while-Schleife, mit der Ausnahme, daß die Anweisungen zuerst ausgeführt
werden, und dann die Bedingung ausgewertet wird.
Hier die Syntax für die do-while-Schleife:
do anweisung(en) while bedingung;
Hier werden zuerst die anweisung(en) ausgeführt und anschließend wird die bedingung ausgewertet. Wenn
die bedingung true ergibt, werden die anweisung(en) erneut ausgeführt, ergibt sie false, wird die Schleife
beendet. Hier ein Beispiel, das 20 Zeilen ausgibt:
int x = 1; Merken Sie sich, daß do-while-Schleifen immer mindestens einmal ausgeführt werden und die Prüfung am
Ende ausführen, während while-Schleifen am Anfang prüfen und möglicherweise nie ausgeführt werden.
Sie haben break bereits als Teil der switch-Anweisung kennengelernt; es beendet die Ausführung von switch
und das Programm wird mit der Anweisung hinter dem switch-Konstrukt fortgesetzt. In einer Schleife macht
das Schlüsselwort break dasselbe - es bricht die Ausführung der aktuellen Schleife unmittelbar ab. Wenn
Sie verschachtelte Schleifen verwenden, wird die Ausführung in der nächsten äußeren Schleife fortgesetzt.
Andernfalls setzt das Programm seine Ausführung einfach in der nächsten Anweisung hinter der Schleife fort.
Betrachten Sie beispielsweise die folgende while-Schleife, die Elemente von einem Integer-Array in ein
Fließkommazahlen-Array kopiert, bis das Ende des Arrays erreicht oder eine 0 erkannt wird. Den letzteren
Fall können Sie innerhalb des Rumpfs von wihle prüfen und die Schleife gegebenenfalls mit break verlassen:
int count = 0; Die break-Anweisung bewirkt, daß die Schleife beendet wird, sobald die Bedingung erfüllt ist. In diesem
Fall wird die Schleife beendet, wenn einer der arrInt-Werte gleich 0 ist. Im Gegensatz dazu beendet das
Schlüsselwort continue die Ausführung des aktuellen Schleifendurchgangs, und führt den nächsten
Schleifendurchgang aus. Bei do-while-Schleifen bedeutet das, daß die Schleife die Ausführung oben wieder
beginnt, while- und for-Schleifen werden mit der Auswertung der Bedingung fortgesetzt.
Das Schlüsselwort continue ist praktisch, wenn Sie die Schleife neu starten wollen, ohne die darin
enthaltenen Anweisungen auszuführen. Betrachten Sie das obige Beispiel, wo ein Array in ein anderes
kopiert wird. Sie können prüfen, ob das aktuelle Integer-Element gleich 0 ist. In diesem Fall können Sie die
Schleife neu starten, so daß das resultierende Fließkommazahlen-Array keinen Null-Wert entgegennehmen
muß. Beachten Sie, daß Sie möglicherweise einige Elemente im ersten Array überspringen, Sie nun zwei
Array-Zähler verwalten müssen:
int iCount = 0; Dieses Beispiel durchläuft beide Arrays, und kopiert den Integer-Wert aus arrInt nur dann in arrFloat, wenn
das Element in arrInt ungleich Null ist.
Für break und continue kann optional ein Sprungziel angegeben werden, das Java mitteilt, mit welcher
Programmanweisung es fortfahren soll. Ohne ein Sprungziel (Label) setzt break die Ausführung mit der
nächsten Programmanweisung nach der schließenden Schleife fort und continue startet die umschließende
Schleife neu. Die Verwendung von break und continue mit Sprungzielen ermöglicht Ihnen, eine Schleife
außerhalb der aktuellen Schleife fortzusetzen oder mehrere Schichten verschachtelter Schleifen gleichzeitig
zu verlassen.
Um eine Schleife mit Sprungzielen zu verwenden, fügen Sie das Label vor der Schleifeninitialisierung ein.
Hinter dem Label wird kein Semikolon (;), sondern ein Doppelpunkt (:) angegeben. Wenn Sie jetzt break
oder continue verwenden, fügen Sie nach dem Schlüsselwort das Label, also das Sprungziel ein:
out: In diesem Codeabschnitt kennzeichnet out: den äußeren Block. Innerhalb der for- und der while-Schleife
bewirkt die break-Anweisung für eine bestimmte Bedingung, daß beide Schleifen verlassen und die
Ausführung mit der Codezeile hinter der for-Schleife fortgesetzt wird.
Das Programm Breakers in Listing 2.5 ist ein Beispiel für verschachtelte for-Schleifen und ein break mit
Sprungziel. In der inneren Schleife werden beide for-Schleifen gleichzeitig verlassen, wenn die Summe der
beiden Zähler größer vier ist.
1: class Breakers { Wenn Sie das Programm ausführen, sehen Sie die folgende Ausgabe:
Heute haben Sie zahlreiche Aspekte zu der Sprache kennengelernt, die JBuilder zugrunde liegt, Java. Sie
haben Programmanweisungen kennengelernt und unter anderem auch die speziellen
Dokumentations-Kommentare von Java. Datentypen, Variablen und Literale wurden vorgestellt. Darüber
hinaus haben Sie die Operatoren gesehen, die in Java zur Verfügung stehen, und wie sie unter
Berücksichtigung der Prioritäten in Java angewendet werden. Es wurde darauf hingewiesen, daß Java
zahlreiche komplexe mathematische Funktionen bietet.
Sie haben viel über Arrays, String und Stringpuffer gelernt. Sie haben gesehen, wie Array-, String- und
StringBuffer-Variablen deklariert werden, und wie ihre Objekte erzeugt werden. Sie haben die Methoden
zum Zugriff auf die Daten in diesen Strukturen kennengelernt und wissen, wo Sie zusätzliche Informationen
finden können. Sie können mehrdimensionale Arrays erzeugen und verwenden und Sie wissen, wann anstelle
von String-Objekten StringBuffer-Objekte verwendet werden sollten.
Es gab zwei Themenbereiche, die Ihnen sicher häufig in Ihren eigenen Java-Programmen begegnen werden,
nämlich Bedingungen und Schleifen. Bedingungen sind unter anderem die if-else- und die
switch-Anweisungen, mit denen Sie zu bestimmten Codezeilen verzweigen können, abhängig von dem
Ergebnis einer Booleschen Auswertung. Die Schleifenanweisungen umfassen die for-, while- und
do-while-Schleifen, die Ihnen ermöglichen, bestimmte Anweisungen wiederholt auszuführen, bis eine
bestimmte Bedingung erfüllt ist.
Nachdem Sie diese Sprachkonstrukte kennengelernt haben, werden Sie lernen, Klassen zu deklarieren und
Methoden zu erzeugen, mit deren Hilfe Instanzen dieser Klassen miteinander kommunizieren können.
F Ich habe keine Möglichkeit gesehen, lokale Konstanten zu erzeugen. Unterstützt Java keine
Konstanten?
A Doch, aber Sie können in Java keine lokalen Konstanten erzeugen. Sie können nur Instanzkonstanten und
Klassenkonstanten erzeugen. Mehr darüber erfahren Sie in der nächsten Lektion.
F Was passiert, wenn Sie einer Variablen einen numerischen Wert zuweisen, die zu groß (oder zu
klein) für diese Variable ist?
A Sie denken vielleicht, die Variable wird einfach nur in den nächst größeren Typ umgewandelt, aber das ist so
nicht der Fall. Wenn es sich bei dem Wert um eine positive Zahl handelt, entsteht ein »Überlauf« für die
Variable, d.h. die Variable kippt um und wird zum kleinsten negativen Wert für diesen Typ, von wo aus
weitergezählt wird. Ist der Wert eine negative Zahl, entsteht ein »Unterlauf« für die Variable, d.h. sie wird zum
höchsten Wert für diesen Typ und zählt von dort aus abwärts. Das kann zu fehlerhaften Ergebnissen führen,
stellen Sie also sicher, daß Sie für numerische Werte die jeweils richtigen Typen deklarieren. Wenn Sie Zweifel
haben, verwenden Sie den nächst größeren Typ.
F Wenn Arrays Objekte sind und mit new erzeugt werden müssen, wo ist dann die Klasse Array? Ich
habe sie in den Klassenbibliotheken von Java nicht gefunden.
A Arrays werden in Java einigermaßen kompliziert implementiert. Die Klasse Array wird automatisch angelegt,
wenn Ihr Java-Programm ausgeführt wird, deshalb können keine Unterklassen davon angelegt werden. Array
stellt die grundlegende Umgebung für Arrays bereit, unter anderem die Instanzvariable length. Darüber besitzt
hat jeder elementare Typ und jedes Objekt eine implizite Unterklasse von Array, die ein Array dieser Klasse
oder dieses Objekts darstellt. Wenn Sie ein neues Array-Objekt erzeugen, haben Sie vielleicht nicht wirklich
eine Klasse, aber es verhält sich so, als ob das der Fall wäre.
F Sie haben gesagt, daß man die Methode arraycopy() auf Arrays anwenden kann, aber kann ich sie
auch für Instanzen der Klassen String und StringBuffer verwenden, die doch ebenfalls als Arrays
implementiert sind?
A Ja, mit einer Ausnahme. Weil String-Werte nicht direkt verändert werden können, können Sie keinen String
als Ziel-Array verwenden. wenn dagegen das Ziel-Array oder der StringBuffer bereits im Speicher alloziert sind,
können Sie arraycopy() verwenden, um Daten hineinzukopieren.
F Wenn ein Array Werte beliebiger elementarer Datentypen oder Objekte aufnehmen kann, wie kann
ich dann genau ermittelt, wieviel Speicher ein Array alloziert?
A Um zu berechnen, wieviel Speicher für ein Array alloziert wird, multiplizieren Sie die Anzahl der Elemente mit
der Anzahl der Bits, die für den Datentyp dieses Elements verwendet werden. Addieren Sie 32 Bit für das Feld
length (das immer ein int ist). Teilen Sie durch 8, um die Anzahl der Bytes zu erhalten, die für das Array alloziert
werden. Wenn Sie beispielsweise ein Array mit 6 double-Elementen deklarieren wollen, die je 64 Bit belegen,
können Sie den erforderlichen Speicher wie folgt berechnen:
Es ergeben sich insgesamt 52 Byte Speicherbedarf.
F Sie haben in den Code-Listings von heute keine import-Anweisungen verwendet. Warum?
A Alle Methoden für Arrays, Strings und Stringpuffer sind Teil des Pakets java.lang, und die Klassen String und
StringBuffer sind in java.lang.String bzw. java.lang.StringBuffer definiert. Weil das ganze java.lang-Paket
implizit in alle Java-Programme importiert wird, ist es nicht erforderlich, eine explizite import-Anweisung
anzugeben.
F Gibt es in Java eine goto-Anweisung?
A Java definiert das Schlüsselwort goto, aber es ist »reserviert« und wird momentan nicht verwendet. Aber ein
break mit Sprungziel realisiert dasselbe.
F Ich habe eine Variable in einer Blockanweisung in einer if-else-Anweisung deklariert. Wenn das
if-else abgearbeitet ist, verschwindet diese Variable. Was ist passiert?
A Blockanweisungen innerhalb geschweifter Klammern bilden einen lokalen Gültigkeitsbereich. Das bedeutet,
wenn Sie eine Variable innerhalb eines Blocks deklarieren, ist sie nur innerhalb dieses Blocks sichtbar und
verwendbar. Nachdem der Block abgearbeitet ist, stehen die Variablen, die dort deklariert wurden, nicht mehr
zur Verfügung.
F Warum können in der switch-Anweisung keine String-Werte verwendet werden?
A Strings sind Objekte, und switch ist in Java nur für die elementaren Datentypen byte, char, short und int
definiert. Um andere Typen zu vergleichen, müssen Sie verschachtelte if-else-Anweisungen verwenden, die
allgemeinere Ausdrücke erlauben, unter anderem auch String-Vergleiche.
Der Workshop bietet zwei Möglichkeiten, zu überprüfen, was Sie in diesem Kapitel gelernt haben. Der
Quiz-Teil stellt Ihnen Fragen, die Ihnen helfen sollen, Ihr Verständnis für den vorgestellten Stoff zu vertiefen.
Die Antworten auf die Fragen finden Sie in Anhang A. Der Übungen-Teil ermöglicht Ihnen, Erfahrungen in
der Anwendung der Dinge zu sammeln, die Sie hier kennengelernt haben. Versuchen Sie, diese Dinge
durchzuarbeiten, bevor Sie mit der nächsten Lektion weitermachen.
Vorgegeben seien das folgende Integer-Array und die Strings:
Erzeugen Sie die Klasse Splat, die Array-Indizes verwendet, den Konkatenations-Operator (+) sowie die
Methoden substring() und valueOf(), um einen String zu erzeugen, der wie folgt auf dem Bildschirm
ausgegeben wird:
im neuen Programm durch die folgende Ausgabe ersetzt wurde:
Stellen Sie sicher, daß dies die einzige Änderung in der Ausgabe ist.
pro Zyklus auf 30 gesetzt */
* täglichen Saldo, das ist die Summe aller noch nicht bezahlten
* Rechnungen dividiert durch die Anzahl der Tage im aktuellen
* Monat des Rechnungszyklus
*/
Dokumentations-Kommentare
* Funktionalität der Klasse awt.Graphics
* erweitern, um Firmenlogos anzuzeigen.
* @author mmm
* @version 3.51
*/
public class mySpecialClass extends java.awt.Graphics {
...
}
Variablen, Literale und Datentypen
Technischer Hinweis
Java unterstützt das Konzept der globalen Variablen nicht, die in allen Teilen eines Programms zur
Verfügung stehen. Statt dessen werden Instanz- und Klassenvariablen verwendet, um eine Kommunikation
zwischen den Objekten zu realisieren.
Datentypen
Technischer Hinweis
Der Unicode-Zeichensatz umfaßt 16 Bit und beinhaltet 34168 Zeichen. Die Unicode-Untermenge, die die
ASCII-Zeichen repräsentiert, liegt zwischen \u0020 und \u007E, für Latin-1 zwischen \u0020 und \u00FF.
Weil ASCII und Latin-1 8-Bit-Zeichensätze sind, sind sie beide nicht einfache Untermengen von Unicode.
Unicode wird schnell zum Standard auf der gesamten Welt, weil es die Symbole und Zeichen der meisten
natürlichen Sprachen darstellen kann. Mehr über Unicode finden Sie auf der Web-Seite des
Unicode-Konsortiums unter http://www.unicode.org/.
Technischer Hinweis
In Java gibt es keine typedef-Anweisung wie in C/C++. Um neue Typen zu deklarieren, deklarieren Sie
zuerst eine neue Klasse und dann können Sie Variablen als Typ dieser Klasse deklarieren. Eine genauere
Beschreibung erhalten Sie in der nächsten Lektion.
Variablennamen
Vergessen Sie nicht, daß in Java die Groß-/Kleinschreibung berücksichtigt wird. Mit anderen
Worten, die Variablen mit den Namen watchOut, WatchOut und WATCHOUT sind nicht dieselben.
Achten Sie also bei der Codierung auf konsistente Schreibweisen.
Variablendeklaration
Die Gruppe der Programmanweisungen, in denen eine Variable existiert, wird auch als ihr
Gültigkeitsbereich bezeichnet. Wenn ein Programm ausgeführt wird, wird die Variable n der
Deklarationsanweisung erzeugt. Alle Anweisungen, die der Variablendeklaration folgen, können auf die
Variable zugreifen und sie verändern, bis eine schließende geschweifte Klammer (}) auftritt. Von dem
Moment an existiert die Variable nicht mehr im Speicher und befindet sich außerhalb des
Gültigkeitsbereichs.
Die einfachste Form einer Variablendeklaration gibt nur den Typ und den Namen der Variablen an. Die
folgenden Deklarationsanweisungen erzeugen die Variablen retireAge und birthYear vom Typ short und die
Variable insValueLimit vom Typ float:
short birthYear;
float insValueLimit;
Initialisierung
boolean isCurrent = true;
Literale
Ein Literal ist ein Wert, der einer Wert-Datentyp-Variablen zugeordnet werden kann, etwa bei
der Initialisierung in der Deklaration. Ein Literal kann aber auch direkt im Programm verwendet werden,
beispielsweise der Wert 8 im Ausdruck i==8.
Es gibt Boolesche, numerische, Zeichen- und String-Literale. Jedes davon stellt spezielle Informationen dar,
die Sie brauchen, um Entscheidungen dahingehend zu treffen, wie diese Werte repräsentiert werden.
Boolesche Literale
Numerische Literale
Zeichen-Literale
Ein Escape-Code entsteht, indem man dem nicht-druckbaren Zeichen oder dem Sonderzeichen
einen Backslash (\) vorausstellt. Dadurch können sie als Zeichen-Literale verwendet werden.
Weil bestimmte Symbole von der Sprache Java verwendet werden, wie etwa einfache Anführungszeichen
('), werden auch diese unter Verwendung des Backslash (\) als Zeichen-Literale dargestellt, wie in Tabelle
2.3 gezeigt.
String-Literale
System.out.println("\"Ich will allein sein\", sagte sie.");
System.out.println("Die meisten 4.-Klässler sind \11 Jahre alt.");
Dieser String gibt
mehrere Zeilen aus.
"Ich will allein sein", sagte sie.
Die meisten 4.-Klässler sind 9 Jahre alt.
In Java sind Strings Instanzen der Klasse String und echte Objekte, keine Arrays wie in anderen Sprachen.
Wenn Sie ein String-Literal verwenden, erzeugen Sie implizit eine Instanz der Klasse String und initialisieren
sie mit dem Wert des String-Literals. Keines der anderen Literale macht dies, weil es sich dabei um
elementare Wert-Datentypen handelt, und nicht um Objekte wie Strings. Mehr über Strings erfahren Sie
später in dieser Lektion.
Ausdrücke und Operatoren
Ein Ausdruck ist eine Anweisung oder ein Teil einer Anweisung, deren variable und literale Terme
einen bestimmten Wert ergeben, etwa i==8, was true oder false ergibt.
Ein Operator ist ein Symbol, das steuert, wie die Terme eines Ausdrucks ausgewertet oder
manipuliert werden. In dem Beispiel i==8 teilt der Operator == dem Compiler mit, die Werte der Variablen
i und des Literals 8, der sogenannten Operanden, zu vergleichen.
Sie können sich die Operatoren auch als Mini-Funktionen vorstellen, die Parameter (die Operanden)
entgegennehmen und ein Ergebnis zurückgeben. Der Datentyp des Ergebnisses hängt von dem verwendeten
Operator ab. Ein logischer Operator beispielsweise kann int-Werte als Operanden entgegennehmen, gibt
aber ein Boolesches Ergebnis zurück. Der Operator und seine Operanden sind die kleinste Form eines
Ausdrucks.
Ein unärer Präfix-Operator wird vor dem Operanden plaziert:
Ein unärer Postfix-Operator wird nach dem Operanden plaziert:
Ein binärer Infix-Operator wird zwischen den beiden Operanden plaziert:
Ein ternärer Infix-Operator besteht eigentlich aus einem Paar von Operator-Symbolen, das drei
Operanden entgegennimmt. Das erste Symbol des Paars wird zwischen dem ersten und dem zweiten
Operanden plaziert, das zweite zwischen dem zweiten und dem dritten Operanden:
Technischer Hinweis
In Java führt der Zuweisungsoperator = dieselbe Operation aus wie in Pascal/Delphi der
Zuweisungsoperator :=.
In den folgenden Abschnitten werden Sie die Aspekte der Auswertung von Ausdrücken und der
Verwendung von Operatoren kennenlernen. Machen Sie müssen sich das hier noch nicht merken.
Versuchen Sie einfach, sich die jeweiligen Konzepte vorzustellen.
Arithmetische Operationen
Inkrement und Dekrement
daysLeftUntilVacation = daysLeftUntilVacation - 1;
daysLeftUntilVacation--;
x = ++z; // In diesem Beispiel wird x der Wert 8 zugewiesen
y = z; // Der Variablen y wird ebenfalls der Wert 8 zugewiesen
x = z++; // Hier wird x der Wert 7 zugewiesen
y = z; // Der Variablen y wird der Wert 8 zugewiesen
Vorzeichen
x = y; // x wird der Wert 4 zugewiesen
x = -y; // x wird der Wert -4 zugewiesen
x = -z; // x wird der Wert 7 zugewiesen
x = z; // x wird der Wert -7 zugewiesen
Grundlegende Mathematik
x = y + z; // x wird der Wert 36 zugewiesen.
x = y - z; // x wird der Wert 20 zugewiesen.
x = y * z; // x wird der Wert 224 zugewiesen.
x = y / z; // x wird der Wert 3 zugewiesen.
x = y % z; // x wird der Wert 346 zugewiesen.
String-Mathematik
helloWorld = hello + space + world + "!"
Relationale Operationen
Technischer Hinweis
In Java macht der Vergleichsoperator == (ist gleich) dasselbe wie der Vergleichsoperator = (ist gleich) in
Pascal/Delphi.
boolean isThatSo;
isThatSo = y < z; // isThatSo erhält den Wert false.
isThatSo = x <= w; // isThatSo erhält den Wert true.
isThatSo = y > z; // isThatSo erhält den Wert true.
isThatSo = x >= w; // isThatSo erhält den Wert false.
isThatSo = y == z; // isThatSo erhält den Wert false.
isThatSo = w != z; // isThatSo erhält den Wert true.
Logische Operationen
Bitweise Operationen
Zuweisungen
isInsured = isInsured & hasRenewed;
isInsured &= hasRenewed;
Operatorpriorität
g = x + y * z;
g = (x + y) * z;
Arrays und Strings
In der folgenden Beschreibung wird der Begriff Konstruktoren verwendet. Weitere Informationen
über Konstruktoren finden Sie im nächsten Kapitel. Hier sollten Sie einfach nur davon ausgehen, daß
Konstruktoren spezielle Methoden sind, die Ihnen ermöglichen, ein Objekt im Speicher zu erzeugen und ihm
optional gleichzeitig einen Wert zuzuweisen.
Array-Objekte
Ein Array stellt eine Möglichkeit dar, eine Auflistung von Elementen zu speichern. Jeder Eintrag in
dem Array enthält einen Eintrag, also ein Element. Sie können die Elemente in den Einträgen plazieren oder
ihren Inhalt ändern.
Array-Elemente können Werte beliebigen Typs enthalten (elementare Datentypen oder Objekte), aber
innerhalb eines Arrays können nicht mehrere Typen verwendet werden. Das bedeutet, alle Elemente eines
Arrays müssen denselben Datentyp haben. Sie können beispielsweise ein Array mit Integern oder ein Array
mit String-Objekten haben, aber nicht ein Array, das sowohl Integer- als auch String-Elemente enthält.
Deklaration von Array-Variablen
Date games[];
int averageRBI[];
Array-Objekte erzeugen
Eine Ausnahme ist ein Fehler, der zur Laufzeit auftritt. Die Java-Klasse Exception wird in
verschiedene Kategorien unterteilt, so daß Sie einen Hinweis darauf erhalten, was den Fehler verursacht hat,
nachdem eine Ausnahme aufgeworfen wurde.
Zugriff und Änderung von Array-Elementen
In Java beginnen Indizes mit Null (0).
float goldRate == rates[1]; // Der Wert ist 14.5
float preferredRate == rates[2]; // Der Wert ist 16.5
float regularRate == rates[3]; // Der Wert ist 18.95
float probationRate == rates[4]; // Der Wert ist 23.0
myArr[10] = 73;
sentence[0] = "The";
Der Name des Quell-Arrays
Die Position, an der das Kopieren beginnen soll
Der Name des Ziel-Arrays
Die Position, ab der die kopierten Daten geschrieben werden sollen
Die Anzahl der zu kopierenden Array-Elemente
Mehrdimensionale Arrays
coords[0][0] = 1;
coords[0][1] = 2;
{"ab", "cd", "ef", "gh", "ij"},
{"kl", "mn"}
{"op", "qr", "st", "uv"}
{"wx", "yz"}
};
String- und StringBuffer-Objekte
Deklaration von String- und StringBuffer-Objekten
StringBuffer myStringBuff;
String-Objekte erzeugen
String chString = String.valueOf(chArr, 1, 4);
String str3 = new String(chArr);
String str4 = new String(chArr, 5, 3);
Zugriff auf String-Elemente
for (int i = 0; i < aString.length; i++)
aString[i] = 'A';
2: public static void main(String args[]) {
3: String str = "Time is too slow for those who wait.";
4: System.out.println();
5:
6: System.out.println("The string is: " + str);
7:
8: System.out.println("Length of string: "
9: + str.length());
10:
11: System.out.println("Character at position 17: "
12: + str.charAt(17));
13:
14: System.out.println("String begins with \"those\": "
15: + str.startsWith("those"));
16:
17: System.out.println("String ends with \"wait.\": "
18: + str.endsWith("wait."));
19:
20: System.out.println("Index of the first \"w\" character: "
21: + str.indexOf('w'));
22:
23: System.out.println("Index of the last \"w\" character: "
24: + str.lastIndexOf('w'));
25:
26: System.out.println("Substring from 0 to 2: "
27: + str.substring(0, 3));
28:
29: }
30: }
The string is: Time is too slow for those who wait.
Length of string: 36
Character at position 17: f
String begins with "those": false
String ends with "wait.": true
Index of the first "w" character: 15
Index of the last "w" character: 31
Substring from 0 to 2: Tim
In diesem Beispiel erzeugen Sie eine Instanz von String und geben dann die von den in der
String-Klasse definierten Methoden ermittelten Werte aus:
Die Methode substring() bedarf einer genaueren Erklärung. Das Zeichen an der Anfangs-Indexposition ist
im Teilstring enthalten, das Zeichen an der Ende-Indexposition nicht. Aus diesem Grund kann die Methode
substring() eine zweite Form annehmen, die Ihnen ermöglicht, den Teilstring von einer bestimmten
Indexposition bis zum Ende des Strings zu ermitteln. Um beispielsweise die beiden letzten Zeichen des
Strings mit dem Wert Hello zu ermitteln, könnten Sie diese zweite Form einsetzen:
String loStr = str.substring(3)); // die richtige Methode
Strings vergleichen und manipulieren
Java optimiert String-Literale. Das bedeutet, wenn Sie einen String-Wert speichern und dann
versuchen, dasselbe Literal einem anderen String zuzuweisen, erkennt der Java-Compiler, daß das Literal
bereits gespeichert ist, und gibt zuvorkommenderweise das existierende Objekt zurück, statt ein neues zu
erzeugen. Sie müssen also explizit new verwenden, wenn Sie zwei verschiedene String-Objektinstanzen mit
demselben Stringwert erzeugen wollen.
2: public static void main(String args[]) {
3: System.out.println();
4:
5: String aStr = " Geed ";
6: String bStr = "Merning!";
7: String cStr = aStr.concat(bStr);
8: System.out.println(cStr);
9:
10: String dStr = cStr.replace('e', 'o');
11: System.out.println(dStr);
12:
13: String eStr = dStr.toLowerCase();
14: System.out.println(eStr);
15:
16: String fStr = eStr.toUpperCase();
17: System.out.println(fStr);
18:
19: String gStr = fStr.trim();
20: System.out.println(gStr);
21:
22: }
23: }
Geed Merning!
Good Morning!
good morning!
GOOD MORNING1
GOOD MORNING!
In diesem Beispiel verwenden Sie die verschiedenen Manipulationsmethoden, die in der Klasse
String definiert sind:
Wie Sie sehen, sind für die Manipulation eines Stringwerts viele Speicherzuweisungen erforderlich, weil Sie
dem aufrufenden String das Ergebnis nicht zuweisen können. Wenn Sie für einen String so viele
Manipulationen vornehmen wollen, dann sollten Sie besser einen StringBuffer verwenden. Mehr darüber
erfahren Sie später in diesem Kapitel.
StringBuffer-Objekte erzeugen
Zugriff auf StringBuffer-Elemente
2: public static void main(String args[]) {
3:
4: System.out.println();
5: StringBuffer aBuff = new StringBuffer("Time Flies!");
6: System.out.println("The contents of aBuff: " + aBuff);
7: System.out.println("Capacity: " + aBuff.capacity());
8: System.out.println("Length: " + aBuff.length());
9: System.out.println("Character at position 7: "
10: + aBuff.charAt(7));
11:
12: System.out.println();
13: StringBuffer bBuff = new StringBuffer();
14: System.out.println("The contents of bBuff: " + bBuff);
15: System.out.println("Capacity: " + bBuff.capacity());
16: System.out.println("Length: " + bBuff.length());
17:
18: System.out.println();
19: StringBuffer cBuff = new StringBuffer(25);
20: System.out.println("The contents of cBuff: " + cBuff);
21: System.out.println("Capacity: " + cBuff.capacity());
22: System.out.println("Length: " + cBuff.length());
23: }
24: }
Capacity: 27
Length: 11
Character at position 7: i
The contents of bBuff:
Capacity: 16
Length: 0
The contents of cBuff:
Capacity: 25
Length: 0
In diesem Beispiel erzeugen Sie mehrere Instanzen von StringBuffer und geben dann die von den in
der Klasse StringBuffer definierten Methoden ermittelten Werte zurück:
Sie werden bemerken, daß capacity beim dynamischen Allozieren manchmal die doppelte Länge von length
des tatsächlichen Inhalts im Puffer zugewiesen wird. Dieser zusätzliche Overhead ist für StringBuffer
erforderlich, damit sie ihren Inhalt manipulieren können. Deshalb sollten Sie String-Objekte verwenden,
wenn Sie nicht unbedingt einen StringBuffer benötigen. Als nächstes erfahren Sie, wie die
Manipulationsmethoden von StringBuffer verwendet werden.
Manipulation von StringBuffern
2: public static void main(String args[]) {
3: System.out.println();
4:
5: StringBuffer aBuff = new StringBuffer("Time plies!");
6: System.out.println("aBuff contents: " + aBuff);
7: System.out.println("Capacity, length: "
8: + aBuff.capacity() + ", "
9: + aBuff.length());
10: aBuff.setLength(10);
11: System.out.println("aBuff contents: " + aBuff);
12: System.out.println("Capacity, length: "
13: + aBuff.capacity() + ", "
14: + aBuff.length());
15: aBuff.setCharAt(5, 'f');
16: System.out.println("aBuff contents: " + aBuff);
17: System.out.println("Capacity, length: "
18: + aBuff.capacity() + ", "
19: + aBuff.length());
20: aBuff.append(" having fun!");
21: System.out.println("aBuff contents: " + aBuff);
22: System.out.println("Capacity, length: "
23: + aBuff.capacity() + ", "
24: + aBuff.length());
25: aBuff.insert(11, "when you're ");
26: System.out.println("aBuff contents: " + aBuff);
27: System.out.println("Capacity, length: "
28: + aBuff.capacity() + ", "
29: + aBuff.length());
30: String aStr = aBuff.toString();
31: System.out.println("The string is: " + aStr);
32: System.out.println("Length: " + aStr.length());
33:
34: StringBuffer bBuff = new StringBuffer("Bob//");
35: System.out.println("Original bBuff contents: " + bBuff);
36: bBuff.reverse();
37: System.out.println("Reversed bBuff contents: " + bBuff);
38: }
39: }
aBuff contents: Time plies!
Capacity, length: 27, 11
aBuff contents: Time plies
Capacity, length: 27, 10
aBuff contents: Time flies
Capacity, length: 27, 10
aBuff contents: Time flies having fun!
Capacity, length: 27, 22
aBuff contents: Time flies when you're having fun!
Capacity, length: 56, 34
The string is: Time flies when you're having fun!
Length: 34
Original contents of bBuff: Bob//
Reversed contents of bBuff: //boB
In diesem Beispiel verwenden Sie einige der Methoden, die in StringBuffer zur String-Manipulation
definiert sind:
Wie in der Analyse bereits aufgezeigt, sind die Methoden append() und insert() überladen. Das bedeutet, sie
haben mehrere Methodensignaturen. Die Methode append() kann elementare Datenwerte (boolean, char,
double, float, int und long), Objekt-Werte (wie Object und String) und char-Array-Werte entgegennehmen.
Es gibt zwei char-Array-Signaturen. Die erste nimmt das char-Array als Parameter entgegen, das zweite ein
char-Array, einen Offset und einen Zähler. Die insert()-Methode nimmt einen Integer-Offset als ersten
Parameter entgegen und für seinen zweiten Parameter kann sie dieselben elementaren oder Objekt-Werte
entgegennehmen wie die append()-Methode.
Bedingungen und Schleifen
if-else-Bedingungen
anweisung(en);
else anweisung(en);
System.out.println("x ist kleiner als y");
else System.out.println("x ist größer oder gleich y");
Es gibt drei häufige Syntaxfehler, die Neulinge in der Java-Programmierung bei der Verwendung
von if-else-Anweisungen machen:
System.out.println("Motor läuft bereits.");
else {
System.out.println("Versuchen Sie, den Motor zu starten.");
if (gasLevel >= 1)
engineState = true;
else System.out.println("Kein Benzin - der Motor kann nicht gestartet werden!");
}
System.out.println("Motor läuft.");
else System.out.println("Motor steht.");
if (bedingung2)
anweisung;
else anweisung;
if (bedingung2)
anweisung;
}
else anweisung;
Der Bedingungsoperator ?:
true-ergebnis und false-ergebnis müssen Ausdrücke sein, die einen einzelnen Wert zurückgeben.
Mit anderen Worten, Sie können keine Zuweisungen oder Block-Anweisungen für diese Operanden
angeben.
if x < y
smaller = x;
else smaller = y;
switch-Bedingungen
addargs(arg1, arg2);
else if (oper == '-')
subargs(arg1, arg2);
else if (oper == '*')
multargs(arg1, arg2);
else if (oper == '/')
divargs(arg1, arg2);
case konstante_1;
anweisung(en);
break;
case konstante_2;
anweisung(en);
break;
...
default:
anweisung(en);
}
Weil die default-Anweisung optional ist, kann sie auch irrtümlicherweise weggelassen werden.
Wenn Sie nicht wollen, daß irgendeine Aktion ausgeführt wird, falls es keine Übereinstimmung mit einem der
case-Werte gibt, sollten Sie einen Kommentar für default eingeben, etwa wie folgt:
case '+';
addargs(arg1, arg2);
break;
case '-';
subargs(arg1, arg2);
break;
case '*';
multargs(arg1, arg2);
break;
case '/';
divargs(arg1, arg2);
break;
default: /* nichts tun */ ;
}
Innerhalb von switch-Anweisungen müssen Anweisungen nicht mit geschweiften Klammern ({}) als
Blöcke gruppiert werden. Alle Anweisungen zwischen einer case-Anweisung und ihrer break-Anweisung
werden automatisch als impliziter Block behandelt, so daß ein lokaler Gültigkeitsbereich entsteht.
case 2:
case 4:
case 6:
case 8:
System.out.println("x ist eine gerade einstellige Zahl");
break;
default:
System.out.print("x ist keine gerade einstellige Zahl");
}
for-Schleifen
for (int i = 0; i < strArray.length; i++)
strArray[i] = "";
/* nichts tun */ ;
System.out.println("Schleife!");
Schreiben Sie kein Semikolon (;) hinter die erste Zeile der Schleife, es sei denn, das ist wirklich
erforderlich!
while-Schleifen
while ( (count < arrInt.length) && (arrInt[count] != 0) ) {
arrFloat[count] = (float) arrInt[count];
count++;
}
do-while-Schleifen
Technischer Hinweis
Die do-while-Schleife in Java entspricht der repeat-until-Schleife in Delphi/Pascal.
do {
System.out.println("Schleifendurchgang " + x);
x++;
} while (x <= 20);
Die Möglichkeit, Schleifen zu verschachteln, kann Ihnen helfen, einen komplexen Datenfluß zu
steuern, aber mehr als zwei oder drei Ebenen können dazu führen, daß der Code schwer lesbar und
schlecht verständlich wird. Vermeiden Sie also das Verschachteln von Schleifen.
while (count < arrInt.length) {
if (arrInt[count] == 0)
break;
arrFloat[count] = (float) arrInt[count];
count++;
}
int fCount = 0;
while (iCount < arrInt.length) {
if (arrInt[iCount] == 0) {
iCount++;
continue;
}
arrFloat[fCount++] = (float) arrInt[iCount++];
}
Schleifen mit Sprungzielen
for (int i = 0; i < 10; i++) {
while (x < 50) {
if (i * x == 400)
break out;
...
} // Ende der while-Schleife
...
} // Ende der for-Schleife
... // Hier wird die Ausführung nach break out fortgesetzt
2: public static void main(String args[]) {
3:
4: ers:
5: for (int i = 1; i <= 5; i++) {
6: for (int k = 1; k <= 3; k++) {
7: System.out.println("i ist " + i + ", k ist " + k);
8: if ((i + k) > 4)
9: break ers;
10: }
11: }
12: System.out.println("Beide Schleifen beendet");
13: }
14: }
i ist 1, k ist 1
i ist 1, k ist 2
i ist 1, k ist 3
i ist 2, k ist 1
i ist 2, k ist 2
i ist 2, k ist 3
Beide Schleifen beendet
In diesem Beispiel ist das Label ers: (Zeile 4). Die Schleifen werden ausgeführt (Zeilen 5 bis 11),
solange i + k nicht größer als 4 ist (Zeile 8). Wenn die Summe von i und k größer 4 ist, bewirkt die
break-Anweisung (Zeile 9), daß beide Schleifen in den äußeren Block gehen und die letzte Zeile wird
ausgegeben (Zeile 12).
Zusammenfassung
F&A
Workshop
Quiz
Richtig oder Falsch?
int scores[] = new int[10];
int a = 3;
int b = 5;
scores[a-b];char chArr[] = { 'I', 'n', 't', 'e', 'r', 'n', 'e', 't' };
String wwwStr = new String(chArr);
int wwwStrLength = wwwStr.length();String firstStr = "Hier bin ich!"
String secondStr = "Nein, hier bin ich!!"
String thirdStr = "Hier bin ich!"for (i = 0; i <= 100; i += 15);
System.out.println("Hidey, hidey, hidey, ho!");Übungen
Schreiben Sie Programmanweisungen für die folgenden Aufgaben:
int nums[] = {2, 10};
String aStr = "doesn't";
String bStr = "will get you that chicken across the road.";
String cStr = "make it"'
String dStr = "I say,"
String aSpace = " ";
I say, two will get you ten that chicken doesn't make it across the road.
Nehmen Sie an dem Programm aus Listing 2.5 die folgenden Änderungen vor:
Führen Sie das Programm aus und prüfen Sie, ob die sechste Ausgabezeile aus Breakers.java (Listing 2.5),
Ein Imprint des Markt&Technik Buch- und Software- Verlag GmbH
Elektronische Fassung des Titels: JBuilder in 14 Tagen, ISBN: 3-87791-895-6