Подтвердить что ты не робот

Java конвертирует int в hex и обратно

У меня есть следующий код...

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 в шестую строку ffff8000, но затем он не может преобразовать шестнадцатеричную строку в Integer.

В .Net он работает так, как я ожидал, и returns -32768.

Я знаю, что я мог бы написать свой собственный маленький метод, чтобы преобразовать это сам, но мне просто интересно, не хватает ли я чего-то или если это действительно ошибка?

4b9b3361

Ответ 1

Он переполняется, потому что число отрицательно.

Попробуйте это, и он будет работать:

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

Ответ 2

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, он переполнится к правильному значению.

Ответ 3

  • int в Hex:

    Integer.toHexString(intValue);
    
  • Hex to int:

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

Вы также можете использовать long вместо int (если значение не соответствует границам int):

  • Hex to long:

    Long.valueOf(hexString, 16).longValue()
    
  • long до шестнадцатеричного

    Long.toHexString(longValue)
    

Ответ 4

Попробуйте использовать класс 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());

Ответ 5

Стоит отметить, что Java 8 имеет методы Integer.parseUnsignedInt и Long.parseUnsignedLong, которые делают то, что вы хотели, в частности:

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

Название немного запутанно, поскольку оно анализирует целое число со знаком из шестнадцатеричной строки, но оно выполняет работу.

Ответ 6

Вы должны знать, что метод parseInt Java - это куча кода, в котором есть "false" hex: если вы хотите перевести -32768, вы должны преобразовать абсолютное значение в шестнадцатеричный, а затем добавить строку с помощью "-".

Существует образец файла 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

Ответ 7

Хехе, любопытно. Я думаю, что это "намеренная ошибка", так сказать.

Основная причина заключается в том, как записывается класс 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 в кумулятивном результате, начиная с максимального конца целочисленного диапазона и продолжая вниз оттуда. Почему они этого не сделали, нужно было бы спросить Джоша Блоха или того, кто его осуществил в первую очередь. Это может быть просто оптимизация.

Однако

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

Ответ 8

Использование 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();

Ответ 9

Как Integer.toHexString(byte/integer) не работает, когда вы пытаетесь преобразовать подписанные байты, такие как декодированные символы UTF-16, которые вы должны использовать:

Integer.toString(byte/integer, 16);

или

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

назад вы можете использовать

Integer.parseInt(hexString, 16);