![]()  | 
  | 
|||||
 
 i >>> nDer Operator >>> verschiebt eine Variable (Bitmuster) bitweise um n Schritte nach rechts, ohne das Vorzeichen der Variablen zu berücksichtigen (vorzeichenloser Rechts-Shift). So werden auf der linken Seite (MSB) nur Nullen eingeschoben; das Vorzeichen wird mitgeschoben. Bei einer positiven Zahl hat dies keinerlei Auswirkungen, und das Verhalten ist wie beim >>-Operator. 
 Die Ausgabe ist für den negativen Operanden besonders spannend: 64 >>> 1 = 32 -64 >>> 1 = 2147483616 Ein <<<-Operator macht allerdings keinen Sinn, da beim Links-Shiften sowieso nur Nullen eingefügt werden. Beim Shift nach links oder rechts steht vor dem binären Operator im rechten Operanden die Anzahl Bits, die verschoben werden. Bei einem int machen hier natürlich nur Werte bis 32 Sinn und für ein long Werte bis 64 Bit. Mit anderen Worten: Nur die ersten 5 beziehungsweise 6 Bit sind nötig. 
 Division und Multiplikation mit VerschiebeoperatorenWird ein Wert um eine Stelle nach links geschoben, so kommt in das niedrigste Bit (das Bit ganz rechts) eine Null hinein und alle Bits schieben sich eine Stelle weiter. Das Resultat ist, dass die Zahl mit 2 multipliziert wird. Natürlich müssen wir mit einem Verlust von Informationen rechnen, wenn das höchste Bit gesetzt ist, denn dann wird es herausgeschoben, aber das Problem haben wir auch schon bei der normalen Multiplikation. Es gibt in Java keinen Operator, der die Bits rollt, der also die an einer Stelle herausfallenden wieder an der anderen Seite einfügt. Wenn ein einmaliger Shift nach links mit 2 multipliziert, so würde eine Verschiebung um zwei Stellen nach links eine Multiplikation mit 4 bewirken. Allgemein gilt: Bei einem Shift von i nach links ergibt sich eine Multiplikation mit 2i. Wir können dies dazu nutzen, beliebige Multiplikationen durch Verschiebung nachzubilden. 
 Diese Umsetzung ist nicht immer einfach, und es gibt tatsächlich kein Verfahren, welches eine optimale Umsetzung liefert. Doch arbeiteten viele Prozessoren auf diese Weise intern die Multiplikation ab, und ein Compiler nutzt dies gern zur Optimierung der Laufzeit. Eine Verschiebeoperation ist bei vielen Prozessoren schneller als eine Multiplikation. Doch ist hier Obacht zu geben, denn eine lange Folge von Verschiebungen ist nicht schneller, sondern langsamer als eine direkte Multiplikation. Neben der Addition kommt selbstverständlich auch die Subtraktion infrage. Ersetzen wir im oberen Beispiel das Plus durch ein Minus, so bekämen wir eine Multiplikation mit 6. Natürlich müssen wir auf die Überläufe der Zwischenergebnisse bei großen Zahlen achten. Diese würde es bei einer echten Multiplikation nicht geben. Was wir am Beispiel der Verschiebung nach links gezeigt haben, funktioniert genauso mit einem Shift nach rechts. Jetzt wird bei einmaliger Verschiebung durch 2 dividiert. Das Ergebnis ist natürlich immer nur ganzzahlig, da die Verschiebeoperatoren nur auf int und long definiert sind; so ist 7 >> 2 = 3. Bei negativen Zahlen sieht das etwas anders aus, denn hier ist das Ergebnis -7 >> 2 = -4. Würden wir die die Division ganz klassisch mit / 2 realisieren ist das Ergebnis 7 / 2 = 3 und -7 / 2 = -3. Bei einer gedachten Optimierung ist auf diese Sonderheit bei negativen Zahlen zu achten. Die Bitoperatoren in Assembler verglichen mit <<<, << und >>Auch in Assembler gibt es zwei Gruppen von Schiebeoperatoren: die arithmetischen Schiebebefehle (SAL und SAR), die das Vorzeichen des Operanden beachten, und die logischen Schiebebefehle (SHL und SHR), die den Operanden ohne Beachtung eines etwaigen Vorzeichens schieben. Die Befehle SAL und SHL haben die gleiche Wirkung. So ist >>> der Bitoperator, in dem das Vorzeichen nicht beachtet wird, wie SHR in Assembler. Es gibt in Java auch keinen Bitoperator <<<, da - wie in Assembler - SAL = SHL gilt (<<< würde die gleiche Wirkung haben wie <<). Bits rotierenJava hat zwar Operatoren zum Verschieben von Bits, aber nicht zum Rotieren. Beim Rotieren werden Bits um eine bestimmte Stelle verschoben, die herausfallenden Bits kommen aber auf der anderen Seite wieder rein. Eine Funktion ist leicht geschrieben: Der Trick dabei ist, die herausfallenden Bits vorher zu extrahieren und auf der anderen Seite wieder einzusetzen. public static int rotateLeft( int v, int n ) { return (v << n) | (v >>> (32 - n)); } public static int rotateRight( int v, int n ) { return (v >>> n) | (v << (32 - n)); } Die Funktionen rotieren jeweils n Bits nach links oder rechts. Da der Datentyp int ist, ist die Verschiebung n in dem Wertebereich von 0 bis 31 erlaubt. 2.8.5 Setzen, Löschen, Umdrehen und Testen von Bits
 | 
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Beispiel   Anwendung aller Bitoperatoren
int setBit( int n, int pos ) { return n | (1 << pos); } int clearBit( int n, int pos ) { return n & ~ (1 << pos); } int flipBit( int n, int pos ) { return n ^ (1 << pos); } boolean testBit( int n, int pos ) { int mask = 1 << pos; return (n & mask) == mask; // alternativ: return (n & 1<<pos)!=0;}  | 
In Java gibt es ebenso wie in C(++) einen Operator, der drei Operanden benutzt. Dies ist der Bedingungsoperator, der auch Konditionaloperator, ternärer Operator beziehungsweise trinärer Operator genannt wird. Er erlaubt es, den Wert eines Ausdrucks von einer Bedingung abhängig zu machen, ohne dass dazu eine if-Anweisung verwendet werden muss. Die Operanden sind durch ? beziehungsweise : voneinander getrennt:
ConditionalOrExpression ? Expression : ConditionalExpression
Der erste Ausdruck muss vom Typ boolean sein und bestimmt, ob das Ergebnis Expression oder ConditionalExpression ist. Der Bedingungsoperator kann eingesetzt werden, wenn der zweite und dritte Operand ein numerischer Typ, boolescher Typ oder Referenztyp ist. Der Aufruf von Methoden, die demnach void zurückgeben, ist nicht gestattet.
Eine Anwendung für den trinären Operator ist oft eine Zuweisung an eine Variable:
Variable = Bedingung ? Ausdruck1 : Ausdruck2;
Der Wert der Variablen wird jetzt in Abhängigkeit von der Bedingung gesetzt. Ist sie erfüllt, dann erhält die Variable den Wert des ersten Ausdrucks, andernfalls wird der Wert des zweiten Ausdrucks zugewiesen.
Beispiel   So etwa für ein Maximum:
max = ( a > b ) ? a : b;  | 
| 
 Dies entspricht beim herkömmlichen Einsatz für if/else: if ( a > b ) max = a; else max = b;  | 
Mit dem Rückgabewert können wir alles Mögliche machen, etwa ihn direkt ausgeben. Das wäre mit if/else nur mit temporären Variablen möglich.
System.out.println( ( a > b ) ? a : b );
Der Bedingungsoperator findet sich häufig in kleinen Funktionen. Dazu einige Beispiele:
Beispiel   Um das Maximum oder Minimum zweier Ganzzahlen zurückzugeben, definieren wir die kompakte Funktion:
static int min( int a, int b ) { return a < b ? a : b; } static int max( int a, int b ) { return a > b ? a : b; }  | 
Beispiel   Der Absolutwert einer Zahl wird zurückgegeben durch
x >= 0 ? x : -x  | 
Beispiel   Der Groß-/Kleinbuchstabe im ASCII-Alphabet soll zurückgegeben werden. Dabei ist c vom Typ char.
// Konvertierung in Großbuchstaben c = (char)(Character.isLowerCase(c) ? (c-'a'+'A' ) : c); // Konvertierung in Kleinbuchstaben c = (char)(Character.isUpperCase(c) ? (c-'A'+'a' ) : c); Da diese Umwandlung nur für die 26 ASCII-Buchstaben funktioniert, ist es besser, Bibliotheksmethoden für alle Unicode-Zeichen zu verwenden. Dazu dienen die Funktionen toUpperCase() und toLowerCase().  | 
Beispiel   Es soll eine Zahl n, die zwischen 0 und 15 liegt, zur Hexadezimalzahl konvertiert werden.
(char)( (n < 10) ? ('0' + n) : ('a' - 10 + n ) )  | 
Die Anwendung des trinären Operators führt schnell zu schlecht lesbaren Programmen und sollte daher vorsichtig eingesetzt werden. In C(++) führt die unbeabsichtigte Mehrfachauswertung in Makros zu schwer auffindbaren Fehlern. Gut, dass uns das in Java nicht passieren kann. Durch ausreichende Klammerung muss sichergestellt werden, dass die Ausdrücke auch in der beabsichtigten Reihenfolge ausgewertet werden. Im Gegensatz zu den meisten Operatoren ist der Bedingungsoperator rechtsassoziativ. (Die Zuweisung ist ebenfalls rechtsassoziativ.) Die Anweisung
b1 ? a1 : b2 ? a2 : a3
ist demnach gleichbedeutend mit
b1 ? a1 : ( b2 ? a2 : a3 )
Beispiel   Wollen wir eine Funktion schreiben, die für eine Zahl n abhängig vom Vorzeichen -1, 0 oder 1 liefert, lösen wir das Problem mit geschachteltem trinären Operator.
int sign( int n ) { return (n < 0) ? -1 : (n > 0) ? 1 : 0; }  | 
Der trinäre Operator liefert als Ergebnis einen Ausdruck zurück, der auf der rechten Seite einer Zuweisung verwendet werden kann. Da er rechts vorkommt, nennt er sich auch rvalue. Er lässt sich nicht derart auf der linken Seite einer Zuweisung einsetzen, dass er eine Variable auswählt, der ein Wert zugewiesen wird.1
Beispiel   Folgende Anwendung des trinären Operators ist in Java nicht möglich:34
((richtung>=0) ? hoch : runter) = true;  | 
1 In C(++) kann dies durch *((Bedingung) ? &a : &b) = Ausdruck; über Pointer gelöst werden.
| << zurück | 
Copyright (c) Galileo Press GmbH 2004
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.