Java Bitwise Operatoren

1. Übersicht

Operatoren werden in der Java-Sprache verwendet, um Daten und Variablen zu bearbeiten.

In diesem Tutorial werden wir die bitweisen Operatoren und ihre Funktionsweise in Java untersuchen.

2. Bitweise Operatoren

Bitweise Operatoren arbeiten mit Binärziffern oder Bits von Eingabewerten. Wir können diese auf die Ganzzahltypen anwenden - long, int, short, char und byte.

Bevor wir die verschiedenen bitweisen Operatoren untersuchen, wollen wir zunächst verstehen, wie sie funktionieren.

Bitweise Operatoren arbeiten mit einem binären Äquivalent von Dezimalzahlen und führen nach und nach Operationen gemäß dem angegebenen Operator aus:

  • Zunächst werden die Operanden in ihre binäre Darstellung konvertiert
  • Als nächstes wird der Operator auf jede Binärzahl angewendet und das Ergebnis berechnet
  • Schließlich wird das Ergebnis wieder in seine Dezimaldarstellung konvertiert

Lassen Sie uns mit einem Beispiel verstehen; Nehmen wir zwei ganze Zahlen:

int value1 = 6; int value2 = 5;

Als nächstes wenden wir einen bitweisen ODER-Operator auf diese Zahlen an:

int result = 6 | 5;

Um diese Operation auszuführen, wird zunächst die binäre Darstellung dieser Zahlen berechnet:

Binary number of value1 = 0110 Binary number of value2 = 0101

Dann wird die Operation auf jedes Bit angewendet. Das Ergebnis gibt eine neue Binärzahl zurück:

0110 0101 ----- 0111

Schließlich wird das Ergebnis 0111 wieder in eine Dezimalzahl umgewandelt, die gleich 7 ist :

result : 7

Bitweise Operatoren werden ferner als bitweise logische und bitweise Verschiebungsoperatoren klassifiziert. Lassen Sie uns nun jeden Typ durchgehen.

3. Bitweise logische Operatoren

Die bitweisen logischen Operatoren sind AND (&), OR (|), XOR (^) und NOT (~).

3.1. Bitweises ODER (|)

Der ODER-Operator vergleicht jede Binärziffer von zwei Ganzzahlen und gibt 1 zurück, wenn eine von beiden 1 ist.

Dies ähnelt dem || logischer Operator, der mit Booleschen Werten verwendet wird. Wenn zwei Boolesche Werte verglichen werden, ist das Ergebnis wahr, wenn einer von ihnen wahr ist. In ähnlicher Weise ist die Ausgabe 1, wenn einer von ihnen 1 ist.

Wir haben im vorherigen Abschnitt ein Beispiel für diesen Operator gesehen:

@Test public void givenTwoIntegers_whenOrOperator_thenNewDecimalNumber()  value2; assertEquals(7, result); 

Sehen wir uns die binäre Darstellung dieser Operation an:

0110 0101 ----- 0111

Hier können wir sehen, dass die Verwendung von OR, 0 und 0 zu 0 führt, während jede Kombination mit mindestens einer 1 zu 1 führt.

3.2. Bitweises UND (&)

Der AND-Operator vergleicht jede Binärziffer von zwei Ganzzahlen und gibt 1 zurück, wenn beide 1 sind, andernfalls gibt er 0 zurück.

Dies ähnelt dem Operator && mit booleschen Werten. Wenn die Werte von zwei Booleschen Werten wahr sind , ist das Ergebnis einer && -Operation wahr.

Verwenden wir das gleiche Beispiel wie oben, außer dass jetzt der Operator & anstelle von | verwendet wird Operator:

@Test public void givenTwoIntegers_whenAndOperator_thenNewDecimalNumber() { int value1 = 6; int value2 = 5; int result = value1 & value2; assertEquals(4, result); }

Sehen wir uns auch die binäre Darstellung dieser Operation an:

0110 0101 ----- 0100

0100 ist 4 dezimal, daher lautet das Ergebnis:

result : 4

3.3. Bitweises XOR (^)

Der XOR-Operator vergleicht jede Binärziffer von zwei ganzen Zahlen und gibt 1 zurück, wenn beide verglichenen Bits unterschiedlich sind. Dies bedeutet, dass wenn die Bits beider Ganzzahlen 1 oder 0 sind, das Ergebnis 0 ist; Andernfalls lautet das Ergebnis 1:

@Test public void givenTwoIntegers_whenXorOperator_thenNewDecimalNumber() { int value1 = 6; int value2 = 5; int result = value1 ^ value2; assertEquals(3, result); }

Und die binäre Darstellung:

0110 0101 ----- 0011

0011 ist 3 in Dezimalzahl, daher ist das Ergebnis:

result : 3

3.4. Bitweise ERGÄNZUNG (~)

Der Operator "Bitweises Nicht" oder "Komplement" bedeutet einfach die Negation jedes Bits des Eingabewerts. Es dauert nur eine ganze Zahl und es entspricht dem! Operator.

Dieser Operator ändert jede Binärziffer der Ganzzahl, was bedeutet, dass alle 0 zu 1 und alle 1 zu 0 werden. Die! Der Operator funktioniert für boolesche Werte ähnlich : Er kehrt die booleschen Werte von wahr nach falsch und umgekehrt um.

Lassen Sie uns nun anhand eines Beispiels verstehen, wie das Komplement einer Dezimalzahl gefunden wird.

Machen wir das Komplement von Wert1 = 6:

@Test public void givenOneInteger_whenNotOperator_thenNewDecimalNumber() { int value1 = 6; int result = ~value1; assertEquals(-7, result); }

Der Wert in binär ist:

value1 = 0000 0110

Durch Anwenden des Komplementoperators ergibt sich Folgendes:

0000 0110 -> 1111 1001

This is the one’s complement of the decimal number 6. And since the first (leftmost) bit is 1 in binary, it means that the sign is negative for the number that is stored.

Now, since the numbers are stored as 2’s complement, first we need to find its 2’s complement and then convert the resultant binary number into a decimal number:

1111 1001 -> 0000 0110 + 1 -> 0000 0111

Finally, 0000 0111 is 7 in decimal. Since the sign bit was 1 as mentioned above, therefore the resulting answer is:

result : -7

3.5. Bitwise Operator Table

Let's summarize the result of the operators we've seen to so far in a comparison table:

A B A|B A&B A^B ~A 0 0 0 0 0 1 1 0 1 0 1 0 0 1 1 0 1 1 1 1 1 1 0 0

4. Bitwise Shift Operators

Binary shift operators shift all the bits of the input value either to the left or right based on the shift operator.

Let's see the syntax for these operators:

value  

The left side of the expression is the integer that is shifted, and the right side of the expression denotes the number of times that it has to be shifted.

Bitwise shift operators are further classified as bitwise left and bitwise right shift operators.

4.1. Signed Left Shift [<<]

The left shift operator shifts the bits to the left by the number of times specified by the right side of the operand. After the left shift, the empty space in the right is filled with 0.

Another important point to note is that shifting a number by one is equivalent to multiplying it by 2, or, in general, left shifting a number by n positions is equivalent to multiplication by 2^n.

Let's take the value 12 as the input value.

Now, we will move it by 2 places to the left (12 <<2) and see what will be the final result.

The binary equivalent of 12 is 00001100. After shifting to the left by 2 places, the result is 00110000, which is equivalent to 48 in decimal:

@Test public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber() { int value = 12; int leftShift = value << 2; assertEquals(48, leftShift); } 

This works similarly for a negative value:

@Test public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber() { int value = -12; int leftShift = value << 2; assertEquals(-48, leftShift); }

4.2. Signed Right Shift [>>]

The right shift operator shifts all the bits to the right. The empty space in the left side is filled depending on the input number:

  • When an input number is negative, where the leftmost bit is 1, then the empty spaces will be filled with 1
  • When an input number is positive, where the leftmost bit is 0, then the empty spaces will be filled with 0

Let's continue the example using 12 as input.

Now, we will move it by 2 places to the right(12 >>2) and see what will be the final result.

The input number is positive, so after shifting to the right by 2 places, the result is 0011, which is 3 in decimal:

@Test public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() { int value = 12; int rightShift = value >> 2; assertEquals(3, rightShift); }

Also, for a negative value:

@Test public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() { int value = -12; int rightShift = value >> 2; assertEquals(-3, rightShift); }

4.3. Unsigned Right Shift [>>>]

This operator is very similar to the signed right shift operator. The only difference is that the empty spaces in the left are filled with 0 irrespective of whether the number is positive or negative. Therefore, the result will always be a positive integer.

Let's right shift the same value of 12:

@Test public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() { int value = 12; int unsignedRightShift = value >>> 2; assertEquals(3, unsignedRightShift); }

And now, the negative value:

@Test public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() { int value = -12; int unsignedRightShift = value >>> 2; assertEquals(1073741821, unsignedRightShift); }

5. Difference Between Bitwise and Logical Operators

There are a few differences between the bitwise operators we've discussed here and the more commonly known logical operators.

First, logical operators work on boolean expressions and return boolean values (either true or false), whereas bitwise operators work on binary digits of integer values (long, int, short, char, and byte) and return an integer.

Also, logical operators always evaluate the first boolean expression and, depending on its result and the operator used, may or may not evaluate the second. On the other hand, bitwise operators always evaluate both operands.

Finally, logical operators are used in making decisions based on multiple conditions, while bitwise operators work on bits and perform bit by bit operations.

6. Anwendungsfälle

Einige mögliche Anwendungsfälle von bitweisen Operatoren sind:

  • Kommunikationsstapel, bei denen die einzelnen Bits im Header, die an die Daten angehängt sind, wichtige Informationen anzeigen
  • In eingebetteten Systemen kann nur ein einzelnes Bit eines bestimmten Registers gesetzt / gelöscht / umgeschaltet werden, ohne die verbleibenden Bits zu ändern
  • So verschlüsseln Sie Daten aus Sicherheitsgründen mit dem XOR-Operator
  • Bei der Datenkomprimierung durch Konvertieren von Daten von einer Darstellung in eine andere, um den verwendeten Speicherplatz zu reduzieren

7. Fazit

In diesem Tutorial haben wir gelernt, welche Arten von bitweisen Operatoren sich von logischen Operatoren unterscheiden. Wir haben auch einige mögliche Anwendungsfälle für sie gesehen.

Alle Codebeispiele in diesem Artikel sind auf GitHub verfügbar.