Java Language
ビット操作
サーチ…
備考
C / C ++とは異なり、Javaは基盤となるマシンハードウェアに関して完全にエンディアンニュートラルです。デフォルトでは、エンディアンの動作が大きくなることはありません。あなたは明示的にあなたが望む行動を指定しなければなりません。
byte
型は符号付きで、範囲は-128〜+ 127です。バイト値を符号なしの同等値に変換するには、次のように0xFFでマスクします(b & 0xFF)
。
ビットフラグメントとしての値のパッキング/アンパック
メモリのパフォーマンスでは、複数の値を単一のプリミティブ値に圧縮するのが一般的です。これは、さまざまな情報を単一の変数に渡すのに便利です。
たとえば、 RGBのカラーコードなどの3バイトを単一のintにパックすることができます。
値のパッキング
// Raw bytes as input
byte[] b = {(byte)0x65, (byte)0xFF, (byte)0x31};
// Packed in big endian: x == 0x65FF31
int x = (b[0] & 0xFF) << 16 // Red
| (b[1] & 0xFF) << 8 // Green
| (b[2] & 0xFF) << 0; // Blue
// Packed in little endian: y == 0x31FF65
int y = (b[0] & 0xFF) << 0
| (b[1] & 0xFF) << 8
| (b[2] & 0xFF) << 16;
値のアンパック
// Raw int32 as input
int x = 0x31FF65;
// Unpacked in big endian: {0x65, 0xFF, 0x31}
byte[] c = {
(byte)(x >> 16),
(byte)(x >> 8),
(byte)(x & 0xFF)
};
// Unpacked in little endian: {0x31, 0xFF, 0x65}
byte[] d = {
(byte)(x & 0xFF),
(byte)(x >> 8),
(byte)(x >> 16)
};
個々のビットのチェック、設定、クリア、トグル。長いビットマスクとして使用する
整数プリミティブのビットn
を変更したいとすると、 i
(byte、short、char、int、またはlong):
(i & 1 << n) != 0 // checks bit 'n'
i |= 1 << n; // sets bit 'n' to 1
i &= ~(1 << n); // sets bit 'n' to 0
i ^= 1 << n; // toggles the value of bit 'n'
long / int / short / byteをビットマスクとして使う:
public class BitMaskExample {
private static final long FIRST_BIT = 1L << 0;
private static final long SECOND_BIT = 1L << 1;
private static final long THIRD_BIT = 1L << 2;
private static final long FOURTH_BIT = 1L << 3;
private static final long FIFTH_BIT = 1L << 4;
private static final long BIT_55 = 1L << 54;
public static void main(String[] args) {
checkBitMask(FIRST_BIT | THIRD_BIT | FIFTH_BIT | BIT_55);
}
private static void checkBitMask(long bitmask) {
System.out.println("FIRST_BIT: " + ((bitmask & FIRST_BIT) != 0));
System.out.println("SECOND_BIT: " + ((bitmask & SECOND_BIT) != 0));
System.out.println("THIRD_BIT: " + ((bitmask & THIRD_BIT) != 0));
System.out.println("FOURTh_BIT: " + ((bitmask & FOURTH_BIT) != 0));
System.out.println("FIFTH_BIT: " + ((bitmask & FIFTH_BIT) != 0));
System.out.println("BIT_55: " + ((bitmask & BIT_55) != 0));
}
}
プリント
FIRST_BIT: true
SECOND_BIT: false
THIRD_BIT: true
FOURTh_BIT: false
FIFTH_BIT: true
BIT_55: true
これはcheckBitMask
パラメータとして渡されたマスクに一致しますFIRST_BIT | THIRD_BIT | FIFTH_BIT | BIT_55
。
2の力を表現する
整数の2乗(2 ^ n)を表現するために、 n
を明示的に指定できるビットシフト演算を使用することができます。
構文は基本的には次のとおりです。
int pow2 = 1<<n;
例:
int twoExp4 = 1<<4; //2^4
int twoExp5 = 1<<5; //2^5
int twoExp6 = 1<<6; //2^6
...
int twoExp31 = 1<<31; //2^31
これは、16進数または10進値を使用する代わりに、2の累乗が使用されることが明らかになるはずの定数を定義する場合に特に便利です。
int twoExp4 = 0x10; //hexadecimal
int twoExp5 = 0x20; //hexadecimal
int twoExp6 = 64; //decimal
...
int twoExp31 = -2147483648; //is that a power of 2?
2のintのべき乗を計算する簡単な方法は、
int pow2(int exp){
return 1<<exp;
}
数字が2の累乗であるかどうかを確認する
整数x
が2の累乗である場合、1ビットのみが設定され、 x-1
はそれ以降に設定されるすべてのビットを有する。例えば、 4
が100
あり、 3
が2進数で011
であり、上記の条件を満たす。ゼロは2の累乗ではなく、明示的にチェックする必要があります。
boolean isPowerOfTwo(int x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
左シフトと右シフトの使用法
READ 、 WRITE 、 EXECUTEという 3種類のパーミッションがあるとしましょう。各許可の範囲は0から7までです(4ビット数のシステムを仮定しましょう)
RESOURCE = READ WRITE EXECUTE(12ビット数)
RESOURCE = 0100 0110 0101 = 4 6 5(12ビット数)
上記(12ビット数)で設定した(12ビットの)パーミッションをどのように取得できますか?
0100 0110 0101
0000 0000 0111(&)
0000 0000 0101 = 5
したがって、これがRESOURCEの EXECUTEパーミッションを取得する方法です。さて、 リソースの READ権限を取得したいのですが?
0100 0110 0101
0111 0000 0000(&)
0100 0000 0000 = 1024
右?あなたはおそらくこれを仮定していますか?しかし、許可は1024年に起こります。私たちはそのリソースに対してREAD権限しか得られません。心配しないでください。そういうわけで、シフト演算子があります。私たちが見ると、READ権限は実際の結果より8ビット遅れているので、結果の右端にREAD権限を与えるシフト演算子を適用すると、もし私たちがすれば:
0100 0000 0000 >> 8 => 0000 0000 0100(正の数で0に置き換えられているため、符号を気にしない場合は、符号なしの右シフト演算子を使用してください)
実際には4つのREAD権限があります。
今、たとえば、 リソースに対してREAD 、 WRITE 、 EXECUTEパーミッションが与えられていますが、このリソースに対してパーミッションを与えるにはどうすればよいですか?
最初にバイナリパーミッションの例を見てみましょう。 (まだ4ビット数のシステムを想定しています)
READ = 0001
WRITE = 0100
EXECUTE = 0110
あなたが単に私たちがやることを考えているなら、
READ | WRITE | EXECUTE
、あなたはちょっと正しいですが正確にはありません。参照してください、もし私たちがREAD |書き込み|実行する
0001 | 0100 | 0110 => 0111
しかし、パーミッションは実際には(この例では)0001 0100 0110
ですから、これを行うには、 READが8ビット遅れ、 WRITEが4ビット遅れ、 PERMISSIONSが最後に配置されていることがわかります。 RESOURCE権限のために使用されている番号システムは実際には12ビットです(この例では)。これは、異なるシステムで異なる(できます)ことができます。
(READ << 8)| (WRITE << 4)| (実行)
0000 0000 0001 << 8(READ)
0001 0000 0000(8ビット左シフト)
0000 0000 0100 << 4(WRITE)
0000 0100 0000(4ビット左シフト)
0000 0000 0001(実行)
今、上記のシフトの結果を追加すると、それは次のようになります。
0001 0000 0000(READ)
0000 0100 0000(書き込み)
0000 0000 0001(実行)
0001 0100 0001(許可)
java.util.BitSetクラス
1.7以降、シンプルで使いやすいビットストレージと操作インタフェースを提供するjava.util.BitSetクラスがあります。
final BitSet bitSet = new BitSet(8); // by default all bits are unset
IntStream.range(0, 8).filter(i -> i % 2 == 0).forEach(bitSet::set); // {0, 2, 4, 6}
bitSet.set(3); // {0, 2, 3, 4, 6}
bitSet.set(3, false); // {0, 2, 4, 6}
final boolean b = bitSet.get(3); // b = false
bitSet.flip(6); // {0, 2, 4}
bitSet.set(100); // {0, 2, 4, 100} - expands automatically
BitSet
はClonable
とSerializable
実装しており、フード内のすべてのビット値は自動的に展開されるlong[] words
フィールドに格納されます。
また、全体のセットの論理演算をサポートand
、 or
、 xor
、 andNot
:
bitSet.and(new BitSet(8));
bitSet.or(new BitSet(8));
bitSet.xor(new BitSet(8));
bitSet.andNot(new BitSet(8));
署名付きシフトと符号なしシフト
Javaでは、すべての数値プリミティブが署名されています。たとえば、intは常に[-2 ^ 31 - 1、2 ^ 31]の値を表し、最初のビットは負の値の場合は-1、正の場合は0の値に署名します。
基本シフト演算子>>
および<<
は符号付き演算子です。彼らは価値の兆候を保つでしょう。
しかし、プログラマは、 符号なしの値を格納するために数値を使用するのが一般的です 。 intの場合、範囲を[0,2 ^ 32 - 1]にシフトし、符号付きintの場合の2倍の値を持つことを意味します。
これらのパワーユーザーの場合、意味のない記号のビット。そのため、Javaでは、符号シフトを無視して左シフト演算子>>>
追加しました。
initial value: 4 ( 100)
signed left-shift: 4 << 1 8 ( 1000)
signed right-shift: 4 >> 1 2 ( 10)
unsigned right-shift: 4 >>> 1 2 ( 10)
initial value: -4 ( 11111111111111111111111111111100)
signed left-shift: -4 << 1 -8 ( 11111111111111111111111111111000)
signed right-shift: -4 >> 1 -2 ( 11111111111111111111111111111110)
unsigned right-shift: -4 >>> 1 2147483646 ( 1111111111111111111111111111110)
なぜ<<<
はありませんか?
これは、右シフトの意図された定義に由来します。左に空いている場所を埋めるので、サインのビットについては決断を下すことはありません。結果として、2つの異なる演算子の必要はない。