A review of number representation (see Section G.4, p. 598) is recommended before continuing with this section on how integer bitwise operators can be applied to values of integral data types.
Integer bitwise operators include the unary operator ~ (bitwise complement) and the binary operators & (bitwise AND), | (bitwise inclusive OR), and ^ (bitwise exclusive OR, a.k.a. bitwise XOR ).
The binary bitwise operators perform bitwise operations between corresponding individual bit values in the operands. Unary numeric promotion is applied to the operand of the unary bitwise complement operator ~, and binary numeric promotion is applied to the operands of the binary bitwise operators. The result is a new integer value of the promoted type, which can only be either int or long.
Given that A and B are corresponding bit values (either 0 or 1) in the left-hand and right-hand operands, respectively, these bitwise operators are defined as shown in Table 3.14. The operators are listed in decreasing precedence order.
The operators &, |, and ^ can also be applied to boolean operands to perform boolean logical operations (see Section 3.11, p. 70).
Operator Name | Notation | Effect on Each Bit of the Binary Representation |
---|---|---|
Bitwise complement | ~A | Invert the bit value: 1 to 0, 0 to 1. |
Bitwise AND | A & B | 1 if both bits are 1; otherwise, 0. |
Bitwise OR | A | B | 1 if either or both bits are 1; otherwise, 0. |
Bitwise XOR | A ^ B | 1 if and only if one of the bits is 1; otherwise, 0. |
The result of applying bitwise operators between two corresponding bits in the operands is shown in Table 3.15, where A and B are corresponding bit values in left-hand and right-hand operands, respectively. Table 3.15 is analogous to Table 3.10 for boolean logical operators, if we consider bit value 1 to represent true and bit value 0 to represent false.
A | B | ~A | A & B | A | B | A ^ B |
---|---|---|---|---|---|
1 | 1 | 0 | 1 | 1 | 0 |
1 | 0 | 0 | 0 | 1 | 1 |
0 | 1 | 1 | 0 | 1 | 1 |
0 | 0 | 1 | 0 | 0 | 0 |
char v1 = ')'; // Unicode value 41 byte v2 = 13; int result1 = ~v1; // -42 int result2 = v1 & v2; // 9 int result3 = v1 | v2; // 45 int result4 = v1 ^ v2; // 36
Table 3.16 shows how the result is calculated. Unary and binary numeric promotions are applied first, converting the operands to int in these cases. Note that the operator semantics is applied to corresponding individual bits, that is, first bit of left-hand operand and first bit of right-hand operand, second bit of left-hand operand, and second bit of right-hand operand, and so on.
~v1 | v1 & v2 | v1 | v2 | v1 ^ v2 |
---|---|---|---|
~ 0...0010 1001 |
0...0010 1001 & 0...0000 1101 |
0...0010 1001 | 0...0000 1101 |
0...0010 1001 ^ 0...0000 1101 |
= 1...1101 0110 | = 0...0000 1001 | = 0...0010 1101 | = 0...0010 0100 |
= 0xffffffd6 | = 0x00000009 | = 0x0000002d | = 0x00000024 |
= -42 | = 9 | = 45 | = 36 |
It is instructive to run examples and print the result of a bitwise operation in different notations, as shown in Example 3.2. Converting integers to different notations is discussed in Section 10.3 on page 398.
public class BitOperations { public static void main(String[] args) { char v1 = ')'; // Unicode value 41 byte v2 = 13; printIntToStr("v1:", v1); // 41 printIntToStr("v2:", v2); // 13 printIntToStr("~v1:", ~v1); // -42 printIntToStr("v1 & v2:", v1 & v2); // 9 printIntToStr("v1 | v2:", v1 | v2); // 45 printIntToStr("v1 ^ v2:", v1 ^ v2); // 36 } public static void printIntToStr(String label, int result) { System.out.println(label); System.out.println(" Binary: " + Integer.toBinaryString(result)); System.out.println(" Hex: " + Integer.toHexString(result)); System.out.println(" Decimal: " + result); } }
Output from the program:
v1: Binary: 101001 Hex: 29 Decimal: 41 v2: Binary: 1101 Hex: d Decimal: 13 ~v1: Binary: 11111111111111111111111111010110 Hex: ffffffd6 Decimal: -42 v1 & v2: Binary: 1001 Hex: 9 Decimal: 9 v1 | v2: Binary: 101101 Hex: 2d Decimal: 45 v1 ^ v2: Binary: 100100 Hex: 24 Decimal: 36
Bitwise compound assignment operators for the bitwise operators are defined in Table 3.17. Type conversions for these operators, when applied to integral operands, are the same as for other compound assignment operators: an implicit narrowing conversion is performed on assignment when the destination data type is either byte, short, or char. These operators can also be applied to boolean operands to perform logical compound assignments (see Section 3.11, p. 71).
Expression: | Given T Is the Integral Type of b, the Expression Is Evaluated as: |
---|---|
b &= a | b = (T) ((b) & (a)) |
b ^= a | b = (T) ((b) ^ (a)) |
b |= a | b = (T) ((b) | (a)) |
int v0 = -42; char v1 = ')'; // 41 byte v2 = 13; v0 &= 15; // 1...1101 0110 & 0...0000 1111 => 0...0000 0110 (= 6) v1 |= v2; // (1) 0...0010 1001 | 0...0000 1101 => 0...0010 1101 (= 45)
At (1) in the examples above, both the char value in v1 and the byte value in v2 are first promoted to int. The result is implicitly narrowed to the destination type char on assignment.