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.
Nie 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:
Kolejność wykonywania operatorów
Wszystkie operacje są wykonywane od lewej do prawej, z uwzględnieniem ich pierwszeństwa.
Na przykład, jeśli napiszemy
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.
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)
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).
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)
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:
A teraz bierzemy każdy z naszych bitów i dosłownie przesuwamy go w lewo o 3 miejsca:
Spó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.
Odpowiada 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);
}
}
W 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: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 | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
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).
Uff! 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.
GO TO FULL VERSION