W3docs

Java Bitweise Operatoren

Einzelne Bits in Java manipulieren mit &, |, ^, ~, <<, >> und >>> Bitweise-Operatoren.

Der größte Teil des Java-Codes arbeitet nicht mit einzelnen Bits. Aber hin und wieder — beim Verpacken von Flags in ein int, beim Lesen eines binären Dateiformats, beim Berechnen eines Hashs oder beim Arbeiten mit Berechtigungs-Bitmasks — müssen Sie Werte auf Bit-Ebene manipulieren. Javas bitweise Operatoren sind der C-ähnliche Satz: &, |, ^, ~ und die drei Shifts. Sie unterscheiden sich von den logischen Operatoren && und ||, die kurzschließen und nur auf boolean-Werten funktionieren — bitweise Operatoren wirken auf jedes Bit einer ganzen Zahl.

Die Operatoren

OperatorNameWas er tut
&ANDBit ist 1 nur wenn beide Bits 1 sind
|ORBit ist 1 wenn eines der Bits 1 ist
^XORBit ist 1 wenn die beiden Bits unterschiedlich sind
~NOT (Komplement)Dreht jedes Bit um
<<LinksverschiebungVerschiebt Bits nach links, füllt rechts mit 0
>>Vorzeichenbehaftete RechtsverschiebungVerschiebt nach rechts, füllt links mit dem Vorzeichenbit
>>>Vorzeichenlose RechtsverschiebungVerschiebt nach rechts, füllt links mit 0

Alle operieren auf int- und long-Operanden. byte, short und char werden zuerst zu int hochgestuft.

Binäre Literale (0b...) machen die Bit-Muster leicht erkennbar:

int a = 0b1100;   // 12
int b = 0b1010;   // 10

System.out.println(Integer.toBinaryString(a & b));   // 1000  (8)
System.out.println(Integer.toBinaryString(a | b));   // 1110  (14)
System.out.println(Integer.toBinaryString(a ^ b));   // 110   (6)

Beachten Sie, dass Integer.toBinaryString führende Nullen weglässt — 6 wird als 110 ausgegeben, nicht als 0110. Wenn Sie eine feste Breite zur Anzeige benötigen, müssen Sie selbst auffüllen.

NOT — ~

~ dreht jedes Bit um, einschließlich des Vorzeichenbits. Für 32-Bit int bedeutet das Zweierkomplement: ~x entspricht -x - 1:

System.out.println(~0);    // -1
System.out.println(~5);    // -6
System.out.println(~-1);   // 0

Shifts

<< verschiebt nach links und multipliziert mit Zweierpotenzen:

System.out.println(1 << 0);   // 1
System.out.println(1 << 1);   // 2
System.out.println(1 << 4);   // 16

>> verschiebt nach rechts und bewahrt das Vorzeichen — nützlich für die Division vorzeichenbehafteter ganzer Zahlen:

System.out.println(16 >> 2);   // 4
System.out.println(-16 >> 2);  // -4   — sign extended

>>> verschiebt nach rechts und füllt immer mit null auf — sinnvoll, wenn Sie ein int als vorzeichenlose Bits behandeln:

System.out.println(-1 >>> 28);  // 15
System.out.println(-1 >> 28);   // -1

Praktische Anwendungen

Flag-Bitmasks

Mehrere Ja/Nein-Flags in einem einzigen int verpacken:

final int READ    = 1 << 0;  // 0001
final int WRITE   = 1 << 1;  // 0010
final int EXECUTE = 1 << 2;  // 0100

int perms = READ | WRITE;             // set both

boolean canRead    = (perms & READ) != 0;     // true
boolean canExecute = (perms & EXECUTE) != 0;  // false

perms |= EXECUTE;       // grant execute
perms &= ~WRITE;        // revoke write
perms ^= READ;          // toggle read

Das ist dieselbe Idee wie Unix-Dateiberechtigungen.

Multiplizieren oder Dividieren durch Zweierpotenzen

x << n entspricht x * 2ⁿ; x >> n entspricht x / 2ⁿ (für nicht-negative x):

int doubled = x << 1;
int halved  = x >> 1;

Der Compiler optimiert in der Regel einfache Multiplikation und Division durch konstante Zweierpotenzen selbständig zu Shifts, also schreiben Sie, was klarer ist.

Zwei ints ohne temporäre Variable tauschen

Ein klassischer XOR-Trick:

int a = 5, b = 3;
a ^= b;
b ^= a;
a ^= b;
System.out.println(a + " " + b);   // 3 5

Nett, aber selten lohnenswert gegenüber einer temporären Variable — moderne Compiler behandeln den temporären Fall problemlos.

Eine Demonstration

java— editable, runs on the server

Wann diese vs. EnumSet verwenden

Für eine kleine feste Menge von Flags in modernem Java ist EnumSet<MyFlag> in der Regel klarer und genauso effizient — intern speichert es Enum-Werte als einzelne long-Bitmask, sodass Sie die Lesbarkeit von Set<MyFlag> mit bitweise-schnellen Operationen erhalten:

enum Permission { READ, WRITE, EXECUTE }

EnumSet<Permission> perms = EnumSet.of(Permission.READ, Permission.WRITE);
perms.add(Permission.EXECUTE);
perms.contains(Permission.READ);   // true

Greifen Sie auf rohe Bit-Operationen nur zurück, wenn Sie mit binären Formaten, Hardware-Registern oder kritischen Pfaden arbeiten, bei denen int-Packing wichtig ist.

Was kommt als Nächstes

Java Strings — der Referenztyp, mit dem Sie mehr als mit jedem anderen arbeiten werden.

Übungen

Übung
Was ergibt 1 << 4?
Was ergibt 1 << 4?
Was this page helpful?