Javaではハードウェアを制御することがあり、ビットの値を計算したいという時がある。Web系だと使わないが、徐々にIoTが広がっている現状、使う機会も多くなっていくはずだ。
このページではJavaでのビット演算子の使い方をまとめてみた。
目次
Javaでのビット演算子の使い方
Javaのビット演算子は、そのままだが「ビットの演算を行う演算子」だ。
ビットの演算とは、数値をビット単位で演算することを指す。ビットの値を演算子のオペランドに与えて論理積や論理和などの演算を行い、結果を数値として生み出す。
この演算子がよく使われるひとつの分野は、ハードウエアを制御する分野だ。32ビットの数値あり、そのひとつひとつのビットがスイッチの状態に対応しているとする。最下位のビットから数えて4番目のビットだけを抜き出して、スイッチの状態を調べたい。こんなとき、このビット演算子が使える。
Webアプリケーションなどではなかなか登場しないが、こういうものがあると知っておくのはJavaエンジニアとしていいことだろう。
まずは、演算子の種類から見ていこう。
演算子の種類
ビット演算子には、4つの種類がある。次のセクションでこれらのひとつひとつの演算子の詳細を説明している。
- 整数ビット演算子 &
- 整数ビット演算子 |
- 整数ビット演算子 ^
- ビット補数演算子 ~
これらの演算子は、整数のビットの並びの同じ位置にあるビット同士を演算する。この例は、&演算子の演算の様子を例として示している。
ビットの位置 |
最上位 |
3 |
2 |
1 |
最下位 |
オペランド1 |
1 |
1 |
1 |
1 |
0 |
オペランド2 |
1 |
0 |
1 |
0 |
0 |
演算 |
↓ |
↓ |
↓ |
↓ |
↓ |
結果 |
1 |
0 |
1 |
0 |
1 |
次は、ビット演算子の詳細だ。演算子それぞれに書き方ある。演算も違う。その詳細を見てみよう。
整数ビット演算子 &
演算子「&」は整数のビットの論理積を求める。&演算子の左と右にあるオペランドのビットごとに演算が行われる。
書き方の基本は簡単だ。
演算結果 = オペランド1 & オペランド2;
数値を構成するひとつのビットに注目すると、論理積の演算結果は次のようになる。
- オペランド1とオペランド2のビットが両方とも1ならば、演算結果は1となる。
- それ以外は0となる。
項目 |
値 |
|||
オペランド1 |
1 |
1 |
0 |
0 |
オペランド2 |
1 |
0 |
1 |
0 |
演算結果 |
1 |
0 |
0 |
0 |
16ビットの数値をオペランドに持つ場合の演算結果は、次の表のようになる。この表は、演算がどのような結果になるかを示している。各ビットに注目すると上のひとつのビットに注目した表のとおりに演算しているのが分かる。
表現 |
16進数 |
2進数 |
オペランド1 |
0xff00 |
0b1111_1111_0000_0000 |
オペランド2 |
0xf0f0 |
0b1111_0000_1111_0000 |
演算結果 |
0xf000 |
0b1111_0000_0000_0000 |
整数ビット演算子 |
演算子「|」は整数のビットの論理和を求める。|演算子の左と右にあるふたつのオペランドのビットごとに演算が行われる。
書き方の基本は簡単だ。
演算結果 = オペランド1 | オペランド2;
数値を構成するひとつのビットに注目すると論理和の演算結果は次のようになる。
- オペランド1とオペランド2のビットのどちらか1ならば、演算結果は1となる。
- それ以外は0となる。
項目 |
値 |
|||
オペランド1 |
1 |
1 |
0 |
0 |
オペランド2 |
1 |
0 |
1 |
0 |
演算結果 |
1 |
1 |
1 |
0 |
16ビットの数値をオペランドに持つ場合の演算結果は次のようになる。
表現 |
16進数 |
2進数 |
オペランド1 |
0xff00 |
0b1111_1111_0000_0000 |
オペランド2 |
0xf0f0 |
0b1111_0000_1111_0000 |
演算結果 |
0xf000 |
0b1111_1111_1111_0000 |
整数ビット演算子 ^
演算子「^」は整数のビットの排他論理和を求める。^演算子の左と右にあるふたつのオペランドのビットごとに演算が行われる。
書き方の基本は簡単だ。
演算結果 = オペランド1 ^ オペランド2;
数値を構成するひとつのビットに注目すると排他論理和の演算結果は次のようになる。
- オペランド1とオペランド2のビットの値が異なれば、演算結果は1となる。
- それ以外は0となる。
項目 |
値 |
|||
オペランド1 |
1 |
1 |
0 |
0 |
オペランド2 |
1 |
0 |
1 |
0 |
演算結果 |
0 |
1 |
1 |
0 |
16ビットの数値をオペランドに持つ場合の演算結果は次のようになる。
表現 |
16進数 |
2進数 |
オペランド1 |
0xff00 |
0b1111_1111_0000_0000 |
オペランド2 |
0xf0f0 |
0b1111_0000_1111_0000 |
演算結果 |
0xf000 |
0b0000_1111_1111_0000 |
ビット補数演算子 ~
演算子「~」は整数のビットの補数を求める。~演算子の左のあるオペランドのビットに対して演算が行われる。
書き方の基本は簡単だ。
演算結果 = ~オペランド;
数値を構成するひとつのビットに注目すると補数の演算結果は次のようになる。
- オペランドのビットが1ならば、演算結果は0となる。
- オペランドのビットが0ならば、演算結果は1となる。
項目 |
値 |
|
オペランド |
1 |
0 |
演算結果 |
0 |
1 |
16ビットの数値をオペランドに持つ場合の演算結果は次のようになる。
表現 |
16進数 |
2進数 |
オペランド1 |
0xff00 |
0b1111_1111_0000_0000 |
演算結果 |
0x00ff |
0b000_0000_1111_1111 |
ビット演算子のサンプルプログラム
このサンプルプログラムは、前のセクションで例としてあげた16ビットのそれぞれの演算をそのままプログラムに書いたものだ。実際のコードで書き方と演算結果を確かめよう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class BitwiseOperator { public static void main (String[] args) { int value1 = 0xff00;//[1] int value2 = 0xf0f0;//[2] int result;//[3] result = value1 & value2;//[4] System.out.println("[5] 0xff00 & 0xf0f0 = 0x" + Integer.toHexString(result)); result = value1 | value2;//[6] System.out.println("[7] 0xff00 | 0xf0f0 = 0x" + Integer.toHexString(result)); result = value1 ^ value2;//[8] System.out.println("[9] 0xff00 ^ 0xf0f0 = 0x0" + Integer.toHexString(result)); result = ~value1;//[10] System.out.println("[11] ~0xff00 = 0x0" + Integer.toHexString(result)); } } |
実行結果
1 2 3 4 |
[5] 0xff00 & 0xf0f0 = 0xf000 [7] 0xff00 | 0xf0f0 = 0xfff0 [9] 0xff00 ^ 0xf0f0 = 0x0ff0 [11] ~0xff00 = 0x0ffff00ff |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] value1を宣言し、0xff00を代入する。
- [2] value2を宣言し、0xf0f0を代入する。
- [3] resultを宣言する。
- [4] resultにvalue1 & value2を代入する。
- [5] resultを表示する。
- [6] resultにvalue1 | value2を代入する。
- [7] resultを表示する。
- [8] valueにvalue1 ^ value2を代入する。
- [9] resultを表示する。
- [10] valueに~value1を代入する。
- [11] resultを表示する。
ビットの値を取り出すサンプルプログラム
このサンプルプログラムは、冒頭で書いたスイッチの状態を取り出す課題の回答となる。最下位ビットから4番目のビットにスイッチが繋がっていて、スイッチをONするとビットの値が1になり、OFFすると0になる。
このプログラムでは、この4番目のビットの値だけ取り出すために&演算子を使っている。Mask Bitで4番目のビットだけを1にしておけば、そのビットの変化だけを取り出せる。他のビットは、すべて0になる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class SwitchStatuesByUsingBitwiseOperator { public class SwitchStatuesByUsingBitwiseOperator { public static void main (String[] args) { int switchStatusOff = 0b0000_0000_0000_0000_0000;//[1] int switchStatusOn = 0b0000_0000_0000_0000_1000;//[2] int switchNumber4MaskBit = 0b0000_0000_0000_0000_1000;//[3] int switchStatus;//[4] switchStatus = switchStatusOn & switchNumber4MaskBit;//[5] System.out.println("[6] Switch ON = " + Integer.toHexString(switchStatus)); switchStatus = switchStatusOff & switchNumber4MaskBit;//[7] System.out.println("[8] Switch OFF = " + Integer.toHexString(switchStatus)); } } |
実行結果
1 2 |
[6] Switch ON = 8 [8] Switch OFF = 0 |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] switchStatusOffを宣言し、0b0000_0000_0000_0000_0000を代入する。
- [2] switchStatusOnを宣言し、0b0000_0000_0000_0000_1000を代入する。
- [3] switchNumber4MaskBitを宣言し、0b0000_0000_0000_0000_1000を代入する。
- [4] switchStatusを宣言する。
- [5] switchStatusにswitchStatusOn & switchNumber4MaskBitを代入する。
- [6] switchStatusを表示する。
- [7] switchStatusにswitchStatusOff & switchNumber4MaskBitを代入する。
- [8] switchStatusを表示する。
まとめ
このページではbit演算子についてまとめてきた。Javaは組みこみ系プログラミングでも動くため、こういったbit演算子も豊富に用意されている。
はじめはとっつきにくいかもしれないが、それほど難しくはないので、マスターしてしまおう。