In der heutigen Lektion machen wir uns mit bitweisen Operatoren in Java vertraut und sehen uns Beispiele an, wie wir mit ihnen arbeiten können. Mit dem Wort „Bit“ bist du wahrscheinlich vertraut. Wenn nicht, sehen wir uns noch einmal an, was es bedeutet :) Ein Bit ist die kleinste Informationseinheit in einem Computer. Der Name kommt vom englischen Ausdruck „binary digit“ (binäre Ziffer). Ein Bit kann durch eine von zwei Zahlen ausgedrückt werden: 1 oder 0. Es gibt ein spezielles binäres Zahlensystem, das auf Einsen und Nullen basiert. Bitweise Operatoren in Java - 1Wir wollen uns hier nun nicht in einen mathematischen Dschungel begeben. Wichtig ist nur, dass jede Zahl in Java in die binäre Form umgewandelt werden kann. Dazu musst du die Wrapper-Klassen verwenden. So kannst du das zum Beispiel für ein int machen:

public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
Konsolenausgabe:
101010110
1010 10110 (ich habe das Leerzeichen eingefügt, damit es leichter zu lesen ist) ist die Zahl 342 im Dezimalsystem. Wir haben diese Zahl in einzelne Bits unterteilt: Nullen und Einsen. Operationen, die mit Bits durchgeführt werden, nennt man bitweise.
  • ~ – bitweises NICHT.
Dieser Operator ist sehr einfach: Er durchläuft jedes Bit unserer Zahl und schaltet das Bit um: Nullen werden zu Einsen und Einsen zu Nullen. Wenn wir das auf unsere Nummer 342 anwenden, passiert folgendes:
101010110 ist 342, dargestellt als Binärzahl 010101001 ist der Wert des Ausdrucks ~342
Lass uns versuchen, das in die Praxis umzusetzen:

public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(~x);
   }
}
Konsolenausgabe:
169
169 ist unser Ergebnis(010101001) im bekannten Dezimalsystem :)
  • & – bitweises UND.
Wie du sehen kannst, sieht es dem logischen UND (&&) sehr ähnlich. Der &&-Operator gibt nur dann true zurück, wenn beide Operanden true sind. Das bitweise & funktioniert auf ähnliche Weise: Es vergleicht zwei Zahlen Bit für Bit. Der Vergleich ergibt eine dritte Zahl. Nehmen wir zum Beispiel die Zahlen 277 und 432:
277 wird als Binärzahl als 110110000 dargestellt 432 wird als Binärzahl als 1000101011 dargestellt
Als nächstes vergleicht der Operator & das erste Bit der oberen Zahl mit dem ersten Bit der unteren Zahl. Da dies ein UND-Operator ist, ist das Ergebnis nur dann 1, wenn beide Bits 1 sind. In allen anderen Fällen ist das Ergebnis 0. 100010101 & 110110000 _______________ 10001000 – Ergebnis des &-Operators Zuerst vergleichen wir die ersten Bits der beiden Zahlen, dann die zweiten Bits, dann die dritten und so weiter. Wie du siehst, sind nur in zwei Fällen die beiden entsprechenden Bits in den Zahlen gleich 1 (das erste und das fünfte Bit). Alle anderen Vergleiche ergaben 0en. Am Ende haben wir also die Zahl 10001000. Im Dezimalsystem entspricht sie der Zahl 272. Überprüfen wir das:

public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
Konsolenausgabe:
272
  • | – bitweises ODER.
Dieser Operator funktioniert auf die gleiche Weise: Er vergleicht zwei Zahlen Bit für Bit. Wenn jetzt aber mindestens eines der Bits 1 ist, dann ist das Ergebnis auch 1. Schauen wir uns noch einmal die gleichen Zahlen an (277 und 432): 100010101 | 110110000 _______________ 110110101 – Ergebnis des |-Operators Hier erhalten wir ein anderes Ergebnis: Die einzigen Bits, die Nullen bleiben, sind die Bits, die in beiden Zahlen Nullen waren. Das Ergebnis ist die Zahl 110110101. Im Dezimalsystem entspricht sie der Zahl 437 Überprüfen wir das:

public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
Konsolenausgabe:
437
Wir haben alles richtig berechnet! :)
  • ^ – bitweises XOR (exklusives ODER)
Diesen Operator kennen wir bislang noch nicht. Aber er ist auch nicht komplizierter. Er ist ähnlich wie der gewöhnliche ODER-Operator. Es gibt nur einen Unterschied: Das gewöhnliche ODER gibt true zurück, wenn mindestens ein Operand true ist. Aber es muss nicht unbedingt nur einer sein: Wenn beide Operanden true sind, ist das Ergebnis ebenfalls true. Beim exklusiven ODER ergibt sich dagegen nur dann true, wenn genau einer der beiden Operanden true ist. Wenn beide Operanden true sind, ergibt das normale ODER true („mindestens ein true“), aber XOR ergibt false. Deshalb heißt es ja auch exklusives ODER. Wenn du weißt, wie die vorherigen bitweisen Operatoren funktionieren, kannst du wahrscheinlich ganz leicht 277 ^ 432 berechnen. Aber das wollen wir uns nochmal genauer ansehen :) 100010101 ^ 110110000 _______________ 010100101 – Ergebnis des ^-Operators Das ist unser Ergebnis. Die Bits, die in beiden Zahlen gleich waren, ergeben eine 0 (was bedeutet, dass der Test auf nur ein true fehlgeschlagen ist). Aber die Bits, die ein 0-1- oder 1-0-Paar bildeten, wurden zu Einsen. Unser Ergebnis ist die Zahl 010100101. Im Dezimalsystem entspricht sie der Zahl 165. Schauen wir mal, ob unsere Berechnungen richtig sind:

public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
Konsolenausgabe:
165
Super! Alles ist so, wie wir es uns vorgestellt haben :) Jetzt ist es an der Zeit, dich mit den Operatoren zum Verschieben von Bits vertraut zu machen. Der Name spricht für sich selbst. Wir nehmen eine Zahl und verschieben ihre Bits nach links oder rechts :) Mal schauen, wie das aussieht:

Nach links schieben

Eine Verschiebung von Bits nach links wird angezeigt durch << Hier ist ein Beispiel:

public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 3;// Shift distance

       int z = (x << y);
       System.out.println(Integer.toBinaryString(x));
       System.out.println(Integer.toBinaryString(z));
   }
}
In diesem Beispiel wird die Zahl x = 64 als Wert bezeichnet. Es sind die Bits des Wertes, die wir verschieben werden. Wir verschieben die Bits nach links (das hast du vielleicht anhand der Richtung des <<-Operators schon erraten). Im Binärsystem ist die Zahl 64 = 1000000 Die Zahl y = 3 wird als Verschiebedistanz bezeichnet. Die Verschiebedistanz gibt an, um wie viele Bits du die Bits der Zahl xnach rechts/links verschieben willst. In unserem Beispiel verschieben wir sie um 3 Bits nach links. Um den Veränderungsprozess deutlicher zu sehen, schau dir das Bild an. In diesem Beispiel verwenden wir int-Werte. Int-Werte belegen 32 Bit im Speicher des Computers. So sieht unsere ursprüngliche Zahl 64 aus: Bitweise Operatoren in Java - 2 Und jetzt nehmen wir jedes unserer Bits und verschieben es buchstäblich um 3 Stellen nach links: Bitweise Operatoren in Java - 3Sieh dir an, was wir jetzt haben. Wie du siehst, sind alle unsere Bits verschoben und weitere 3 Nullen wurden am Rand eingefügt. Drei, weil wir um 3 Stellen verschoben haben. Hätten wir um 10 Stellen verschoben, wären 10 Nullen eingefügt worden. Der Ausdruck x << y bedeutet also „verschiebe die Bits der Zahl x um y Stellen nach links“. Das Ergebnis unseres Ausdrucks ist die Zahl 1000000000, die im Dezimalsystem 512 ist. Überprüfen wir das:

public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 3;// Shift distance

       int z = (x << y);
       System.out.println(z);
   }
}
Konsolenausgabe:
512
Absolut korrekt! Theoretisch könnten die Bits endlos verschoben werden, aber da unsere Zahl ein int ist, haben wir nur 32 Binärstellen zur Verfügung. Davon sind 7 bereits von 64 (1000000) besetzt. Wenn wir also 27 Stellen nach links verschieben würden, würde unsere einzige 1 über den Bereich des Datentyps hinausgehen und verloren gehen. Es würden nur Nullen übrig bleiben!

public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 26;// Shift distance

       int z = (x << y);
       System.out.println(z);
   }
}
Konsolenausgabe:
0
Wie erwartet, hat sich die 1 über die 32 verfügbaren Bits hinaus bewegt und ist verschwunden. Am Ende haben wir eine 32-Bit-Zahl, die nur aus Nullen besteht. Bitweise Operatoren in Java - 4Das entspricht natürlich der 0 im Dezimalsystem. Hier ist eine einfache Regel, mit der du dir Verschiebungen nach links merken kannst: Bei jeder Verschiebung nach links wird die Zahl mit 2 multipliziert. Versuchen wir, den folgenden Ausdruck ohne Bilder von Bits zu berechnen 111111111 << 3 Wir müssen die Zahl 111111111 mit 2 multiplizieren. Als Ergebnis erhalten wir 888888888. Schreiben wir etwas Code und überprüfen das:

public class Main {

   public static void main(String[] args) {
       System.out.println(111111111 << 3);
   }
}
Konsolenausgabe:
888888888

Nach rechts schieben

Diese Operation wird angegeben mit >>. Sie macht das Gleiche, nur in die andere Richtung! :) Wir werden das Rad nicht neu erfinden. Versuchen wir es mit demselben int 64.

public class Main {

   public static void main(String[] args) {
       int x = 64;//value
       int y = 2;// Shift distance

       int z = (x >> y);
       System.out.println(z);
   }
}
Bitweise Operatoren in Java - 5Bitweise Operatoren in Java - 6Durch die Verschiebung um 2 nach rechts geraten die beiden äußersten Nullen in unserer Zahl aus dem Bereich und gehen verloren. Wir erhalten 10000, was der Zahl 16 im Dezimalsystem entspricht Konsolenausgabe:
16
Hier ist eine einfache Regel, um sich die Verschiebungen nach rechts zu merken: Jede Verschiebung nach rechts dividiert durch zwei und verwirft den Rest. Zum Beispiel bedeutet 35 >> 2 dass wir 35 zweimal durch 2 teilen müssen, wobei die Reste verworfen werden
35/2 = 17 (Rest 1 verwerfen) 17/2 = 8 (Rest 1 verwerfen)
Am Ende sollte 35 >> 2 gleich 8 sein. Überprüfen wir das:

public class Main {

   public static void main(String[] args) {
       System.out.println(35 >> 2);
   }
}
Konsolenausgabe:
8

Vorrang von Operatoren in Java

Beim Schreiben und Lesen von Code wirst du oft auf Ausdrücke stoßen, die mehrere Operationen kombinieren. Es ist sehr wichtig, dass du die Reihenfolge kennst, in der sie ausgeführt werden (sonst könnte dich das Ergebnis überraschen) Da es in Java viele Operationen gibt, wurde jeder von ihnen ein Platz in einer speziellen Tabelle zugewiesen:

Operatorvorrang

Operatoren Vorrang
Postfix expr++ expr--
Unär ++expr --expr +expr ~ !
Multiplikativ * / %
Additiv + -
Verschiebung << >> >>>
Relational < > <= >= instanceof
Gleichheit == !=
Bitweises UND &
Bitweises exklusives ODER ^
Bitweises inklusives ODER |
Logisches UND &&
Logisches ODER ||
Ternär ? :
Zuweisung = += -= *= /= %= &= ^= |= <<= >>= >>>=
Alle Operationen werden von links nach rechts ausgeführt, wobei ihre Rangfolge berücksichtigt wird. Wenn wir zum Beispiel schreiben

int x  = 6 - 4/2;
dann wird zuerst die Divisionsoperation (4/2) durchgeführt. Obwohl sie an zweiter Stelle steht, hat sie einen höheren Stellenwert. Klammern geben den höchsten Vorrang an. Das kennst du wahrscheinlich noch aus der Schule. Wenn du sie zum Beispiel zum Ausdruck

int x  = (6 - 4)/2;
hinzufügst, dann wird die Subtraktion zuerst durchgeführt, da sie in Klammern eingeschlossen ist. Der Vorrang des logischen &&-Operators ist eher niedrig (siehe Tabelle), daher steht er normalerweise an letzter Stelle. Bitweise Operatoren in Java - 7So wie hier:

boolean x = 6 - 4/2 > 3 && 12*12 <= 119;
Dieser Ausdruck wird wie folgt ausgeführt:
  • 4/2 = 2

boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144

boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4

boolean x = 4 > 3 && 144 <= 119;
Als nächstes werden die Vergleichsoperatoren ausgeführt:
  • 4 > 3 = true

boolean x = true && 144 <= 119;
  • 144 <= 119 = false

boolean x = true && false;
Und schließlich wird der UND-Operator (&&) zuletzt ausgeführt.

boolean x = true && false;
boolean x = false;
Zum Beispiel hat der Additionsoperator (+) einen höheren Vorrang als der Vergleichsoperator != (nicht gleich); Daher wird in dem Ausdruck

boolean x = 7 != 6+1;
zuerst die Operation 6+1 ausgeführt, dann die Prüfung 7 != 7 (die zu false ausgewertet wird) und schließlich die Zuweisung des Ergebnisses (false) an die Variable x (die Zuweisung hat im Allgemeinen den niedrigsten Vorrang aller Operatoren; siehe die Tabelle). Puh! Das war eine ganz schön umfangreiche Lektion, aber du hast es geschafft! Wenn du diese oder frühere Lektionen nicht ganz verstanden hast, mach dir keine Sorgen. Wir werden diese Themen in Zukunft noch öfter aufgreifen. Ein paar CodeGym-Lektionen über logische und numerische Operationen. Dazu werden wir in nächster Zeit nicht kommen, aber es schadet nicht, wenn du sie jetzt schon liest.