Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Die Funktionsbibliothek
10 Threads und nebenläufige Programmierung
11 Raum und Zeit
12 Datenstrukturen und Algorithmen
13 Dateien und Datenströme
14 Die eXtensible Markup Language (XML)
15 Grafische Oberflächen mit Swing
16 Grafikprogrammierung
17 Netzwerkprogrammierung
18 Verteilte Programmierung mit RMI und Web-Services
19 JavaServer Pages und Servlets
20 Applets
21 Midlets und die Java ME
22 Datenbankmanagement mit JDBC
23 Reflection und Annotationen
24 Logging und Monitoring
25 Sicherheitskonzepte
26 Java Native Interface (JNI)
27 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort
Download: - ZIP, ca. 12,5 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> /Java-Insel | vor >>
Java ist auch eine Insel von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel 7., aktualisierte Auflage geb., mit DVD (November 2007) 1.492 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1146-8 |
| 2 Sprachbeschreibung
|  | 2.1 Elemente der Programmiersprache Java
|  |  | 2.1.1 Textkodierung durch Unicode-Zeichen
|  |  | 2.1.2 Literale
|  |  | 2.1.3 Bezeichner
|  |  | 2.1.4 Reservierte Schlüsselwörter
|  |  | 2.1.5 Token
|  |  | 2.1.6 Kommentare
|  | 2.2 Anweisungen formen Programme
|  |  | 2.2.1 Anweisungen
|  |  | 2.2.2 Eine Klasse bildet den Rahmen
|  |  | 2.2.3 Die Reise beginnt am main()
|  |  | 2.2.4 Programme übersetzen und starten
|  |  | 2.2.5 Funktionsaufrufe als Ausdrücke und Anweisungen
|  |  | 2.2.6 print(), println() und printf() für Bildschirmausgaben
|  |  | 2.2.7 Modifizierer
|  |  | 2.2.8 Anweisungen und Blöcke
|  | 2.3 Datentypen
|  |  | 2.3.1 Primitive Datentypen im Überblick
|  |  | 2.3.2 Wahrheitswerte
|  |  | 2.3.3 Variablendeklarationen
|  |  | 2.3.4 Ganzzahlige Datentypen
|  |  | 2.3.5 Die Fließkommazahlen float und double
|  |  | 2.3.6 Alphanumerische Zeichen
|  | 2.4 Ausdrücke, Operanden und Operatoren
|  |  | 2.4.1 Zuweisungsoperator
|  |  | 2.4.2 Arithmetische Operatoren
|  |  | 2.4.3 Unäres Minus und Plus
|  |  | 2.4.4 Zuweisung mit Operation
|  |  | 2.4.5 Präfix- oder Postfix-Inkrement und -Dekrement
|  |  | 2.4.6 Die relationalen Operatoren und die Gleichheitsoperatoren
|  |  | 2.4.7 Logische Operatoren Und, Oder, Xor, Nicht
|  |  | 2.4.8 Rang der Operatoren in der Auswertungsreihenfolge
|  |  | 2.4.9 Die Typanpassung (das Casting)
|  |  | 2.4.10 Überladenes Plus für Strings
|  |  | 2.4.11 Was C(++)-Programmierer vermissen könnten
|  | 2.5 Bedingte Anweisungen oder Fallunterscheidungen
|  |  | 2.5.1 Die if-Anweisung
|  |  | 2.5.2 Die Alternative mit einer if/else-Anweisung wählen
|  |  | 2.5.3 Die switch-Anweisung bietet die Alternative
|  | 2.6 Schleifen
|  |  | 2.6.1 Die while-Schleife
|  |  | 2.6.2 Schleifenbedingungen und Vergleiche mit ==
|  |  | 2.6.3 Die do-while-Schleife
|  |  | 2.6.4 Die for-Schleife
|  |  | 2.6.5 Ausbruch planen mit break und Wiedereinstieg mit continue
|  |  | 2.6.6 break und continue mit Sprungmarken
|  | 2.7 Methoden einer Klasse
|  |  | 2.7.1 Bestandteil einer Funktion
|  |  | 2.7.2 Beschreibungen in der Java-API
|  |  | 2.7.3 Aufruf einer Methode
|  |  | 2.7.4 Methoden ohne Parameter
|  |  | 2.7.5 Statische Funktionen (Klassenmethoden)
|  |  | 2.7.6 Parameter, Argument und Wertübergabe
|  |  | 2.7.7 Methoden vorzeitig mit return beenden
|  |  | 2.7.8 Nicht erreichbarer Quellcode bei Funktionen
|  |  | 2.7.9 Rückgabewerte
|  |  | 2.7.10 Methoden überladen
|  |  | 2.7.11 Vorgegebener Wert für nicht aufgeführte Argumente
|  |  | 2.7.12 Finale lokale Variablen
|  |  | 2.7.13 Rekursive Funktionen
|  |  | 2.7.14 Die Türme von Hanoi
|  | 2.8 Weitere Operatoren
|  |  | 2.8.1 Bits und Bytes
|  |  | 2.8.2 Operationen auf Bit-Ebene
|  |  | 2.8.3 Die Verschiebeoperatoren
|  |  | 2.8.4 Ein Bit setzen, löschen, umdrehen und testen
|  |  | 2.8.5 Bit-Funktionen der Integer- und Long-Klasse
|  |  | 2.8.6 Der Bedingungsoperator
|  | 2.9 Einfache Benutzereingaben
|  | 2.10 Zum Weiterlesen
## 2.4 Ausdrücke, Operanden und Operatoren Beginnen wir mit mathematischen Ausdrücken, um dann die Schreibweise in Java zu ermitteln. Eine mathematische Formel, etwa der Ausdruck –27 * 9, besteht aus Operanden (engl. operand) und Operatoren (engl. operator). Ein Operand ist eine Variable oder ein Literal. Im Fall einer Variablen wird der Wert aus der Variablen ausgelesen und mit ihm die Berechnung durchgeführt.
Beispiel Ein Ausdruck mit Zuweisungen:
    int i = 12, j;
    j = i * 2;
Die Multiplikation berechnet das Produkt von 12 und 2 und speichert das Ergebnis in j ab. Von allen primitiven Variablen, die in dem Ausdruck vorkommen, wird also der Wert ausgelesen und in den Ausdruck eingesetzt. [Es gibt Programmiersprachen, in denen werden Wertoperationen besonders gekennzeichnet. So etwa in LOGO. Eine Wertoperation schreibt sich dort mit einem Doppelpunkt vor der Variablen, etwa :X + :Y. ] Dies nennt sich auch Wertoperation, da der Wert der Variablen betrachtet wird und nicht ihr Speicherort oder gar ihr Variablenname. #### Die Arten von Operatoren Operatoren verknüpfen die Operanden. Ist ein Operator auf genau einem Operand definiert, so nennt er sich unärer Operator (oder einstelliger Operator). Das Minus (negatives Vorzeichen) vor einem Operand ist ein unärer Operator, da er für genau den folgenden Operanden gilt. Die üblichen Operatoren Plus, Minus, Mal und Division sind binäre (zweistellige) Operatoren. Es gibt auch einen Fragezeichenoperator für bedingte Ausdrücke, der dreistellig ist. #### Ausdrücke Ein Ausdruck (engl. expression) ergibt bei der Auswertung ein Ergebnis. Dieser Wert wird auch Resultat genannt. Ausdrücke haben immer einen Wert, während das für Anweisungen (wie eine Schleife) nicht gilt. Daher kann ein Ausdruck an allen Stellen stehen, an denen ein Wert benötigt wird. Dieser Wert ist entweder ein numerischer Typ (von arithmetischen Ausdrücken) oder ein Referenztyp (etwa von einer Objekt-Erzeugung). Operatoren erlauben die Verbindung einzelner Ausdrücke zu neuen Ausdrücken. Einige Operatoren sind aus der Schule bekannt, wie Addition, Vergleich, Zuweisung und weitere. C(++)-Programmierer werden viele Freunde wiedererkennen. ### 2.4.1 Zuweisungsoperator Der Zuweisungsoperator kopiert den Wert eines Ausdrucks der rechten Seite in die Variable der linken Seite. In Java stellt das Gleichheitszeichen = eine Zuweisung (engl. assignment) mit dar. Der linke Teil einer Zuweisung ist eine Variable, die den Wert speichert, und nennt sich l-Wert. Der rechte Teil ist der Ausdruck, der ausgewertet in die Variable geschrieben wird. Er nennt sich r-Wert.
    int a;
    a = 12 * 3;
Die Zuweisungen sehen zwar so aus wie mathematische Gleichungen, doch existiert ein wichtiger Unterschied: Die Formel a = a + 1 ist – zumindest im Dezimalsystem ohne zusätzliche Algebra – mathematisch nicht zu erfüllen, da es kein a geben kann, das a = a + 1 erfüllt. Aus Programmiersicht ist es in Ordnung, da die Variable a um eins erhöht wird. In anderen Programmiersprachen wird die Zuweisung durch ein anderes Symbol deutlich gemacht (etwa :=); Java folgt hier der Tradition von C(++) und definiert einen binären Vergleichsoperator mit ==.
Hinweis Eine Zuweisung ist insbesondere ein Ausdruck, der einen Wert liefert. Zwar finden sich Zuweisungen oft als Anweisungen wieder, doch können sie an jeder Stelle stehen, an der ein Ausdruck erlaubt ist, etwa in einem Funktionsaufruf wie print():
    int a = 1;                    // Deklaration mit Initialisierung
    a = 2;                        // Anweisung mit Zuweisung
    System.out.println( a = 3 );  // Ausdruck mit Zuweisung. Liefert 3
    System.out.println( a == 3 ); // Ausdruck mit Vergleich. Liefert true
#### Mehrere Zuweisungen in einer Anweisung Zuweisungen der Form a = b = 0 sind erlaubt und gleichbedeutend mit zwei Anweisungen b = 0 und a = b beziehungsweise mit expliziter Klammerung a = (b = 0). Daran lässt sich ablesen, dass beim Zuweisungsoperator die Auswertung von rechts nach links erfolgt. Doch auch wenn wir meinen, dass
    a = (b = c + d) + e;
eine Vereinfachung im Vergleich zu
    b = c + d;
    a = b + e;
ist, sollten wir mit einer Zuweisung pro Zeile auskommen. ### 2.4.2 Arithmetische Operatoren Ein arithmetischer Operator verknüpft die Operanden mit den Operatoren Addition (+), Subtraktion (-), Multiplikation (*) und Division (/). Zusätzlich gibt es den Restwert-Operator %, der den bei der Division verbleibenden Rest betrachtet. Alle Operatoren sind für ganzzahlige Werte sowie für Fließkommazahlen definiert. [In C sind sie nur für Ganzzahlen definiert. ] Die arithmetischen Operatoren sind binär, und auf der linken und rechten Seite sind die Typen numerisch. Der Ergebnistyp ist ebenfalls numerisch. #### Numerische Umwandlung Bei unterschiedlichen Datentypgrößen bringt der Compiler vor der Anwendung der Operation alle Operanden auf den größten vorkommenden Typ. Das nennt sich numerische Umwandlung (engl. numeric promotion). Bei byte und short gilt die Sonderregelung, dass sie vorher auf int konvertiert werden. [http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#26917 ] (Auch im Java Bytecode gibt es keine arithmetischen Operationen auf byte, short und char.) Anschließend wird die Operation ausgeführt, und der Ergebnistyp entspricht dem umfassenderen Typ. #### Der Divisionsoperator Der binäre Operator »/« bildet den Quotienten aus Dividend und Divisor. Auf der linken Seite steht der Dividend und auf der rechten der Divisor. Die Division ist für Ganzzahlen und für Fließkommazahlen definiert. Bei der Ganzzahldivision wird zu null hin gerundet, und das Ergebnis ist keine Fließkommazahl, so dass 1/3 das Ergebnis 0 ergibt, und nicht 0,333 ... Den Datentyp des Ergebnisses bestimmen die Operanden und nicht der Operator. Soll das Ergebnis vom Typ double sein, muss ein Operand ebenfalls double sein.
    System.out.println( 1.0 / 3 );          // 0.3333333333333333
    System.out.println( 1   / 3.0 );        // 0.3333333333333333
    System.out.println( 1 / 3 );            // 0
Schon in der Schulmathematik war die Division durch null nicht definiert. Führen wir eine Ganzzahldivision mit dem Divisor 0 durch, so bestraft uns Java mit einer ArithmeticException. Bei Fließkommazahlen verläuft dies anders. Eine Division durch 0 liefert +/– unendlich und ein NaN bei 0.0/0.0. Ein NaN steht für Not-A-Number (auch schon manchmal »Unzahl« genannt) und wird vom Prozessor erzeugt, falls er eine mathematische Operation wie die Division durch null nicht durchführen kann. In Kapitel 5 werden wir auf NaN noch einmal zurückkommen.
Anekdote Beim Lenkraketenkreuzer USS Yorktown gab ein Mannschaftsmitglied aus Versehen die Zahl Null ein. Das führte zu einer Division durch null, und der Fehler pflanzte sich so weit fort, dass die Software abstürzte und das Antriebssystem stoppte. Das Schiff trieb mehrere Stunden antriebslos im Wasser.
#### Der Restwert-Operator % Eine Ganzzahldivision muss nicht unbedingt glatt aufgehen, wie im Fall 9/2. In diesem Fall gibt es den Rest 1. Diesen Rest liefert der Restwert-Operator (engl. remainder operator), oft auch Modulo genannt. (Mathematiker unterscheiden die beiden Begriffe Rest und Modulo, da ein Modulo nicht negativ ist, der Rest in Java aber schon. Das soll uns aber egal sein.)
    System.out.println( 9 % 2 );            // 1
Im Gegensatz zu C(++) [Wir müssten in C(++) die Funktion fmod() benutzen. ] ist der Restwert-Operator in Java auch auf Fließkommazahlen anwendbar, und die Operanden können negativ sein. [Die Sprachdefinition von C(++) schreibt bei der Division und beim Modulo mit negativen Zahlen keine Berechnungsmethode vor. ]
    System.out.println( 12. % 2.5 );        // 2.0
Die Division und der Restwert richten sich in Java nach einer einfachen Formel: int(a/b)*b + (a%b) = a.
Beispiel Die Gleichung ist erfüllt, wenn wir etwa a = 10 und b = 3 wählen. Es gilt: int(10/3) = 3 und 10 % 3 ergibt 1. Dann ergeben 3 * 3 + 1 = 10.
Aus dieser Gleichung folgt, dass beim Restwert das Ergebnis nur dann negativ ist, wenn der Dividend negativ ist; er ist nur dann positiv, wenn der Dividend positiv ist. Es ist leicht einzusehen, dass das Ergebnis der Restwert-Operation immer echt kleiner ist als der Wert des Divisors. Wir haben den gleichen Fall wie bei der Ganzzahldivision, dass ein Divisor mit dem Wert 0 eine ArithmeticException auslöst und bei Fließkommazahlen zum Ergebnis NaN führt. Listing 2.5 RemainerAndDivDemo.java, main()
    System.out.println( "+5% +3 = " + (+5% +3) );   //  2
    System.out.println( "+5 / +3 = " + (+5 / +3) ); //  1

    System.out.println( "+5% –3 = " + (+5% –3) );   //  2
    System.out.println( "+5 / –3 = " + (+5 / –3) ); // –1

    System.out.println( "-5% +3 = " + (-5% +3) );   // –2
    System.out.println( "-5 / +3 = " + (-5 / +3) ); // –1

    System.out.println( "-5% –3 = " + (-5% –3) );   // –2
    System.out.println( "-5 / –3 = " + (-5 / –3) ); //  1
Gewöhnungsbedürftig ist die Tatsache, dass der erste Operand (Dividend) das Vorzeichen des Restes definiert und niemals der zweite (Divisor).
Hinweis Um mit value % 2 == 1 zu testen, ob value eine ungerade Zahl ist, muss value positiv sein, denn –3 % 2 wertete Java zu –1 aus. Der Test auf ungerade Zahlen wird erst wieder korrekt mit value % 2 != 0.
#### Restwert für Fließkommazahlen und IEEEremainder() Über die oben genannte Formel können wir auch bei Fließkommazahlen das Ergebnis einer Restwert-Operation leicht berechnen. Dabei muss beachtet werden, dass sich der Operator nicht so wie unter IEEE 754 verhält. Denn diese Norm schreibt vor, dass die Restwert-Operation den Rest von einer rundenden Division berechnet und nicht von einer abschneidenden. So wäre das Verhalten nicht analog zum Restwert bei Ganzzahlen. Java definiert den Restwert jedoch bei Fließkommazahlen genauso wie den Restwert bei Ganzzahlen. Wünschen wir ein Restwert-Verhalten, wie es IEEE 754 vorschreibt, so können wir immer noch die Bibliotheksfunktion Math.IEEEremainder() verwenden. Auch bei der Restwert-Operation bei Fließkommazahlen werden wir niemals eine Exception erwarten. Eventuelle Fehler werden, wie im IEEE-Standard beschrieben, mit NaN angegeben. Ein Überlauf oder Unterlauf kann zwar passieren, aber nicht geprüft werden. #### Rundungsfehler Prinzipiell sollten Anweisungen wie 1.1 – 0.1 immer 1.0 ergeben, jedoch treten interne Rundungsfehler bei der Darstellung auf und lassen das Ergebnis von Berechnung zu Berechnung immer ungenauer werden. Ein besonders ungünstiger Fehler trat 1994 beim Pentium-Prozessor im Divisionsalgorithmus Radix-4 SRT auf, ohne dass der Programmierer der Schuldige war.
    double x, y, z;
    x = 4195835.0;
    y = 3145727.0;
    z = x – (x/y) * y;
    System.out.println( z );
Ein fehlerhafter Prozessor liefert hier 256, obwohl laut Rechenregel das Ergebnis 0 sein muss. Laut Intel sollte für einen normalen Benutzer (Spieler, Softwareentwickler, Surfer?) der Fehler nur alle 27 000 Jahre auftauchen. Glück für die meisten. Eine Studie von IBM errechnete eine Fehlerhäufigkeit von einmal in 24 Tagen. Alles in allem hat Intel die CPUs zurückgenommen, über 400 Millionen US-Dollar verloren und spät den Kopf gerade noch aus der Schlinge gezogen. Die meisten Rundungsfehler resultieren aber daher, dass endliche Dezimalbrüche im Rechner als Näherungswerte für periodische Binärbrüche repräsentiert werden müssen. 0,1 entspricht einer periodischen Mantisse im IEEE-Format. ### 2.4.3 Unäres Minus und Plus Die binären Operatoren sitzen zwischen zwei Operanden, während sich ein unärer Operator genau einen Operanden vornimmt. Das unäre Minus (Operator zur Vorzeichenumkehr) etwa dreht das Vorzeichen des Operanden um. So wird aus einem positiven Wert ein negativer und aus einem negativen ein positiver.
Beispiel Drehe das Vorzeichen einer Zahl um:
    a = -a;
Alternativ ist:
    a = -1 * a;
Das unäre Plus ist eigentlich unnötig; die Entwickler haben es jedoch aus Symmetriegründen mit eingeführt.
Beispiel Minus und Plus sitzen direkt vor dem Operanden, und der Compiler weiß selbstständig, ob dies unär oder binär ist. Der Compiler erkennt auch folgende Konstruktion:
    int i = - - - 2 + - + 3;
Dies ergibt den Wert -5. Einen Ausdruck wie ---2+-+3 erkennt der Compiler dagegen nicht an, da die zusammenhängenden Minuszeichen als Inkrement interpretiert werden und nicht als unärer Operator. Das Leerzeichen ist also bedeutend.
#### Vorzeichen erfragen Um für das Vorzeichen einen Wert +1 für positive oder –1 für negative Zahlen und 0 für 0 zu bekommen, lässt sich die Funktion signum() verwenden. Sie ist nicht ganz logisch auf die Klasse Math für Fließkommazahlen und Integer/Long für Ganzzahlen verteilt: java.lang.Integer.signum( int i ) java.lang.Long.signum( long i ) java.lang.Math.signum( double d ) java.lang.Math.signum( float f ) ### 2.4.4 Zuweisung mit Operation In Java lassen sich Zuweisungen mit numerischen Operatoren kombinieren. Für einen Operator # im Ausdruck a = a # (b) kürzt der Verbundoperator den Ausdruck zu a #= b ab. So addiert a += 2 zur Variable a 2 hinzu, und der Rückgabewert ist die um 2 erhöhte Variable a. Besondere Obacht sollten wir auf die automatische Klammerung geben. Bei einem Ausdruck wie a *= 3 + 5 gilt a = a * (3 + 5) und nicht selbstverständlich die Punkt-vor-Strich-Regelung a = a * 3 + 5. Falls es sich bei der rechten Seite um einen komplexeren Ausdruck handelt, wird dieser nur einmal ausgewertet. Dies ist wichtig bei Methodenaufrufen, die Nebenwirkungen besitzen, etwa Zustände wie einen Zähler verändern.
Beispiel Wir profitieren auch bei Feldzugriffen (siehe Abschnitt 3.9, »Arrays«) von Verbundoperationen, da die Auswerung des Indexes nur einmal stattfindet:
    feld[ 2 * i + j ] = feld[ 2 * i + j ] + 1;
Leichter zu lesen ist die folgende Anweisung:
    feld[ 2 * i + j ] += 1;
#### Typanpassung beim Verbundoperator Beim Verbundoperator wird noch etwas mehr gemacht, als E1 #= E2 zu E1 = (E1) # (E2) aufzulösen. Interessanterweise kommt auch noch der Typ von E1 ins Spiel, denn der Ausdruck E1 # E2 wird vor der Zuweisung auf den Datentyp von E1 gebracht, sodass es genau heißen muss: E1 #= E2 wird zu E1 = (Typ von E1)((E1) # (E2)).
Beispiel Auf eine Ganzzahl soll der Verbundoperator eine Fließkommazahl addieren.
    int i = 1973;
    i += 30.2;
Die Anwendung des Verbundoperators ist in Ordnung, denn der Übersetzer nimmt eine implizite Typanpassung vor, sodass die Bedeutung bei i = (int)(i + 30.2) liegt. So viel dazu, dass Java eine intuitive und einfache Programmiersprache sein soll.
### 2.4.5 Präfix- oder Postfix-Inkrement und -Dekrement Das Herauf- und Heruntersetzen von Variablen ist eine sehr häufige Operation, wofür die Entwickler in der Vorgängersprache C auch einen Operator spendiert hatten. Die praktischen Operatoren ++ und -- kürzen die Programmzeilen zum Inkrement und Dekrement ab.
    i++;     // Abkürzung für i = i + 1
    j--;     //               j = j – 1
Eine lokale Variable muss allerdings vorher initialisiert sein, da ein Lesezugriff vor einem Schreibzugriff stattfindet. #### Vorher oder nachher Die beiden Operatoren liefern einen Ausdruck und geben daher einen Wert zurück. Es macht jedoch einen feinen Unterschied, wo dieser Operator platziert wird. Es gibt ihn nämlich in zwei Varianten: vor der Variable und dahinter. Steht das Inkrement vor der Variable, sprechen wir von Prä-Inkrement/Prä-Dekrement, steht es dahinter, von Post-Inkrement/Post-Dekrement – kurz auch Präfix/Postfix genannt. Nutzen wir einen Präfix-Operator, so wird die Variable erst herauf- beziehungsweise heruntergesetzt und dann der Wert geliefert. Neben der Wertrückgabe gibt es eine Veränderung der Variable.
Beispiel Präfix/Postfix in einer Ausgabeanweisung:
    int i = 10, j = 20;
    System.out.println( ++i );       // 11
    System.out.println( --j );       // 19
    System.out.println( i );         // 11
    System.out.println( j );         // 19
Die Variable wird erst heraufgesetzt und dann ausgegeben. Wiederholen wir mit i und j die Ausgaben mit Postfix:
    int i = 10, j = 20;
    System.out.println( i++ );       // 10
    System.out.println( j-- );       // 20
    System.out.println( i );         // 11
    System.out.println( j );         // 19
Der Wert wird im Ausdruck verwendet und erst anschließend heraufgesetzt. Wir bekommen mit dem Präfix den Ausdruck nach der Operation und mit dem Postfix den Ausdruck davor.
Das Post-Inkrement finden wir auch im Namen der Programmiersprache C++. Es soll ausdrücken, dass es C-mit-eins-drauf ist, also ein verbessertes C. Mit dem Wissen über den Postfix-Operator ist klar, dass wir erst einen Zugriff haben und dann die Erhöhung stattfindet – also C++ ist auch nur C, und der Vorteil kommt später. (Einer der Entwickler von Java, Bill Joy, hat einmal Java als C++-- [--C++ könnte besser passen: Erst wird C++ bereinigt und dann zu Java erweitert. ] beschrieben. Er meinte damit C++ ohne die schwer zu pflegenden Eigenschaften.) Bei den von Microsoft geschaffenen Buchstabe-#-Sprachen, wie C#, – das # liest sich »Sharp« – wurde die Idee von den Musiknoten entlehnt. Ein Sharp hinter einer Note bedeutet, dass sie um einen Halbton erhöht wird.
Beispiel In Java sind Inkrement (++) und Dekrement (--) für alle numerischen Datentypen erlaubt, also auch für Fließkommazahlen.
    double d = 12;
    System.out.println( --d );       // 11.0
    double e = 12.456;
    System.out.println( --e );       // 11.456
#### Einige Kuriositäten Wir wollen uns abschließend noch mit einer Besonderheit des Post-Inkrements und Prä-Inkrements beschäftigen, die nicht nachahmenswert ist:
    a = 2;
    a = ++a;      // a = 3
    b = 2;
    b = b++;      // b = 2
Im ersten Fall bekommen wir den Wert 3 und im zweiten Fall 2. Der erste Fall überrascht nicht. Denn a = ++a erhöht den Wert 2 um 1, und anschließend wird 3 der Variablen a zugewiesen. Bei b ist es raffinierter. Der Wert von b ist 2, und dieser Wert wird intern vermerkt. Anschließend erhöht b++ die Variable b. Doch die Zuweisung setzt b auf den gemerkten Wert, der 2 war. Also ist b = 2. ### 2.4.6 Die relationalen Operatoren und die Gleichheitsoperatoren Relationale Operatoren sind Vergleichsoperatoren, die Ausdrücke miteinander vergleichen und einen Wahrheitswert vom Typ boolean zurückgeben. Die von Java für numerische Vergleiche zur Verfügung gestellten Operatoren sind: Größer (>) Kleiner (<) Größer-gleich (>=), Kleiner-gleich (<=) Weiterhin gibt es einen Spezial-Operator instanceof zum Testen von Referenzeigenschaften. Zudem kommen zwei Vergleichsoperatoren hinzu, die Java als Gleichheitsoperatoren bezeichnet: Test auf Gleichheit (==) Test auf Ungleichheit (!=) Dass Java hier einen Unterschied macht, liegt an einem etwas anderen Vorrang, der uns aber nicht weiter beschäftigen soll.
Hinweis Bei einem Gleichheitsvergleich zwischen Variable und Literal schreiben viele Entwickler die Variable gerne links und die Konstante rechts, etwa in folgender Fallunterscheidung:
    if ( anzahlZentnerGoldes == 666 )
Beide Operanden können aber vertauscht werden, was am Ergebnis nichts ändert, denn der Vergleichsoperator ist kommutativ, wenn denn die beiden Seiten keine beeinflussenden Seiteneffekte produzieren, also etwa Zustände ändern.
    if ( 666 == anzahlZentnerGoldes )
Ebenso wie arithmetische Operatoren passen die relationalen Operatoren ihre Operanden an einen gemeinsamen Typ an. Handelt es sich bei den Typen um Referenztypen, so sind nur die Vergleichsoperatoren == und != erlaubt. #### Kaum Verwechslungsprobleme durch == und = Die Verwendung des relationalen Operators == und der Zuweisung = führt bei Einsteigern oft zu Problemen, da die Mathematik für Vergleiche und Zuweisungen immer nur ein Gleichheitszeichen kennt. Glücklicherweise ist das Problem in Java nicht so drastisch wie beispielsweise in C(++), da die Typen der Operatoren unterschiedlich sind. Der Vergleichsoperator ergibt immer nur den Rückgabewert boolean. Zuweisungen von numerischen Typen ergeben jedoch wieder einen numerischen Typ. Es kann also kein Problem wie das folgende geben:
    int a = 10, b = 11;
    boolean result1 = ( a = b );        // Compilerfehler
    boolean result2 = ( a == b );       // Das ist OK
Beispiel Die Wahrheitsvariable hatVorzeichen soll dann true sein, wenn das Zeichen vorzeichen gleich dem Minus ist.
    boolean hatVorzeichen = (vorzeichen == '-');
Schön ist die Auswertungsreihenfolge zu sehen: Erst wird das Ergebnis des Vergleichs berechnet, und dieser Wahrheitswert wird anschließend in hatVorzeichen kopiert.
### 2.4.7 Logische Operatoren Und, Oder, Xor, Nicht Mit logischen Operatoren werden Wahrheitswerte nach definierten Mustern verknüpft. Logische Operatoren operieren nur auf boolean-Typen, andere Typen führen zu Compilerfehlern. Java bietet die Operatoren Und (&&), Oder (||), Xor (^) und Nicht (!) an. Xor ist eine Operation, die genau dann falsch zurückgibt, wenn entweder beide Operatoren wahr oder beide falsch sind. Sind sie unterschiedlich, so ist das Ergebnis wahr. Xor heißt auch exklusives beziehungsweise ausschließendes Oder. #### Kurzschlussoperatoren Eine Besonderheit sind die beiden Operatoren && (Und) beziehungsweise || (Oder). In der Regel muss ein logischer Ausdruck nur dann weiter ausgewertet werden, wenn er das Schluss-ergebnis noch beeinflussen kann. Zwei Operatoren bieten sich zur Optimierung der Ausdrücke an: Und: Ist einer der beiden Ausdrücke falsch, so kann der Ausdruck schon nicht mehr wahr werden. Das Ergebnis ist falsch. Oder: Ist mindestens einer der Ausdrücke schon wahr, so ist auch der gesamte Ausdruck wahr. Der Compiler bzw. die Laufzeitumgebung kann den Programmfluss abkürzen. Daher nennen sich die beiden Operatoren auch Kurzschlussoperatoren (engl. short-circuit-operator). [Den Begriff verwendet die Java-Sprachdefinition nicht! Siehe dazu auch http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.23. ] #### Nicht-Kurzschlussoperatoren In einigen Fällen ist erwünscht, dass die Laufzeitumgebung alle Teilausdrücke auswertet. Das kann der Fall sein, wenn Funktionen Nebenwirkungen haben sollen, etwa Zustände ändern. Daher bietet Java zusätzlich die nicht über einen Kurzschluss arbeitenden Operatoren | und & an, die eine Auswertung aller Teilausdrücke erzwingen.
Beispiel In dem ersten Ausdruck wird die Methode foo() nicht aufgerufen, im zweiten schon.
    boolean b1 = true || foo();   // foo() wird nicht aufgerufen
    boolean b2 = false & foo();   // foo() wird aufgerufen
Für Xor kann es keinen Kurzschlussoperator geben, da immer beide Operanden ausgewertet werden müssen, bevor das Ergebnis feststeht. ### 2.4.8 Rang der Operatoren in der Auswertungsreihenfolge Aus der Schule ist der Spruch »Punktrechnung geht vor Strichrechnung« bekannt, sodass sich der Ausdruck 1 + 2 * 3 zu 7 und nicht zu 9 auswertet. [Dass von diesen Rechnungen eine gewisse Spannung ausgeht, zeigen diverse Fernsehkanäle, die damit ihr Abendprogramm füllen. ]
Beispiel Auch wenn bei Ausdrücken wie a() + b() * c() zuerst das Produkt gebildet wird, schreibt doch die Auswertungsreihenfolge von binären Operatoren vor, dass der linke Operand zuerst ausgewertet werden muss, was bedeutet, dass Java zuerst die Methode a() aufruft.
In den meisten Programmiersprachen gibt es eine Unzahl von Operatoren neben Plus und Mal, die alle ihre eigenen Vorrangregeln besitzen. [Es gibt Programmiersprachen wie APL, die keine Vorrangregeln kennen. Sie werten die Ausdrücke streng von rechts nach links oder umgekehrt aus. ] Der Multiplikationsoperator besitzt zum Beispiel eine höhere Priorität und damit eine andere Auswertungsreihenfolge als der Plus-Operator. Die Rangordnung der Operatoren (engl. operator precedence) legt folgende Tabelle fest:
Tabelle 2.6 Operatoren mit Rangordnung in Java
Operator | Rang | Typ | Beschreibung
++, -- | 1 | Arithmetisch | Inkrement und Dekrement
+, - | 1 | Arithmetisch | unäres Plus und Minus
~ | 1 | Integral | bitweises Komplement
! | 1 | Boolean | logisches Komplement
(Typ) | 1 | Jeder | Cast
*, /, % | 2 | Arithmetisch | Multiplikation, Division, Rest
+, - | 3 | Arithmetisch | Addition und Subtraktion
+ | 3 | String | String-Konkatenation
<< | 4 | Integral | Verschiebung links
>> | 4 | Integral | Rechtsverschiebung mit Vorzeichenerweiterung
>>> | 4 | Integral | Rechtsverschiebung ohne Vorzeichenerweiterung
<, <=, >, >= | 5 | Arithmetisch | numerische Vergleiche
instanceof | 5 | Objekt | Typvergleich
==, != | 6 | Primitiv | Gleich-/Ungleichheit von Werten
==, != | 6 | Objekt | Gleich-/Ungleichheit von Referenzen
& | 7 | Integral | bitweises Und
& | 7 | Boolean | logisches Und
^ | 8 | Integral | bitweises Xor
^ | 8 | Boolean | logisches Xor
| | 9 | Integral | bitweises Oder
| | 9 | Boolean | logisches Oder
&& | 10 | Boolean | logisches konditionales Und, Kurzschluss
|| | 11 | Boolean | logisches konditionales Oder, Kurzschluss
?: | 12 | Alles | Bedingungsoperator
= | 13 | Jede | Zuweisung
*=, /=, %=, +=, -=, <<=, >>=, >>>=, &=, ^=, |= | 14 | Jede | Zuweisung mit Operation
Die Rechenregeln für Mal vor Plus kann sich jeder noch leicht merken. Auch ist leicht zu merken, dass die typischen arithmetischen Operatoren wie Plus und Mal eine höhere Priorität als Vergleichsoperationen haben. Komplizierter ist die Auswertung bei den zahlreichen Operatoren, die seltener im Programm vorkommen.
Beispiel Wie ist die Auswertung bei dem nächsten Ausdruck?
    boolean A = false,
            B = false,
            C = true;
    System.out.println( A && B || C );
Das Ergebnis ist ja nach Randord true oder false. Die Tabelle lehrt uns, dass im Beispiel A && B || C das Und stärker als das Oder bindet, also der Wert mit der Belegung A=false, B=false, C=true zu true ausgewertet wird.
Vermutlich gibt es Programmierer, die dies wissen oder eine Tabelle mit Rangordnungen immer am Monitor kleben haben. Aber beim Durchlesen von fremdem Code ist es nicht schön, immer wieder die Tabelle konsultieren zu müssen, die verrät, ob nun das binäre Xor oder das binäre Und stärker bindet.
Tipp Alle Ausdrücke, die über die einfache Regel »Punktrechnung geht vor Strichrechnung« hinausgehen, sollten geklammert werden. Da die unären Operatoren ebenfalls sehr stark binden, kann eine Klammerung wegfallen.
#### Links- und Rechtsassoziativität Bei den Operatoren + und * gilt die mathematische Kommutativität und Assoziativität. Das heißt, die Operanden können prinzipiell umgestellt werden, und das Ergebnis sollte davon nicht beeinträchtigt sein. Bei der Division unterscheiden wir zusätzlich Links- und Rechtsassoziativität. Deutlich wird das am Beispiel A / B / C. Den Ausdruck wertet Java von links nach rechts aus, und zwar als (A / B) / C; daher ist der Divisionsoperator linksassoziativ. Hier sind Klammern angemessen. Denn würde der Compiler den Ausdruck zu A / (B / C) auswerten, käme es einem A * C / B gleich. In Java sind die meisten Operatoren linksassoziativ, aber es gibt Ausnahmen, wie Zuweisungen der Art A = B = C, die der Compiler zu A = (B = C) auswertet.
Hinweis Die mathematische Assoziativität ist natürlich gefährdet, wenn Rechenfehler mit im Spiel sind. Java würde sich nie anmaßen, die Operanden umzustellen.
    float a = –16777217F;
    float b =  16777216F;
    float c = 1F;

    System.out.println( a + b + c );    // 1.0
    System.out.println( a + (b + c) );  // 0.0
### 2.4.9 Die Typanpassung (das Casting) Zwar ist Java eine getypte Sprache, aber nicht so stark, dass es hinderlich ist. So übersetzt der Compiler die folgenden Zeilen problemlos:
    int  anInt = 1;
    long long1 = 1;
    long long2 = anInt;
Streng genommen könnte ein Compiler bei einer sehr starken Typisierung die beiden unteren Zeilen ablehnen, denn das Literal 1 ist vom Typ int und kein 1L, also long, und in long2 = anInt ist die Variable anInt vom Typ int statt vom gewünschten Datentyp long. #### Arten der Typanpassung In der Praxis kommt es also vor, dass Datentypen konvertiert werden müssen. Dies nennt sich Typanpassung (engl. typecast) oder auch casten. Java unterscheidet zwei Arten der Typanpassung: Automatische (implizite) Typanpassung. Daten eines kleineren Datentyps werden automatisch (implizit) dem größeren angepasst. Der Compiler nimmt diese Anpassung selbstständig vor. Daher funktioniert unser erstes Beispiel. Explizite Typanpassung. Ein größerer Typ kann einem kleineren Typ mit möglichem Verlust von Informationen zugewiesen werden. Typanpassungen gibt es bei primitiven Datentypen und bei Referenztypen. Während die folgenden Absätze die Anpassungen bei einfachen Datentypen beschreiben, kümmert sich Kapitel 6 um die Typkompatibilität bei Referenzen. #### Automatische Anpassung der Größe Werte der Datentypen byte und short werden bei Rechenoperationen automatisch in den Datentyp int umgewandelt. Ist ein Operand vom Datentyp long, dann werden alle Operanden auf long erweitert. Wird aber short oder byte als Ergebnis verlangt, dann ist dieses durch einen expliziten Typecast anzugeben, und nur die niederwertigen Bit des Ergebniswerts werden übergeben. Folgende Typumwandlungen führt Java automatisch aus:
Tabelle 2.7 Implizite Typanpassungen
Von Typ | In Typ
byte | short, char, int, long, float, double
short | int, long, float, double
char | int, long, float, double
int | long, float, double
long | float, double
float | double
Die Anpassung wird im Englischen auch widening conversion genannt, weil sie den Wertebereich automatisch erweitert. #### Explizite Typanpassung Die explizite Anpassung engt einen Typ ein, sodass diese Operation auch narrowing conversion genannt wird. Der gewünschte Typ für eine Typanpassung wird vor den umzuwandelnden Datentyp in Klammern gesetzt.
Beispiel Umwandlung einer Fließkommazahl in eine Ganzzahl:
    int n = (int) 3.1415;                  // n = 3
Hier klicken, um das Bild zu vergrößern Passt der Typ eines Ausdrucks nicht, lässt er sich mit + korrigieren. Eine Typumwandlung hat eine sehr hohe Priorität. Daher muss der Ausdruck gegebenenfalls geklammert werden.
Beispiel Die Zuweisung an n verfehlt das Ziel.
    int n = (int) 1.0315 + 2.1;
    int m = (int)(1.0315 + 2.1);            // das ist korrekt
#### Typumwandlung von Fließkommazahlen in Ganzzahlen Bei der expliziten Typumwandlung von double und float in einen Ganzzahltyp kann es selbstverständlich zum Verlust von Genauigkeit kommen sowie zur Einschränkung des Wertebereichs. Bei der Konvertierung von Fließkommazahlen verwendet Java eine Rundung gegen null.
    System.out.println( (int) +12.34 );     //  12
    System.out.println( (int) +67.89 );     //  67
    System.out.println( (int) –12.34 );     // –12
    System.out.println( (int) –67.89 );     // –67
Bei der Konvertierung eines größeren Ganzzahltyps in einen kleineren werden einfach die oberen Bits abgeschnitten. Eine Anpassung des Vorzeichens findet nicht statt. Die Darstellung in Bit zeigt das sehr anschaulich:
    int   ii = 123456789;     // 00000111010110111100110100010101
    int   ij =   –123456;     // 11111111111111100001110111000000

    short si = (short) ii;    //                 1100110100010101
    short sj = (short) ij;    //                 0001110111000000

    System.out.println( si ); // –13035
    System.out.println( sj ); //   7616
si wird eine negative Zahl, da das 16. Bit beim int ii gesetzt war und nun beim short das negative Vorzeichen anzeigt. Die Zahl hinter ij hat kein 16. Bit gesetzt, und so wird das short sj positiv. #### Unterschiedliche Wertebereiche bei Fließ- und Ganzzahlen Natürlich kann die Konvertierung double long nicht verlustfrei sein. Wie sollte das auch gehen? Zwar verfügt sowohl ein long als auch ein double über 64 Bit zur Datenspeicherung, aber ein double kann eine Ganzzahl nicht so effizient speichern wie ein long und hat etwas »Overhead« für einen großen Exponenten. Bei der impliziten Konvertierung eines long in ein double können einige Bit als Informationsträger herausfallen, wie es das folgende Beispiel illustriert.
    long   l = 1111111111111111111L; // 1111111111111111111
    double d = l;                    // 1111111111111111170 (1.11111111111111117E18)
    long   m = (long) d;             // 1111111111111111168
Java erlaubt ohne explizite Anpassung die Konvertierung eines long an ein double und auch an ein noch kleineres float, was vielleicht noch merkwürdiger ist, da float nur eine Genauigkeit von 6 bis 7 Stellen, long hingegen 18 Stellen hat.
    long  l = 1000000000000000000L;
    float f = l;
    System.out.printf( "%f", f );    // 999999984306749440,000000
#### short und char Ein short hat wie ein char eine Länge von 16 Bit. Doch diese Umwandlung ist nicht ohne ausdrückliche Konvertierung möglich. Das liegt am Vorzeichen von short. Zeichen sind per Definition immer ohne Vorzeichen. Würde ein char mit einem gesetzten höchstwertigen letzten Bit in ein short konvertiert, käme eine negative Zahl heraus. Ebenso wäre, wenn ein short eine negative Zahl bezeichnet, das oberste Bit im char gesetzt, was unerwünscht ist. Die ausdrückliche Umwandlung erzeugt immer nur positive Zahlen. Der Verlust bei der Typumwandlung von char nach short tritt etwa bei der Han-Zeichenkodierung für chinesische, japanische oder koreanische Zeichen auf, weil dort im Unicode das erste Bit gesetzt ist, das bei der Umwandlung in ein short dem nicht gesetzten Vorzeichen-Bit weichen muss. #### Typanpassungen von int und char Die Methode printXXX() reagiert auf die Typen char und int, und eine Typumwandlung führt zur gewünschten Ausgabe.
    int  c1 = 65;
    char c2 = 'A';
    System.out.println( c1 );              // 65
    System.out.println( (int)c2 );         // 65
    System.out.println( (char)c1 );        // A
    System.out.println( c2 );              // A
    System.out.println( (char)(c1 + 1) );  // B
    System.out.println( c2 + 1 );          // 66
Einen Ganzzahlwert in einem int können wir als Zeichen ausgeben, genauso wie eine char-Variable als Zahlenwert. Wir sollten beachten, dass eine mathematische Operation auf char-Typen zu einem int führt. Daher funktioniert für ein char c Folgendes nicht:
    c = c + 1;
Richtig wäre c = (char)(c + 1). #### Berechnungen bei Datentypen byte und short auf int-Basis Leider ist die Typanpassung nicht ganz so einleuchtend, wie folgendes Beispiel zeigt: Listing 2.6 AutoConvert.java, main()
    short s1 = 1, s2 = 2;
    byte  b1 = 1, b2 = 2;
    int   i1 = 1, i2 = 2;
    long  l1 = 1, l2 = 2;
    // short s3 = s1 + s2;  // Type mismatch: cannot convert from int to short
    // byte  b3 = b1 + b2;  // Type mismatch: cannot convert from int to byte
    short s3 = (short)( s1 + s2 );
    byte  b3 =  (byte)( b1 + b2 );
    int   i3 = i1 + i2;
    long  l3 = l1 + l2;
Dies ist auf den ersten Blick paradox. Es ist nicht möglich, ohne explizite Typumwandlung zwei short- oder byte-Zahlen zu addieren. Das Verhalten des Übersetzers lässt sich mit der automatischen Anpassung erklären. Wenn Ganzzahl-Ausdrücke vom Typ kleiner int mit einem Operator verbunden werden, passt der Compiler eigenmächtig den Typ auf int an. Die Addition der beiden Zahlen arbeitet also nicht mit short- oder byte-Werten, sondern mit int-Werten; intern im Bytecode ist es ebenso realisiert. Überläufe werden korrekt behandelt. Bei der Zuweisung wird dies zum Problem. Denn dann steht auf der rechten Seite ein int und auf der linken Seite der kleinere Typ byte oder short. Nun muss der Compiler meckern, da Zahlen abgeschnitten werden könnten. Mit der ausdrücklichen Typumwandlung erzwingen wir diese Konvertierung und akzeptieren ein paar fehlende Bit. Diese Eigenart ist insofern verwunderlich, als auch ein int nur dann zu einem long erweitert wird, wenn einer der Operanden eines Ausdrucks vom Typ long ist. [http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.6.1 ]
Tipp »Kleine« Typen wie short und byte führen oft zu Problemen. Wenn sie nicht absichtlich in großen Feldern verwendet werden und Speicherplatz nicht ein absolutes Kriterium ist, erweist sich int als die beste Wahl – auch weil Java nicht durch besonders intuitive Typ-Konvertierungen glänzt, wie das Beispiel mit dem unären Minus und Plus zeigt:
    byte b = 0;
    b = -b;             // "Cannot convert from int to byte"
    b = +b;             // "Cannot convert from int to byte"
Der Compiler meldet einen Fehler, denn der Ausdruck auf der rechten Seite wird durch den unären Operator in ein int umgewandelt; was immer für die Typen byte, short und char gilt.31
#### Materialverlust durch Überläufe Überläufe bei Berechnungen können zu schwerwiegenden Fehlern führen, so wie beim Absturz der Ariane 5 am 4. Juni 1996 genau 36,7 Sekunden nach dem Start. Die europäische Raumfahrtbehörde European Space Agency (ESA) hatte die unbemannte Rakete, die vier Satelliten an Bord hatte, von Französisch-Guyana aus gestartet. Glücklicherweise kamen keine Menschen ums Leben, doch der materielle Schaden belief sich auf etwa 500 Millionen US-Dollar. In dem Projekt steckten zusätzlich Entwicklungskosten von etwa 7 Milliarden US-Dollar. Grund für den Absturz war ein Rundungsfehler, der durch die Umwandlung einer 64-Bit-Fließkommazahl (die horizontale Geschwindigkeit) in eine vorzeichenbehaftete 16-Bit-Ganzzahl auftrat. Die Zahl war leider größer als 215 und die Umwandlung nicht gesichert, da die Programmierer diesen Zahlenbereich nicht angenommen hatten. Als Konsequenz brach das Lenksystem zusammen, und die Selbstzerstörung wurde ausgelöst, da die Triebwerke abzubrechen drohten. Das wirklich Dumme an dieser Geschichte ist, dass die Software nicht unbedingt für den Flug notwendig war und nur den Startvorbereitungen diente. Im Fall einer Unterbrechung während des Countdowns hätte das Programm schnell abgebrochen werden können. Ungünstig war, dass der Programmteil unverändert durch Wiederverwendung per Copy-and-Paste aus der Ariane-4-Software kopiert worden war, die Ariane 5 aber schneller flog. #### Typanpassung zwischen einfachen Typen und Referenztypen Allgemeine Umwandlungen zwischen einfachen Typen und Referenztypen gibt es nicht. Falsch sind zum Beispiel Listing 2.7 TypecastPrimRef.java, main() Teil 1
    String s = (String) 1;    // Cannot cast from int to String
    int i = (int) "1";        // Cannot cast from String to int
Einiges sieht dagegen nach Typanpassung aus, ist aber in Wirklichkeit eine Technik, die sich Autoboxing nennt (Kapitel 3 geht näher darauf ein). Listing 2.8 TypecastPrimRef.java, main() Teil 2
    Long lông = (Long) 2L;      // Or: Long lông = 2L;
    System.out.println( (Boolean) true );
    ((Integer)2).toString();
### 2.4.10 Überladenes Plus für Strings Obwohl sich in Java die Operatoren fast alle auf primitive Datentypen beziehen, gibt es doch eine weitere Verwendung des Plus-Operators. Diese wurde in Java eingeführt, da ein Aneinanderhängen von Zeichenketten oft benötigt wird. Objekte vom Typ String können durch den Plus-Operator mit anderen Strings und Datentypen verbunden werden. Falls zusammenhängende Teile nicht alle den Datentyp String annehmen, werden sie automatisch in einen String umgewandelt. Der Ergebnistyp ist immer String.
Beispiel Setzte fünf Teile zu einem String zusammen:
    String s = '"' + "Extrem Sandmännchen" + '"' + " frei ab " + 18;
    //         char  String                  char  String        int
    System.out.println( s ); // "Extrem Sandmännchen" frei ab 18
Besteht der Ausdruck aus mehreren Teilen, so muss die Auswertungsreihenfolge beachtet werden, andernfalls kommt es zu seltsamen Zusammensetzungen. So ergibt "Aufruf von " + 1 + 0 + 0 + " Ökonomen" tatsächlich »Aufruf von 100 Ökonomen« und nicht »Aufruf von 1 Ökonomen«, da der Compiler die Konvertierung in Strings dann startet, wenn er einen Ausdruck als String-Objekt erkannt hat.
Beispiel Auswertungsreihenfolge vom Plus: Listing 2.9 PlusString.java, main()
    System.out.println( 1 + 2 );       // 3
    System.out.println( "1" + 2 );     // 12
    System.out.println( 1 + "2" );     // 12
    System.out.println( 1 + "2" + 3 ); // 123
    System.out.println( "1" + 2 + 3 ); // 123
    System.out.println( 1 + 2 + "3" ); // 33
    System.out.println( '0' + 2 );     // 50  – ASCII value for '0' is 48
    System.out.println( 'A' + 'a' );   // 162 – 'A'=65, 'a'=97
Beispiel Der Plus-Operator für Zeichenketten geht streng von links nach rechts und bereitet mit eingebetteten arithmetischen Ausdrücken mitunter Probleme. Eine Klammerung hilft, wie im Folgenden zu sehen ist:
    "Ist 1 größer als 2? " + (1 > 2 ? "ja" : "nein");
Wäre der Ausdruck um den Bedingungsoperator nicht geklammert, dann würde der Plus-Operator an die Zeichenkette die 1 anhängen und es käme der >-Operator. Der erwartet aber kompatible Datentypen, die in unserem Fall – links stünde die Zeichenkette und rechts die Ganzzahl 2 – nicht gegeben sind.
### 2.4.11 Was C(++)-Programmierer vermissen könnten Da es in Java keine Pointer-Operationen gibt, existiert das Operatorzeichen zur Referenzierung (&) und Dereferenzierung (*) nicht. Ebenso ist ein sizeof unnötig, da das Laufzeitsystem und der Compiler immer die Größe von Klassen kennen beziehungsweise die primitiven Datentypen immer eine feste Länge haben. Eine abgeschwächte Version vom Kommaoperator ist in Java nur im Kopf von for-Schleifen erlaubt. ### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.
Name |
E-Mail |
Ihr Kommentar |
<< zurück | <top> | vor >>

Copyright © Galileo Press 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

[Galileo Computing]
Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de