CodeGym/Blog Java/Poland/Operatory bitowe w Javie
Autor
Alex Vypirailenko
Java Developer at Toshiba Global Commerce Solutions

Operatory bitowe w Javie

Opublikowano w grupie Poland
Podczas tej lekcji zapoznasz się z koncepcją operatorów bitowych Java i dowiesz się, na przykładach, jak ich używać. Prawdopodobnie znasz słowo "bit". Jeśli nie, przypomnijmy sobie co ono oznacza :) Bit to najmniejsza jednostka informacji w komputerze. Jego nazwa pochodzi od binary digit (cyfra binarna). Bit można wyrazić jedną z dwóch liczb: 1 lub 0. Istnieje specjalny system liczb binarnych oparty na zerach i jedynkach. Operatory bitowe w Javie - 1Nie będziemy zagłębiać się tu w matematyczną dżunglę. Zauważmy tylko, że dowolną liczbę w Javie można przekonwertować na postać binarną. Aby to zrobić, musisz użyć klas osłonowych. Oto przykład jak możesz zrobić to dla int:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
Wyświetlone zostanie:
101010110
1010 10110 (dodałem spację, aby ułatwić czytanie) to liczba 342 w systemie dziesiętnym. Właściwie podzieliliśmy tę liczbę na poszczególne bity: zera i jedynki. Operacje wykonywane na bitach nazywamy bitowymi.
  • ~ — negacja bitowa.
Ten operator jest bardzo prosty: przechodzi przez każdy bit naszej liczby i odwraca go: zera stają się jedynkami, a jedynki zerami. Jeśli zastosujemy to do naszej liczby 342, oto co się stanie:
101010110 to 342 jako liczba binarna 010101001 to wartość wyrażenia ~342
Spróbujmy zastosować to w praktyce:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(~x);
   }
}
Wyświetlone zostanie:
169
169 to wynik (010101001) w dobrze nam znanym systemie dziesiętnym :)
  • & — koniunkcja bitowa (AND)
Działa to dość podobnie do logicznego AND (&&). Jak zapewne pamiętasz, operator && zwraca wartość true tylko wtedy, gdy oba operandy mają wartość true. Bitowe & działa w podobny sposób: porównuje dwie liczby bit po bicie. Porównanie daje trzecią liczbę. Weźmy na przykład liczby 277 i 432:
110110000 to 277 reprezentowane jako liczba binarna 1000101011 to 432 reprezentowane jako liczba binarna
Następnie operator & porównuje pierwszy bit górnej liczby z pierwszym bitem dolnej liczby. Ponieważ jest to operator AND, wynik będzie równy 1 tylko wtedy, gdy oba bity będą równe 1. W każdym innym przypadku wynik to 0. 100010101 & 110110000 _______________ 10001000 — wynik działania operatora & Najpierw porównujemy pierwszy bit obu liczb, potem drugi bit, potem trzeci i tak dalej. Jak widać, tylko w dwóch przypadkach oba odpowiadające sobie bity w liczbach są równe 1 (pierwszy i piąty bit). Wszystkie inne porównania dają wynik 0. Więc ostatecznie otrzymaliśmy liczbę 10001000. W systemie dziesiętnym odpowiada to liczbie 272. Sprawdźmy:
public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
Wyświetlone zostanie:
272
  • | — bitowa alternatywa (OR).
Ten operator działa w ten sam sposób: porównuje dwie liczby bit po bicie. Tylko teraz, jeśli przynajmniej jeden z bitów ma wartość 1, zwracany wynik to 1. Spójrzmy na te same liczby (277 i 432): 100010101 | 110110000 _______________ 110110101 — wynik działania operatora | W otrzymanym wyniku jedynymi bitami, które pozostają zerami, są te bity, które miały wartość zero w obu liczbach. Wynik to liczba 110110101. W systemie dziesiętnym odpowiada to liczbie 437. Sprawdźmy:
public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
Wyświetlone zostanie:
437
Wszystko obliczyliśmy poprawnie! :)
  • ^ — bitowa alternatywa wykluczająca XOR (exclusive OR)
Nie spotkaliśmy jeszcze tego operatora. Ale nie ma w nim nic skomplikowanego. Działa podobnie do zwykłego operatora OR. Jest jedna różnica: zwykłe OR zwraca true, jeśli przynajmniej jeden operand ma wartość true. Ale nie musi to być tylko jeden operand: jeśli oba operandy mają wartość true, wynik to true. Alternatywa wykluczająca (exclusive OR) zwraca wartość true tylko wtedy, gdy dokładnie jeden z operandów ma wartość true. Jeśli oba operandy mają wartość true, zwykłe OR zwraca true ("co najmniej jedno true"), ale XOR zwraca false. Dlatego nazywa się to alternatywą wykluczającą. Wiedząc, jak działają poprzednie operatory bitowe, prawdopodobnie możesz łatwo obliczyć 277 ^ 432. Ale przejdźmy przez to razem jeszcze raz :) 100010101 ^ 110110000 _______________ 010100101 — wynik działania operatora ^ Oto nasz wynik. Bity, które miały taką samą wartość w obu liczbach, dają 0 (czyli test "tylko jeden" zwraca błąd). Ale bity tworzące pary 0-1 lub 1-0 dają jedynki. Nasz wynik to liczba 010100101. W systemie dziesiętnym odpowiada to liczbie 165. Sprawdźmy, czy nasze obliczenia są poprawne:
public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
Wyświetlone zostanie:
165
Super! Wszystko działa tak jak myśleliśmy :) Czas zapoznać się z operatorami przesunięć bitowych. Nazwa mówi sama za siebie. Bierzemy jakąś liczbę i przesuwamy jej bity w lewo lub w prawo :) Zobaczmy, jak to wygląda:

Przesunięcie w lewo

Przesunięcie bitów w lewo jest sygnalizowane przez << Oto przykład:
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));
   }
}
W tym przykładzie liczba x = 64 jest nazywana wartością. Przesuwamy bity tej wartości. Przesuniemy bity w lewo (można było to odgadnąć po kierunku operatora <<). W systemie binarnym liczba 64 = 1000000 Liczba y = 3 nazywana jest odległością przesunięcia. Odległość przesunięcia wskazuje, o ile bitów w prawo/lewo chcesz przesunąć bity liczby x. W naszym przykładzie przesuniemy je o 3 bity w lewo. Aby lepiej zrozumieć proces przesuwania, spójrz na ilustrację. W tym przykładzie używamy wartości int. Int zajmuje 32 bity w pamięci komputera. Tak prezentuje się nasza oryginalna liczba 64: Operatory bitowe w Javie - 2A teraz bierzemy każdy z naszych bitów i dosłownie przesuwamy go w lewo o 3 miejsca: Operatory bitowe w Javie - 3Spójrzmy co otrzymaliśmy. Jak widać wszystkie nasze bity zostały przesunięte, a od krawędzi zakresu dodano kolejne 3 zera. Trzy, bo wykonaliśmy przesunięcie o 3. Gdybyśmy przesunęli się o 10, dodalibyśmy 10 zer. Zatem wyrażenie x << y oznacza "przesunięcie bitów liczby x w lewo o y miejsc". Wynik naszego wyrażenia to liczba 1000000000, czyli 512 w systemie dziesiętnym. Sprawdźmy:
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);
   }
}
Wyświetlone zostanie:
512
W punkt! Teoretycznie bity mogłyby być przesuwane w nieskończoność, ale ponieważ działamy na liczbie typu int, mamy do dyspozycji tylko 32 cyfry binarne. Spośród nich 7 jest już zajętych przez 64 (1000000). Dlatego gdybyśmy przesunęli się o 27 miejsc w lewo, nasza jedynka wyszłaby poza zakres używanego typu danych i zostałaby utracona. Zostałyby tylko zera!
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);
   }
}
Wyświetlone zostanie:
0
Zgodnie z oczekiwaniem, jedynka wyszła poza 32 dostępne bity i zniknęła. Skończyliśmy z 32-bitową liczbą składającą się tylko z zer. Operatory bitowe w Javie - 4Odpowiada to oczywiście liczbie 0 w systemie dziesiętnym. Oto prosta zasada do zapamiętania przesunięć w lewo: Przy każdym przesunięciu w lewo liczba jest mnożona przez 2. Spróbujmy obliczyć następujące wyrażenie bez ilustracji pokazujących bity 111111111 << 3 Musimy pomnożyć liczbę 111111111 przez 2 odpowiednią liczbę razy. W rezultacie otrzymamy 888888888. Napiszmy trochę kodu i sprawdźmy:
public class Main {

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

Przesunięcie w prawo

Ta operacja jest oznaczana przez >>. Robi to samo, ale w przeciwnym kierunku! :) Nie będziemy wyważać otwartych drzwi. Spróbujmy z tym samym 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);
   }
}
Operatory bitowe w Javie - 5Operatory bitowe w Javie - 6W wyniku przesunięcia o 2 w prawo, dwa skrajne zera w naszej liczbie przesuwają się poza zakres i giną. Otrzymujemy 10000, co odpowiada liczbie 16 w systemie dziesiętnym. Wyświetlone zostanie:
16
Oto prosta zasada do zapamiętania przesunięć w prawo: Przy każdym przesunięciu w prawo dzielimy liczbę przez dwa, odrzucając resztę. Na przykład, 35 >> 2 oznacza, że musimy dwukrotnie podzielić 35 przez 2, odrzucając resztę
35/2 = 17 (odrzuć resztę 1) 17/2 = 8 (odrzuć resztę 1)
Ostatecznie 35 >> 2 powinno być równe 8. Sprawdźmy:
public class Main {

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

Kolejność wykonywania operatorów w Javie

Podczas pisania i czytania kodu często można napotkać wyrażenia, które łączą kilka operacji. Bardzo ważne jest, aby rozumieć kolejność, w jakiej zostaną wykonane (w przeciwnym razie wynik może Cię zaskoczyć). Ponieważ w Javie występuje wiele operacji, każdej z nich przypisano miejsce w specjalnej tabeli:
Kolejność wykonywania operatorów
Operatory Kolejność wykonywania
przyrostkowe expr++ expr--
jednoargumentowe ++expr --expr +expr ~ !
multiplikatywne * / %
addytywne + -
przesunięcia << >> >>>
relacyjne < > <= >= instanceof
porównania == !=
bitowa koniunkcja (bitowe AND) &
bitowa alternatywa rozłączna (XOR, exclusive OR) ^
bitowa alternatywa (inclusive OR) |
logiczna koniunkcja (logiczne AND) &&
logiczna alternatywa (logiczne OR) ||
trójargumentowe ? :
przypisania = += -= *= /= %= &= ^= |= <<= >>= >>>=
Wszystkie operacje są wykonywane od lewej do prawej, z uwzględnieniem ich pierwszeństwa. Na przykład, jeśli napiszemy
int x  = 6 - 4/2;
jako pierwsza zostanie wykonana operacja dzielenia (4/2). Została zapisana jako druga ale ma wyższy priorytet. Nawiasy oznaczają najwyższy priorytet. Pewnie pamiętasz to ze szkoły. Na przykład, jeśli dodamy je do naszego wyrażenia
int x  = (6 - 4)/2;
wtedy jako pierwsze wykonane zostanie odejmowanie, ponieważ jest umieszczone w nawiasach. Priorytet operatora logicznego && jest raczej niski (patrz tabela), więc zwykle będzie on ostatni. Na przykład:
boolean x = 6 - 4/2 > 3 && 12*12 <= 119;
To wyrażenie zostanie wykonane w następujący sposób:
  • 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;
Następnie wykonywane są operatory porównania:
  • 4 > 3 = true
boolean x = true && 144 <= 119;
  • 144 <= 119 = false
boolean x = true && false;
I wreszcie operator AND (&&) zostanie wykonany jako ostatni.
boolean x = true && false;
boolean x = false;
Na przykład operator dodawania (+) ma wyższy priorytet niż operator porównania != (nie równe); Dlatego w wyrażeniu
boolean x = 7 != 6+1;
najpierw wykonana zostanie operacja 6+1, następnie sprawdzenie 7 != 7 (które da wynik false), a na koniec przypisanie wyniku (false) do zmiennej x (ogólnie przypisanie ma najniższy priorytet ze wszystkich operatorów; patrz tabela). Operatory bitowe w Javie - 7Uff! To była długa lekcja, ale udało się! Jeśli nie do końca rozumiesz część tej lub poprzednich lekcji, nie martw się. Będziemy poruszać te tematy jeszcze nie raz w przyszłości. Kilka lekcji CodeGym o operacjach logicznych i numerycznych. Nie przejdziemy do nich w najbliższym czasie, ale nie zaszkodzi przeczytać je teraz.
Komentarze
  • Popularne
  • Najnowsze
  • Najstarsze
Musisz się zalogować, aby dodać komentarz
Ta strona nie ma jeszcze żadnych komentarzy