Architecture & DesignHow to Use the Java Bit Manipulation Operators

How to Use the Java Bit Manipulation Operators

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Programmers sometimes have to stoop to the level of bits and bytes when dealing with low-level data. This is particularly seen when developing software for test equipment, networking, operating systems, or establishing direct communication with the hardware. Whatever the case, Java provides the capabilities for extensive bit manipulation and one may use it according to one’s need. This article provides background information related to this capability and the use of the bitwise operators available in Java.

Bits and Bytes

A bit is derived from the phrase “binary digit,” represented by 0 or 1. These two seemingly simple numbers can carry a lot of information when combined. The 0 basically means off/false and 1 means on/true. To put it colloquially, a switch can signal one of two things, either off (0) or on (1). Now, using two switches alternately/together gives 22 = 4 such signals—00, 01, 10, 11. Three switches would provide 23 = 8 signals—000, 001, 010, 011, 100, 101, 110, 111. Four switches, 16 signals, and so on. The individual bits, when combined into a group of eight, it is called a byte (8 bit = 1 byte). The number of signals provided by 8-bit or 1 byte processing is 28 = 256. As the number of bytes increases, the unit becomes Kilobyte (210), Megabyte (220), Gigabyte (230), and so on.

Computers represent all data internally as a sequence of bits. More accurately, it is not even bits but electrical charges represented as having certain voltages as 1/on/true, and the absence or deficiency of it as 0/off/false. This simple idea provides a significant impetus to formulate signal circuitry into a mathematical expression and solves it like any mathematical problem. It is due to this convenience that signals are mapped into binary numbers. There is a branch of mathematics that specifically deals with binary logic, called Boolean Algebra, named after English mathematician and logician George Boole. Boolean algebra provides the principles of binary arithmetic that can be perfectly used as a tool in creating logic circuitry.

When we say binary arithmetic, the basic operators used with the binary operations are AND, OR, and NOT. Also, there are other derived operators such as NAND (NOT AND), NOR (NOT OR), Ex-OR/XOR (Exclusive-OR), and Ex-NOR/XNOR (Exclusive-NOR). The truth table with the basic operators is shown in Figure 1:

A truth table
Figure 1: A truth table

Other derived operators—NAND, NOR, and Ex-NOR—are nothing but the NOT operator added to the result of these basic operators.

Data Types

In Java, there is a data type, called a byte, to hold an eight-bit sequence. If it is required to hold information more than eight bits, there are many other data types, but the bitwise operators only work on integral operands such as byte, char, short, int, and long. In the order stated, each has the capacity to store more bit sequences than the previous one. The bitwise operators do not work on floating-point operands.

Java Bitwise Operators

There are seven bitwise operators in Java: bitwise AND (&), OR (|), Ex-OR (^), left shift (<<), signed right shift (>>), unsigned right shift (>>>), and bitwise complement (~). They operate in the manner as stated above with the help of truth tables. The left shift and right shift operators will be explained later in the article.

The Bitwise Operator vs. Logical Operator

It is worth mentioning that the short-circuit operators, such as logical-AND (&&) and logical-OR (||), must not be confused with bitwise-AND (&) and bitwise-OR (|) operators because they have different significance. The logical operators may be termed as lazy evaluation operators whereas the bitwise operators are eager to greedy evaluation operators. This means that the bitwise operator AND (&) and OR (|) evaluate both sides of the operation. On the other hand, the logical AND (&&) and OR (||) operators evaluate the left side of the operation; if it is true, they only evaluate the right side.

The confusing part is that, on most occasions, they result in the same conclusion. Here is an example to illustrate that.

package org.mano.example;

public class BitwiseOperatorDemo {

   public static void main(String[] args) {

      System.out.println((false |
         false) ? "true" : "false");
      System.out.println((false |
         true) ? "true" : "false");
      System.out.println((true |
         false) ? "true" : "false");
      System.out.println((true |
         true) ? "true" : "false");

      System.out.println((false ||
         false) ? "true" : "false");
      System.out.println((false ||
         true) ? "true" : "false");
      System.out.println((true ||
         false) ? "true" : "false");
      System.out.println((true ||
         true) ? "true" : "false");
      System.out.println (
        "-----------------------------------------");

      System.out.println((false & false)
         ? "true" : "false");
      System.out.println((false & true)
         ? "true" : "false");
      System.out.println((true & false)
         ? "true" : "false");
      System.out.println((true & true)
         ? "true" : "false");

      System.out.println((false &&
         false) ? "true" : "false");
      System.out.println((false &&
         true) ? "true" : "false");
      System.out.println((true &&
         false) ? "true" : "false");
      System.out.println((true &&
         true) ? "true" : "false");
}

Output

false
true
true
true
false
true
true
true
-----------------------------------------
false
false
false
true
false
false
false
true

Observe the next example; it clarifies the point of difference. The logical-AND and logical-OR operations do not even invoke the function f2 () unless the return value of the method f1 () is true. But, this is not the situation with the bitwise-AND and bitwise-OR operators. Both sides of the operation are evaluated in any case.

package org.mano.example;

public class BitwiseOperatorDemo {

   public static void main(String[] args) {
      if (f1() | f2())
         System.out.println("bitwise-OR");
      if (!f1() & f2())
         System.out.println("bitwise-AND");
      System.out.println(
            "-----------------------------------");
      if (f1() || f2())
         System.out.println("logical-OR");
      if (!f1() && f2())
      System.out.println("logical-AND");
   }

   public static Boolean f1() {
      System.out.println("Function f1 invoked");
      return true;
   }

   public static Boolean f2() {
      System.out.println("Function f2 invoked");
      return true;
   }
}

Output

Function f1 invoked
Function f2 invoked
bitwise-OR
Function f1 invoked
Function f2 invoked
-----------------------------------
Function f1 invoked
logical-OR
Function f1 invoked

Java Bit Manipulation

The bitwise-AND (&), OR (|), and Ex-OR (^) operators compare two operands bit by bit.

  • The AND (&) operator sets the result bit to 1 only if both the operand bits are 1.
  • The OR (|) operator, on the other hand, sets the result bit to 1 when any one or both the operand bits is 1.
  • The Ex-OR operator sets the result bit to 1 if the corresponding bit of exactly one of its operands is 1.
  • The left shift operator (<<) shifts the bits of its left operand to the left according to the number specified in the right operand. The 0s are pushed in from the right.
  • The signed right shift operator (>>) shifts the bit of its left operand to the right according to the number of bits specified by the right operand. Because the operator maintains the signed bit of the operand, the negative operand pushes 1t from the left; otherwise, 0s are pushed. This technique maintains the signed bit of the operand.
  • The unsigned right shift operator (>>>) is similar to the left shift operator, except only in the reverse direction. This means that the operator shifts the bits in its left operand to the right by the number of bits specified by the right operand. The 0s are pushed in from the left.
  • The bitwise complement operator (~) sets all the 0s bits in its operand to 1s and all 1s to 0s.

A Quick Example

package org.mano.example;

public class BitwiseOperatorDemo {

   public static void main(String[] args) {

      int a = -10;
      int b = -6;
      System.out.print(a + ": ");
      showBits(a);
      System.out.print(b + ": ");
      showBits(b);
      System.out.print("AND (a & b): ");
      showBits(a & b);
      System.out.print("OR (a | b): ");
      showBits(a | b);
      System.out.print("Ex-OR (a ^ b): ");
      showBits(a ^ b);
      System.out.print("left-shift (a << 2): ");
      showBits(a << 2);
      System.out.print("signed right-shift
         (a >> 2): ");
      showBits(a >> 2);
      System.out.print("right-shift
         (a >>> 2): ");
      showBits(a >>> 2);
      System.out.print("Complement (~a): ");
      showBits(~a);

   }

   public static void showBits(int param) {
      int mask = 1 << 31;

      for (int i = 1; i <= 32; i++,
            param <<= 1) {
         System.out.print((param & mask) ==
            0 ? "0" : "1");
         if (i % 8 == 0)
            System.out.print(" ");
      }
      System.out.println();
   }
}

Output

-10: 11111111 11111111 11111111 11110110
-6: 11111111 11111111 11111111 11111010
AND (a & b): 11111111 11111111 11111111 11110010
OR (a | b): 11111111 11111111 11111111 11111110
Ex-OR (a ^ b): 00000000 00000000 00000000 00001100
left-shift (a << 2): 11111111 11111111 11111111 11011000
signed right-shift (a >> 2): 11111111 11111111 11111111
   11111101
right-shift (a >>> 2): 00111111 11111111 11111111 11111101
Complement (~a): 00000000 00000000 00000000 00001001

The BitSet Class

Java provides a dedicated class, called BitSet, in the java.util package to work with bits. This class may be used to perform bit manipulation operations in a more convenient manner. Refer to the article “Exploring Java BitSet” for more detail on its usage.

Conclusion

The bitwise operation can be used just like any other operator in Java. The only difference between it and other operations is that it evaluates in a bit-by-bit value. On occasion, one may combine the bitwise operation with other binary operators. However, note that bitwise operators only work with integral types: byte, char, short, int, and long. Floating point types, such as float and double, cannot be used with bitwise operators.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories