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

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

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

Rich S
источник
5
Просто подсказка: имена переменных по соглашению начинаются с символа нижнего регистра:int firstAttempt = 5;
Simulant

Ответы:

48

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

Попробуйте это, и это сработает:

int n = (int) Long.parseLong("ffff8000", 16);
Рони Бар Янаи
источник
Спасибо, Рони, кажется, это лучшее решение. Хотя все еще кажется странным, что Int.parseInt работает не так, как я ожидал.
Rich S
ffff8000 не вписывается в int (больше, чем max int), это положительное число (это строка, поэтому оно отрицательное, только если у него есть минус)
roni bar yanai
1
Это потому, что parseInt принимает подписанный int, а toHexString дает беззнаковый результат (см. Мой ответ) ...
brimborium
Спасибо, ты спас мне день :)
Vineesh TP
1
@roni, а что, если шестнадцатеричный формат имеет строковое значение, например, String Hex=Integer.toHexString("xyz");как вернуть строку из шестнадцатеричного значения как «xyz»
subodh
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, оно переполнится до правильного значения.

Brimborium
источник
27
  • int в Hex:

    Integer.toHexString(intValue);
    
  • Hex для int:

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

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

  • Hex для long:

    Long.valueOf(hexString, 16).longValue()
    
  • long в Hex

    Long.toHexString(longValue)
    
скоро
источник
9

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

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

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

Юваль Сапир
источник
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);
Spektakulatius
источник
3

Java-метод parseInt на самом деле представляет собой набор кода, поедающего "ложное" шестнадцатеричное значение: если вы хотите перевести -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
Бендж
источник
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);
user7258708
источник
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 в совокупный результат, начиная с максимального конца целочисленного диапазона и продолжая оттуда вниз. Почему они этого не сделали, нужно было бы спросить Джоша Блоха или того, кто реализовал это в первую очередь. Возможно, это просто оптимизация.

Тем не мение,

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