Java перетворює int на hex і назад


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.

Я знаю, що міг би сам написати свій маленький метод, щоб перетворити це, але мені просто цікаво, чи я чогось не пропускаю, чи це справді помилка?



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, що якщо hex має значення String, наприклад, String Hex=Integer.toHexString("xyz");як повернути рядок з hex як "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, він переллється до правильного значення.


27
  • int до Hex:

    Integer.toHexString(intValue);
    
  • Шістнадцятковий до int:

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

Можливо, ви також захочете використовувати longзамість int(якщо значення не відповідає intмежам):

  • Шістнадцятковий до long:

    Long.valueOf(hexString, 16).longValue()
    
  • long до Гекса

    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 (байт / ціле число) не працює, коли ви намагаєтесь перетворити підписані байти, такі як декодовані символи UTF-16, які потрібно використовувати:

Integer.toString(byte/integer, 16);

або

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

зворотний ви можете використовувати

Integer.parseInt(hexString, 16);

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);

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 ^^
бримборій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.