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)
};
개별 비트 확인, 설정, 지우기 및 전환 비트 마스크로 long을 사용
정수 기본 요소의 비트 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
매개 변수로 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
은 이진수로 011
이며 위의 조건을 만족합니다. 0은 2의 거듭 제곱이 아니며 명시 적으로 검사해야합니다.
boolean isPowerOfTwo(int x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
왼쪽 및 오른쪽 시프트 사용법
우리는 READ , WRITE 및 EXECUTE 의 세 가지 권한을 가지고 있다고 가정 해 보겠습니다. 각 권한의 범위는 0에서 7까지입니다 (4 비트 시스템을 가정 해 봅시다)
RESOURCE = READ WRITE EXECUTE (12 비트 숫자)
RESOURCE = 0100 0110 0101 = 4 6 5 (12 비트 수)
위에 설정된 (12 비트 숫자) 권한을 얻으려면 어떻게해야합니까?
0100 0110 0101
0000 0000 0111 (&)
0000 0000 0101 = 5
그래서 이것은 우리가 RESOURCE 의 EXECUTE 권한을 얻는 방법입니다. 이제 리소스 에 대한 읽기 권한을 얻으려면 어떻게해야할까요?
0100 0110 0101
0111 0000 0000 (&)
0100 0000 0000 = 1024
권리? 당신은 아마 이것을 추측하고 있습니까? 그러나 권한은 1024가됩니다. 우리는 리소스에 대한 읽기 권한 만 얻고 자합니다. 걱정하지 마세요. 그래서 우리는 이동 교환 원을 가졌습니다. 우리가 보는 경우, 읽기 권한은 실제 결과보다 8 비트이므로, 결과의 바로 오른쪽에 READ 권한을 가져올 일부 시프트 연산자를 적용한다면? 우리가한다면?
0100 0000 0000 >> 8 => 0000 0000 0100 (0으로 대체 된 양수이므로 부호에 신경 쓰지 않는다면 부호없는 오른쪽 시프트 연산자 만 사용하십시오)
이제 실제로 4라는 읽기 권한이 있습니다.
예를 들어, 리소스에 대해 READ , WRITE , EXECUTE 권한이 부여 된 경우이 리소스에 대한 사용 권한을 얻기 위해 수행 할 수있는 작업은 무엇입니까?
먼저 바이너리 권한의 예를 들어 봅시다. (여전히 4 비트 수를 가정 함)
READ = 0001
쓰기 = 0100
EXECUTE = 0110
우리가 단순히 다음과 같이 할 것이라고 생각한다면 :
READ | WRITE | EXECUTE
, 당신은 다소 옳지 만 정확하게는 아닙니다. 우리가 READ를 수행한다면 어떻게 될까요? 쓰기 | 실행
0001 | 0100 | 0110 => 0111
그러나 사용 권한은 실제로 0001로 표시됩니다 (이 예에서는 0001 0110 0110).
그래서 이것을하기 위해 READ 가 8 비트 뒤에 놓이고 WRITE 는 4 비트 뒤쳐지고 PERMISSIONS 는 마지막에 놓입니다. RESOURCE 권한에 사용되는 번호 시스템은 실제로 12 비트입니다 (이 예에서는). 다른 시스템에서는 다를 수 있습니다.
(읽기 << 8) | (쓰기 << 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 (WRITE)
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 명의 다른 운영자가 필요하지 않습니다.
좀 더 자세한 답변을 원하면이 질문 을보십시오.