Ответ 1
Он переполняется, потому что число отрицательно.
Попробуйте это, и он будет работать:
int n = (int) Long.parseLong("ffff8000", 16);
У меня есть следующий код...
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
.
Я знаю, что я мог бы написать свой собственный маленький метод, чтобы преобразовать это сам, но мне просто интересно, не хватает ли я чего-то или если это действительно ошибка?
Он переполняется, потому что число отрицательно.
Попробуйте это, и он будет работать:
int n = (int) Long.parseLong("ffff8000", 16);
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, он переполнится к правильному значению.
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)
Попробуйте использовать класс 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());
Стоит отметить, что Java 8 имеет методы Integer.parseUnsignedInt
и Long.parseUnsignedLong
, которые делают то, что вы хотели, в частности:
Integer.parseUnsignedInt("ffff8000",16) == -32768
Название немного запутанно, поскольку оно анализирует целое число со знаком из шестнадцатеричной строки, но оно выполняет работу.
Вы должны знать, что метод 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
Хехе, любопытно. Я думаю, что это "намеренная ошибка", так сказать.
Основная причина заключается в том, как записывается класс 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
Использование 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();
Как Integer.toHexString(byte/integer) не работает, когда вы пытаетесь преобразовать подписанные байты, такие как декодированные символы UTF-16, которые вы должны использовать:
Integer.toString(byte/integer, 16);
или
String.format("%02X", byte/integer);
назад вы можете использовать
Integer.parseInt(hexString, 16);