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.
All operations are performed from left to right, taking into account their precedence.
For example, if we write
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.
- ~ - bitwise NOT.
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 :)
- & - bitwise AND
public class Main {
public static void main(String[] args) {
System.out.println(277&432);
}
}
Console output:
272
- | - bitwise OR.
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)
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 | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
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:
- 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;
Next, the comparison operators are executed:
- 4 > 3 = true
boolean x = true && 144 <= 119;
- 144 <= 119 = false
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.More reading: |
---|
GO TO FULL VERSION