1. Bitwise left shift

Java also has 3 bitwise shift operators: If you really need to, you can very simply shift all the bits of a number several positions to the left or right.

To shift the bits of a number to the left, you need the bitwise left shift operator. This is how it's written:

a << b

Where a is the number whose bits are being shifted, and b is a number that indicates how many times to shift the bits of the number a to the left. During this operation, the low-order bits added on the right are zeros.

Examples:

Example Result
0b00000011 << 1
0b00000110
0b00000011 << 2
0b00001100
0b00000011 << 5
0b01100000
0b00000011 << 20
0b001100000000000000000000

Shifting one digit to the left has the same effect as multiplying a number by 2.

Want to multiply a number by 16? 16 is the same as 24. So you shift the number 4 digits to the left


2. Bitwise shift right

Bits can also be shifted to the right. To do this, use the bitwise right shift operator. This is how it's written:

a >> b

Where a is the number whose bits are being shifted, and b is the number of times to shift the bits of the number a to right.

Examples:

Example Result
0b11000011 >> 1
0b01100001
0b11000011 >> 2
0b00110000
0b11000011 >> 5
0b00000110
0b11000011 >> 20
0b00000000

Shifting one digit to the right has the same effect as dividing a number by 2.

During this operation, the high-order bits added on the left are zeros, but not always!

Important!

The leftmost bit of a signed number is called the sign bit: if the number is positive, it is 0; but if the number is negative, this bit is 1.

When shifting the bits of a number to the right, the value of the sign bit would ordinarily also shift and the sign of the number would be lost. Accordingly, for negative numbers (where the leftmost bit is 1), this bit gets special treatment. When shifting the bits of a number to the right, a 0 is added on the left if the leftmost bit was 0, and a 1 is added on the left if the leftmost bit was 1.

But in the example above, that doesn't appear to be the result. Why? Because integer literals are ints, and 0b11111111 actually means 0b00000000000000000000000011111111. That is, the leftmost bit is zero.

Many programmers are frustrated by this right-shift behavior and would prefer the number to always be padded with zeros. So Java added another right shift operator.

This is how it's written:

a >>> b

Where a is the number whose bits are being shifted, and b  is the number of times to shift the bits of the number a to right. This operator always appends zeros on the left, regardless of the original value of the sign bit of the number a.


1
Task
Module 1. Java Syntax,  level 11lesson 2
Locked
StringTokenizer
Using a StringTokenizer, split the query variable into parts based on the delimiter variable. Example: getTokens("java.util.stream", "\\.") returns the string array {"java", "util", "stream"}

3. Working with flags

Programmers created an almost entirely new field of study on the basis of bitwise and shift operations: working with flags.

When computers had very little memory, it was highly popular to cram a lot of information into a single number. A number was treated as an array of bits: an int is 32 bits, and a long is 64 bits.

You can write a lot of information in such a number, especially if you need to store logical (true or false) values. A single long is like a boolean array comprised of 64 elements. These bits were called flags and were manipulated using the following operations:

  • set flag
    (make a specific bit equal to 1)
  • reset flag
    (make a specific bit equal to 0)
  • check flag
    (check the value of a specific bit)

And here's how it's done with bitwise operators.

Setting a flag

To set a specific bit to 1, you need to perform a bitwise OR operation between the number whose bit you want to set and a specially created number, where only that bit is 1.

For example, suppose you have the number 0b00001010 and you need to set the 5th bit to 1. In that case, you need to:

0b00001010 | 0b00010000 = 0b00011010

If the 5th bit had been set to one already, then nothing would have changed.

In general, the operation of setting a flag can be written as follows

a | (1 << b)

Where a is the number whose bit will be set to 1. And b is the position of the bit to be set. Using the left shift operator is super convenient here, since you can immediately tell which bit we are working with.

Resetting a flag

To reset a specific bit (i.e. set it to 0) without disturbing other bits, you need to perform an & operation between the number whose bit you want to reset (i.e. set to 0) and a specially created number, where all the bits are equal to 1 except for the bit you want to reset.

For example, suppose you have the number 0b00001010 and you need to set the 4th bit to 0. In that case, you need to:

0b00001010 & 0b11110111 = 0b00000010

If the 4th bit had been set to zero already, then nothing would have changed.

In general, the operation of resetting a flag can be written as follows

a & ~(1 << b)

Where a is the number whose bit will be reset to 0. And b is the position of the bit to be cleared.

To get a number where all the bits are 1 except the one we want to be zero, we first shift 1 b positions to the left, and then use the bitwise NOT operator to invert the result.

Checking a flag

In addition to setting or resetting a specific flag, sometimes you just need to check whether a given flag is set, i.e. whether a certain bit is equal to 1. This is quite easy to do with a bitwise &.

For example, suppose you need to check whether the 4th bit is set to 1 in the number 0b00001010. Then you need to do this:

if ( (0b00001010 & 0b00001000) == 0b00001000 )

In general, the operation of checking a flag can be written as follows

(a & (1 << b)) == (1 << b)

Where a is the number whose bit is being checked. And b is the position of the bit to be checked.


4. Encryption

The bitwise XOR operation is often used by programmers for simple encryption. In general, such encryption looks like this:

result = number ^ password;

Where number is the data we want to encrypt, password is a special number used as a "password" for the data, and result is the encrypted number.

number == (number ^ password) ^ password;

The important thing here is that when the XOR operator is applied to a number twice, it produces the original number, regardless of the "password".

To recover number from the encrypted result, you just need to perform the operation again:

original number = result ^ password;

Example:

class Solution
{
   public static int[] encrypt(int[] data, int password)
   {
     int[] result = new int[data.length];
     for (int i = 0; i <  data.length; i++)
       result[i] = data[i] ^ password;
     return result;
   }

   public static void main(String[] args)
   {
     int[] data =  {1, 3, 5, 7, 9, 11};
     int password = 199;

     // Encrypt the array of data
     int[] encrypted = encrypt(data, password);
     System.out.println(Arrays.toString(encrypted));

     // Decrypt the array of data
     int[] decrypted = encrypt(encrypted, password);
     System.out.println(Arrays.toString(decrypted));
   }
}

1
Task
Module 1. Java Syntax,  level 11lesson 2
Locked
String.format()
Make the format(String name, int salary) method return a string like this: My name is . I will earn $ a month. Use the String.format() method to do this.