int를 16 진수로 다시 변환하는 Java


80

다음 코드가 있습니다.

int Val=-32768;
String Hex=Integer.toHexString(Val);

이것은 ffff8000

int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
int SecondAttempt=Integer.decode("0x"+Hex);  // Error "Invalid Int"

따라서 처음에는 -32768 값을 16 진수 문자열 ffff8000으로 변환하지만 16 진수 문자열을 다시 Integer로 변환 할 수 없습니다.

에서 .Net작동 나는 기대, 그리고 것입니다 returns -32768.

나는 이것을 직접 변환하기 위해 내 자신의 작은 방법을 작성할 수 있다는 것을 알고 있지만, 내가 뭔가를 놓치고 있는지 아니면 이것이 진짜 버그인지 궁금합니다.



5
힌트 : 규칙에 따라 변수 이름은 소문자로 시작합니다.int firstAttempt = 5;
Simulant

답변:


48

숫자가 음수이기 때문에 오버플로됩니다.

이것을 시도하면 작동합니다.

int n = (int) Long.parseLong("ffff8000", 16);

고마워요 roni, 그게 최선의 해결책 인 것 같습니다. Int.parseInt가 예상대로 작동하지 않는 것이 여전히 이상해 보입니다.
Rich S

ffff8000는,이 양수입니다 (더 큰 다음 최대 INT)를 int에 맞지 않는 (그것은 문자열입니다 영하이있는 경우에만 그것을 부정 정도)
로니 바 야나이

1
parseInt가 서명 된 int를 취하고 toHexString이 서명되지 않은 결과를 생성하기 때문입니다 (내 대답 참조) ...
brimborium

덕분에 u는 내 하루 :) 저장
Vineesh TP

1
@roni, 진수는 같은 문자열 값의 것 인 경우 String Hex=Integer.toHexString("xyz");"XYZ"로 진수에서 다시 문자열을 얻는 방법
수 보드

73
int val = -32768;
String hex = Integer.toHexString(val);

int parsedResult = (int) Long.parseLong(hex, 16);
System.out.println(parsedResult);

그것이 당신이 할 수있는 방법입니다.

그것이 당신의 방식으로 작동하지 않는 이유 Integer.parseInt는 서명 된 int를 취하고 서명 toHexString되지 않은 결과 를 생성합니다. 따라서보다 높은 것을 삽입하면 0x7FFFFFF자동으로 오류가 발생합니다. long대신 파싱 하면 여전히 서명됩니다. 그러나 int로 다시 캐스팅하면 올바른 값으로 오버플로됩니다.


27
  • int 16 진수로 :

    Integer.toHexString(intValue);
    
  • 16 진수 int:

    Integer.valueOf(hexString, 16).intValue();
    

(값이 경계에 맞지 않는 경우) long대신 사용할 수도 있습니다 .intint

  • 16 진수 long:

    Long.valueOf(hexString, 16).longValue()
    
  • long 16 진수로

    Long.toHexString(longValue)
    

9

Java 8에는 메서드가 Integer.parseUnsignedInt있으며 Long.parseUnsignedLong원하는 작업을 수행 한다는 점을 언급 할 가치가 있습니다.

Integer.parseUnsignedInt("ffff8000",16) == -32768

이름은 16 진 문자열에서 부호있는 정수를 구문 분석하기 때문에 약간 혼란 스럽지만 작업을 수행합니다.


7

BigInteger 클래스를 사용해보십시오.

int Val=-32768;
String Hex=Integer.toHexString(Val);

//int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
//int SecondAttempt=Integer.decode("0x"+Hex);  // Error "Invalid Int"
BigInteger i = new BigInteger(Hex,16);
System.out.println(i.intValue());

4

Integer.toHexString (byte / integer)은 UTF-16 디코딩 문자와 같은 부호있는 바이트를 변환하려고 할 때 작동하지 않으므로 사용해야합니다.

Integer.toString(byte/integer, 16);

또는

String.format("%02X", byte/integer);

반대로 사용할 수 있습니다

Integer.parseInt(hexString, 16);

3

Java의 parseInt 메소드는 실제로 "false"hex를 먹는 코드입니다. -32768을 번역하려면 절대 값을 16 진수로 변환 한 다음 문자열 앞에 '-'를 추가해야합니다.

Integer.java 파일의 샘플이 있습니다.

public static int parseInt(String s, int radix)

설명은 매우 명확합니다.

* Parses the string argument as a signed integer in the radix 
* specified by the second argument. The characters in the string 
...
...
* parseInt("0", 10) returns 0
* parseInt("473", 10) returns 473
* parseInt("-0", 10) returns 0
* parseInt("-FF", 16) returns -255

2

사용 Integer.toHexString(...)하는 것이 좋은 대답입니다. 그러나 개인적으로 String.format(...).

이 샘플을 테스트로 사용해보십시오.

byte[] values = new byte[64];
Arrays.fill(values, (byte)8);  //Fills array with 8 just for test
String valuesStr = "";
for(int i = 0; i < values.length; i++)
    valuesStr += String.format("0x%02x", values[i] & 0xff) + " ";
valuesStr.trim();

2

아래 코드는 작동합니다.

int a=-32768;
String a1=Integer.toHexString(a);
int parsedResult=(int)Long.parseLong(a1,16);
System.out.println("Parsed Value is " +parsedResult);

1

헤헤, 궁금해. 말하자면 이것은 "의도적 인 버그"라고 생각합니다.

근본적인 이유는 Integer 클래스가 작성되는 방법입니다. 기본적으로 parseInt는 양수에 대해 "최적화"됩니다. 문자열을 구문 분석 할 때 결과가 누적되지만 부정됩니다. 그런 다음 최종 결과의 부호를 뒤집습니다.

예:

66 = 0x42

다음과 같이 구문 분석됩니다.

4*(-1) = -4
-4 * 16 = -64 (hex 4 parsed)

-64 - 2 = -66 (hex 2 parsed)

return -66 * (-1) = 66

이제 FFFF8000의 예를 살펴 보겠습니다.

16*(-1) = -16 (first F parsed)
-16*16 = -256 

-256 - 16 = -272 (second F parsed)
-272 * 16 = -4352 

-4352 - 16 = -4368 (third F parsed)
-4352 * 16 = -69888

-69888 - 16 = -69904 (forth F parsed)
-69904 * 16 = -1118464 

-1118464 - 8 = -1118472 (8 parsed)
-1118464 * 16 = -17895552 

-17895552 - 0 = -17895552 (first 0 parsed)
Here it blows up since -17895552 < -Integer.MAX_VALUE / 16 (-134217728). 
Attempting to execute the next logical step in the chain (-17895552 * 16)
would cause an integer overflow error.

편집 (추가) : parseInt ()가 -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE에 대해 "일관되게"작동하려면 다음에서 -Integer.MAX_VALUE에 도달 할 때 "회전"하는 논리를 구현해야했습니다. 누적 결과, 정수 범위의 최대 끝에서 시작하여 아래로 계속됩니다. 왜 이렇게하지 않았는지, Josh Bloch 나 처음에 구현 한 사람에게 물어봐야합니다. 단지 최적화 일 수 있습니다.

하나,

Hex=Integer.toHexString(Integer.MAX_VALUE);
System.out.println(Hex);
System.out.println(Integer.parseInt(Hex.toUpperCase(), 16));

이 이유 때문에 잘 작동합니다. Integer의 소스에서이 주석을 찾을 수 있습니다.

// Accumulating negatively avoids surprises near MAX_VALUE

2
// Accumulating negatively avoids surprises near MAX_VALUE->하지만 놀라움을 더 낮게 소개합니다 0 ^^
brimborium
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.