Int를 부호없는 바이트로 변환하고 그 반대로 변환하는 방법


92

숫자를 부호없는 바이트로 변환해야합니다. 숫자는 항상 255보다 작거나 같으므로 1 바이트에 맞습니다.

또한 해당 바이트를 해당 숫자로 다시 변환해야합니다. Java에서 어떻게 할 수 있습니까? 나는 여러 가지 방법을 시도했지만 아무것도 작동하지 않습니다. 지금 내가하려는 작업은 다음과 같습니다.

int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);

이제 해당 바이트를 다시 숫자로 변환합니다.

Byte test = new Byte(binaryByte);
int msgSize = test.intValue();

분명히 이것은 작동하지 않습니다. 어떤 이유로 항상 숫자를 65. 어떤 제안?


나는 또한이 방법을 시도했다 : crazysquirrel.com/computing/java/basics/…- 작동하지 않습니다.
darksky 2011 년

답변:


201

바이트는 항상 Java로 서명됩니다. 그러나 0xFF로 이진화하여 부호없는 값을 얻을 수 있습니다.

int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234

아직 65 점을 받고 있어요 ... 왜죠?
darksky 2011 년

1
원하는 숫자를 바이트에 저장합니다. Java는 서명되지 않은 숫자가 아닌 서명 된 숫자로 간주합니다. 그러나 모든 비트는 마치 부호없는 숫자 인 것처럼 동일합니다. 문자열을 바이트로 변환하는 것은 관련되지 않은 또 다른 질문입니다. 새 질문에 별도로 게시하십시오.
JB Nizet 2011 년

1
getInt를 사용하여 int를 되찾고 int를 바이트로 변환하십시오. int는 int입니다. 어디에서 왔는지는 중요하지 않습니다.
JB Nizet 2011 년

19
왜 비트 및 with 0xFF결과가 부호없는 정수가됩니까? 몇 가지 설명이 정말 도움이 될 것입니다.
user462455

2
Java 8은 동일한 방법을 사용합니다. public static int toUnsignedInt (byte x) {return ((int) x) & 0xff; }
Daniel De León

55

Java 8은 서명되지 않은 변환 Byte.toUnsignedInt으로 변환 byte을 제공 합니다 int. Oracle의 JDK에서는 return ((int) x) & 0xff;HotSpot이 이미이 패턴을 최적화하는 방법을 이해하고 있지만 다른 VM에 내장 될 수 있기 때문에 간단히 구현됩니다 . 더 중요한 것은 호출이 무엇을하는지 이해하기 위해 사전 지식이 필요하지 않다는 것 toUnsignedInt(foo)입니다.

총, 자바 8 변환하는 방법을 제공 byte하고 short서명을 int하고 long, 그리고 int부호로를 long. 변환하는 방법은 byte서명을가 short하였다 고의로 생략 JVM이 단지 산술 제공하므로 intlong어쨌든.

int를 다시 바이트로 변환하려면 캐스트를 사용하십시오 : (byte)someInt. 결과적으로 축소되는 기본 변환 은 마지막 8 비트를 제외한 모든 비트를 버립니다.


7

예상되는 8 비트 값을 부호있는 정수에서 부호없는 값으로 변환해야하는 경우 간단한 비트 이동을 사용할 수 있습니다.

int signed = -119;  // 11111111 11111111 11111111 10001001

/**
 * Use unsigned right shift operator to drop unset bits in positions 8-31
 */
int psuedoUnsigned = (signed << 24) >>> 24;  // 00000000 00000000 00000000 10001001 -> 137 base 10

/** 
 * Convert back to signed by using the sign-extension properties of the right shift operator
 */
int backToSigned = (psuedoUnsigned << 24) >> 24; // back to original bit pattern

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

int기본 유형 이 아닌 다른 것을 사용하는 경우 분명히 이동량을 조정해야합니다. http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

또한 bytetype을 사용할 수 없으므로 다른 응답자가 언급 한대로 부호있는 값이 생성됩니다. 8 비트 부호없는 값을 나타내는 데 사용할 수있는 가장 작은 기본 유형은 short.


3

Integer.toString(size)하여 정수의 문자 표현으로 통화 변환은 문자를 즉 '5'. 해당 문자 의 ASCII 표현 은 값 65입니다.

Integer.parseInt원래 int 값을 되돌리려면 먼저를 사용하여 문자열을 정수 값으로 다시 구문 분석해야 합니다.

결론적으로, 부호있는 / 부호없는 변환 String의 경우 @JB가 제안하는대로 그림에서 벗어나 비트 조작을 사용 하는 것이 가장 좋습니다.


그래서 이렇게? (여전히 65 점을 String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
얻음

@Nayefc, 난 당신이 당신의 코멘트 :-) 기록 된 것처럼 내 대답 업데이트
페테르 토록

감사합니다! 어떤 이유로 여전히 65를 인쇄합니다. 이것은 무엇을 의미 하는가? 65 만 표시되면 실제로 바이트에 저장되는 내용을 알 수 없습니다. 또한 내 질문을 확인하십시오. 편집하고 문자열 변환에 대한 섹션을 추가했습니다. :)
darksky

다시 @Nayefc 는 숫자의 숫자 값이 아니라 텍스트에 포함 된 문자String.getBytes() 의 ASCII 값을 생성합니다 . 위에서 언급했듯이 문자열을 숫자 값으로 구문 분석 해야합니다 .
Péter Török 2011 년

1
@Nayefc, 실제로 완전히 다른 질문입니다. 그리고 AFAIS는 작동합니다. 변환의 실제 입력 및 출력과 케이스를 재현하기위한 전체 코드를 포함하여 새 질문을 만듭니다.
Péter Török 2011 년

3

솔루션은 잘 작동하지만 (감사합니다!) 캐스팅을 피하고 저수준 작업을 JDK에 남겨두고 싶다면 DataOutputStream을 사용하여 int를 작성하고 DataInputStream을 사용하여 다시 읽을 수 있습니다. 자동으로 unsigned로 처리됩니다. 바이트 :

int를 바이너리 바이트로 변환하기 위해;

ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int val = 250;
dos.write(byteVal);
...
dos.flush();

다시 읽기 :

// important to use a (non-Unicode!) encoding like US_ASCII or ISO-8859-1,
// i.e., one that uses one byte per character
ByteArrayInputStream bis = new ByteArrayInputStream(
   bos.toString("ISO-8859-1").getBytes("ISO-8859-1"));
DataInputStream dis = new DataInputStream(bis);
int byteVal = dis.readUnsignedByte();

Esp. 바이너리 데이터 형식 (예 : 플랫 메시지 형식 등)을 처리하는 데 유용합니다.


3

를 제외하고 charJava의 다른 모든 숫자 데이터 유형은 서명됩니다.

이전 답변에서 말했듯이을 사용하여 and작업을 수행하여 부호없는 값을 얻을 수 있습니다 0xFF. 이 답변에서 어떻게 발생하는지 설명하겠습니다.

int i = 234;
byte b = (byte) i;
System.out.println(b);  // -22

int i2 = b & 0xFF;      
// This is like casting b to int and perform and operation with 0xFF

System.out.println(i2); // 234

머신이 32 비트 인 경우 int데이터 유형에 값을 저장하려면 32 비트가 필요합니다. byte8 비트 만 필요합니다.

int변수는 i(32 비트 정수로서) 다음 메모리에 표시된다.

0{24}11101010

그런 다음 byte변수 b는 다음과 같이 표시됩니다.

11101010

으로 byte의가 서명되지 않은 경우,이 값은 나타냅니다 -22. (메모리에서 음의 정수를 표현하는 방법에 대해 자세히 알아 보려면 2의 보수를 검색하십시오)

그런 다음 캐스팅하면 캐스팅이 숫자의 부호를 유지하기 때문에 int여전히 될 것 -22입니다.

1{24}11101010

으로 작업 수행 의 캐스트 된 32-bit값입니다 .band0xFF

 1{24}11101010 & 0{24}11111111
=0{24}11101010

그럼 당신 234은 답 을 얻습니다 .


1

BigInteger로 바이트와 부호없는 정수 처리 :

byte[] b = ...                    // your integer in big-endian
BigInteger ui = new BigInteger(b) // let BigInteger do the work
int i = ui.intValue()             // unsigned value assigned to i

1

너무 늦었지만 JB Nizet이 제공 한 솔루션이 작동하는 이유를 명확히 할 수 있으므로 이에 대한 의견을 제공하고 싶습니다. 나는 바이트 파서와 문자열 변환 작업 에서이 작은 문제를 발견했습니다. 이 자바 문서에 따르면 더 큰 크기의 정수 유형에서 더 작은 크기의 정수 유형으로 복사하면 다음과 같은 일이 발생합니다.

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 부호있는 정수를 정수 유형 T로 축소 변환하면 가장 낮은 n 개를 제외하고 모두 버립니다. 순서 비트, 여기서 n은 유형 T를 나타내는 데 사용되는 비트 수입니다. 숫자 값의 크기에 대한 정보의 손실 가능성 외에도 결과 값의 부호가 입력 값의 부호와 다를 수 있습니다. .

이 자바 문서가 https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html 바이트 라고 말했듯이 바이트가 정수 유형인지 확인할 수 있습니다 . 바이트 데이터 유형은 8 비트 부호있는 2입니다. 보수 정수.

따라서 정수 (32 비트)를 바이트 (8 비트)로 캐스팅하는 경우 해당 정수의 마지막 (최하위 8 비트)을 주어진 바이트 변수에 복사합니다.

int a = 128;
byte b = (byte)a; // Last 8 bits gets copied
System.out.println(b);  // -128

이야기의 두 번째 부분은 Java 단항 및 이항 연산자가 피연산자를 촉진하는 방법을 포함합니다. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 확장 기본 변환 (§5.1.2)이 적용되어 지정된대로 피연산자 중 하나 또는 둘 다를 변환합니다. 다음 규칙에 따라 :

피연산자가 double 유형이면 다른 피연산자가 double로 변환됩니다.

그렇지 않고 피연산자 중 하나가 float 유형이면 다른 피연산자가 float로 변환됩니다.

그렇지 않고 피연산자 중 하나가 long 유형이면 다른 피연산자가 long으로 변환됩니다.

그렇지 않으면 두 피연산자가 모두 int 유형으로 변환됩니다.

int 유형 및 / 또는 그 이하로 작업하는 경우 int로 승격되므로 안심하십시오.

// byte b(0x80) gets promoted to int (0xFF80) by the & operator and then
// 0xFF80 & 0xFF (0xFF translates to 0x00FF) bitwise operation yields 
// 0x0080
a = b & 0xFF;
System.out.println(a); // 128

나는 이것에도 내 머리를 긁었다 :). 여기에 rgettman의 좋은 대답이 있습니다. 정수 및 long에 대해서만 Java의 비트 연산자?


0

기본 래퍼 클래스를 사용하려면 작동하지만 모든 Java 유형은 기본적으로 서명됩니다.

public static void main(String[] args) {
    Integer i=5;
    Byte b = Byte.valueOf(i+""); //converts i to String and calls Byte.valueOf()
    System.out.println(b);
    System.out.println(Integer.valueOf(b));
}

-1

자바 7에서

public class Main {
    public static void main(String[] args) {
        byte b =  -2;
        int i = 0 ;
        i = ( b & 0b1111_1111 ) ;
        System.err.println(i);
    }
}

결과 : 254

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.