In today's lesson, we'll get acquainted with Java Bitwise Operators and consider examples of how to work with them. You're probably familiar with the word "bit". If not, let's recall what it means :)
A bit is the smallest unit of information in a computer. Its name comes from
binary digit. A bit can be expressed by one of two numbers: 1 or 0. There is a special binary number system based on ones and zeros.
We won't delve into a mathematical jungle here. We'll only note that any number in Java can be converted into binary form. To do this, you need to use the wrapper classes.
For example, here's how you can do this for an
int:
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(Integer.toBinaryString(x));
}
}
Console output:
101010110
1010 10110 (I added the space to make it easier to read) is the number 342 in the decimal system. We've actually broken this number down into individual bits: zeros and ones. Operations performed on bits are called
bitwise.
This operator is very simple: it passes over each bit of our number, and flips the bit: zeros become ones, and ones become zeros.
If we apply it to our number 342, here's what happens:
101010110 is 342 represented as a binary number
010101001 is the value of the expression ~342
Let's try to put this into practice:
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(~x);
}
}
Console output:
169
169 is our result (
010101001) in the familiar, decimal system :)
As you can see, it looks quite similar to the logical AND (
&&).
The
&& operator, you will recall, returns true only if both operands are true. Bitwise
& works in a similar way: it compares two numbers bit by bit. The comparison produces a third number.
For example, let's take the numbers 277 and 432:
110110000 is 277 represented as a binary number
1000101011 is 432 represented as a binary number
Next, the operator
& compares the first bit of the upper number to the first bit of the bottom number. Because this is an AND operator, the result will be 1 only if both bits are 1. In any other case, the result is 0.
100010101
&
110110000
_______________
10001000 - result of the
& operator
First, we compare the first bits of the two numbers, then the second bits, then the third, and so on.
As you can see, in only two cases are both corresponding bits in the numbers equal to 1 (the first and fifth bits). All other comparisons produced 0s.
So in the end we got the number 10001000. In the decimal system, it corresponds to the number 272. Let's check:
public class Main {
public static void main(String[] args) {
System.out.println(277&432);
}
}
Console output:
272
This operator works in the same way: comparing two numbers bit by bit. Only now if at least one of the bits is 1, then the result is 1. Let's look at the same numbers (277 and 432):
100010101
|
110110000
_______________
110110101 - result of the
| operator
Here's we get a different result: the only bits that remain zeros are those bits that were zeros in both numbers.
The result is the number 110110101. In the decimal system, it corresponds to the number 437
Let's check:
public class Main {
public static void main(String[] args) {
System.out.println(277|432);
}
}
Console output:
437
We calculated everything correctly! :)
- ^ - bitwise XOR (exclusive OR)
We haven't yet encountered this operator. But there's nothing complicated about it. It is similar to the ordinary OR operator. There is one difference: the ordinary OR returns true if at least one operand is true. But it doesn't have to be one: if both operands are true, the result is true.
But exclusive OR returns true only if exactly one of the operands is true.
If both operands are true, the ordinary OR returns true ("at least one true"), but XOR returns false. That's why it's called exclusive OR.
Knowing how the previous bitwise operators work, you can probably easily calculate 277
^ 432.
But let's dig into it together one more time :)
100010101
^
110110000
_______________
010100101 - result of the
^ operator
That's our result. Those bits that were the same in both numbers produce a 0 (meaning the "only one" test failed). But the bits that formed a 0-1 or 1-0 pair became ones.
Our result is the number 010100101. In the decimal system, it corresponds to the number 165.
Let's see if our calculations are correct:
public class Main {
public static void main(String[] args) {
System.out.println(277^432);
}
}
Console output:
165
Super! Everything is just as we thought :)
Now it's time to get acquainted with bit shifts operators.
The name speaks for itself. We take some number, and move its bits left or right :) Let's see how it looks:
Shift left
A shift of bits to the left is indicated by
<<
Here's an example:
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 this example, the number x = 64 is called the value. It's the bits of the value that we'll shift. We'll shift the bits to the left (you could have guessed this by the direction of the
<< operator)
In the binary system, the number 64 = 1000000
The number
y = 3 is called shift distance. The shift distance indicates how many bits to the right/left you want to shift the bits of the number
x
In our example, we'll shift them 3 bits to the left.
To see the shift process more clearly, look at the picture.
In this example, we use
ints. Ints occupy 32 bits in the computer's memory. This is how our original number 64 looks:
And now we take each of our bits and literally shift them to the left by 3 places:
Take a look at what we got. As you can see, all our bits have shifted, and another 3 zeros have been added from the edge of the range. Three, because we shifted by 3. If we had shifted by 10, 10 zeros would have been added.
Thus, the expression
x << y means "shift the bits of the number
x to the left by y places". The result of our expression is the number of 1000000000, which is 512 in the decimal system.
Let's check:
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);
}
}
Console output:
512
Spot on!
Theoretically, the bits could be shifted endlessly, but because our number is an
int, we have only 32 binary digits available. Of these, 7 are already occupied by 64 (1000000).
Therefore, if we shifted 27 places to the left, our only one would move beyond the data type's range and be lost.
Only zeros would remain!
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);
}
}
Console output:
0
As expected, the one moved beyond the 32 available bits and disappeared. We ended with a 32-bit number consisting of only zeros.
Naturally, this corresponds to 0 in the decimal system.
Here's a simple rule for remembering shifts to the left:
For each shift to the left, the number is multiplied by 2.
Let's try to calculate the following expression without pictures of bits
111111111
<< 3
We need to multiply the number 111111111 by 2. As a result, we get 888888888. Let's write some code and check:
public class Main {
public static void main(String[] args) {
System.out.println(111111111 << 3);
}
}
Console output:
888888888
Shift right
This operation is denoted by
>>.
It does the same thing, but in the other direction! :)
We won't reinvent the wheel. Let's try it with the same
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);
}
}
As a result of a shift to the right by 2, the two extreme zeroes in our number move out of range and are lost. We get 10000, which corresponds to the number 16 in the decimal system
Console output:
16
Here's a simple rule for remembering shifts to the right:
Each shift to the right divides by two, discarding any remainder.
For example,
35
>> 2
means that we need to divide 35 by 2 twice, discarding the remainders
35/2 = 17 (discard remainder 1)
17/2 = 8 (discard remainder 1)
In the end, 35
>> 2 should be equal to 8.
Let's check:
public class Main {
public static void main(String[] args) {
System.out.println(35 >> 2);
}
}
Console output:
8
Operator precedence in Java
While writing and reading code, you'll often find expressions that combine several operations. It's very important to understand the order they will be executed in (otherwise, you may be surprised by the result)
Because Java has lots of operations, each of them has been assigned a place in a special table:
Operator Precedence
Operators |
Precedence |
postfix |
expr++ expr-- |
unary |
++expr --expr +expr ~ ! |
Multiplicative |
* / % |
additive |
+ - |
shift |
<< >> >>> |
relational |
< > <= >= instanceof |
equality |
== != |
bitwise AND |
& |
bitwise exclusive OR |
^ |
bitwise inclusive OR |
| |
logical AND |
&& |
logical OR |
|| |
ternary |
? : |
assignment |
= += -= *= /= %= &= ^= |= <<= >>= >>>=
|
All operations are performed from left to right, taking into account their precedence.
For example, if we write
int x = 6 - 4/2;
then the division operation (
4/2) will be performed first. Although it comes second, it has higher precedence.
Parentheses and brackets indicate maximum precedence. You probably remember that from school.
For example, if you add them to the expression
int x = (6 - 4)/2;
then the subtraction is performed first, since it is enclosed in parentheses.
The precedence of the logical
&& operator is rather low (see the table), so it will usually be last.
For example:
boolean x = 6 - 4/2 > 3 && 12*12 <= 119;
This expression will be executed as follows:
boolean x = 6 - 2 > 3 && 12*12 <= 119;
boolean x = 6 - 2 > 3 && 144 <= 119;
boolean x = 4 > 3 && 144 <= 119;
Next, the comparison operators are executed:
boolean x = true && 144 <= 119;
boolean x = true && false;
And, finally, the AND operator (
&&) will be executed last.
boolean x = true && false;
boolean x = false;
For example, the addition(
+) operator has a higher precedence than the
!= (not equal) comparison operator;
Therefore, in the expression
boolean x = 7 != 6+1;
the 6+1 operation will be performed first, then the 7 != 7 check (which evaluates to false), and finally the assignment of the result (false) to the variable
x (assignment generally has the lowest precedence of all operators; see the table).
Phew! It was a huge lesson, but you did it! If you didn't fully understand some of this or previous lessons, don't worry. We'll touch on these topics more than once in the future.
A couple of CodeGym lessons about logical and numerical operations. We won't get to these any time soon, but there's no harm in you reading them now.
GO TO FULL VERSION