Java chuyển đổi int thành hex và quay lại một lần nữa


80

Tôi có mã sau ...

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

Điều này tương đương với ffff8000

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

Vì vậy, ban đầu, nó chuyển đổi giá trị -32768 thành chuỗi hex ffff8000, nhưng sau đó nó không thể chuyển đổi chuỗi hex trở lại thành Số nguyên.

Trong .Netnó hoạt động như tôi mong đợi, và returns -32768.

Tôi biết rằng tôi có thể viết một phương thức nhỏ của riêng mình để tự chuyển đổi điều này, nhưng tôi chỉ tự hỏi liệu tôi có thiếu thứ gì đó không, hay đây thực sự là một lỗi?



5
Chỉ cần một gợi ý: Như tên biến ước bắt đầu với một nhân vật chữ thường:int firstAttempt = 5;
Simulant

Câu trả lời:


48

Nó tràn, bởi vì số âm.

Hãy thử điều này và nó sẽ hoạt động:

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

Cảm ơn roni, đó có vẻ là giải pháp tốt nhất. Mặc dù vẫn có vẻ kỳ lạ khi Int.parseInt không hoạt động như tôi mong đợi.
Rich S

ffff8000 không phù hợp với một int (int lớn hơn sau đó max), đây là một số dương (nó là một chuỗi để nó tiêu cực chỉ khi nó có trừ)
Roni thanh yanai

1
Đó là bởi vì parseInt mất một int ký và toHexString tạo ra một kết quả unsigned (xem câu trả lời của tôi) ...
brimborium

Cảm ơn bạn đã cứu một ngày của tôi :)
Vineesh TP.

1
@roni, những gì nếu hex là của Chuỗi giá trị như String Hex=Integer.toHexString("xyz");thế nào để có được chuỗi lại từ hex là "xyz"
Subodh

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

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

Đó là cách bạn có thể làm điều đó.

Lý do tại sao nó không hoạt động theo cách của bạn: Integer.parseIntlấy int có dấu, trong khi toHexStringtạo ra kết quả không dấu. Vì vậy, nếu bạn chèn một cái gì đó cao hơn 0x7FFFFFF, một lỗi sẽ tự động được đưa ra. Nếu bạn phân tích cú pháp longthay thế, nó sẽ vẫn được ký. Nhưng khi bạn chuyển nó trở lại int, nó sẽ tràn sang giá trị chính xác.


26
  • int sang Hex:

    Integer.toHexString(intValue);
    
  • Hex thành int:

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

Bạn cũng có thể muốn sử dụng longthay thế int(nếu giá trị không phù hợp với intgiới hạn):

  • Hex thành long:

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

    Long.toHexString(longValue)
    

9

Điều đáng nói là Java 8 có các phương thức Integer.parseUnsignedIntLong.parseUnsignedLongđiều đó thực hiện những gì bạn muốn, cụ thể:

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

Tên hơi khó hiểu, vì nó phân tích cú pháp một số nguyên có dấu từ một chuỗi hex, nhưng nó hoạt động.


7

Hãy thử sử dụng lớp BigInteger, nó hoạt động.

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

Vì Integer.toHexString (byte / số nguyên) không hoạt động khi bạn đang cố gắng chuyển đổi các byte có dấu như ký tự được giải mã UTF-16, bạn phải sử dụng:

Integer.toString(byte/integer, 16);

hoặc là

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

đảo ngược bạn có thể sử dụng

Integer.parseInt(hexString, 16);

3

Phương thức parseInt của Java trên thực tế là một loạt mã ăn "false" hex: nếu bạn muốn dịch -32768, bạn nên chuyển đổi giá trị tuyệt đối thành hex, sau đó thêm chuỗi với '-'.

Có một mẫu tệp Integer.java:

public static int parseInt(String s, int radix)

Mô tả khá rõ ràng:

* 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

Sử dụng Integer.toHexString(...)là một câu trả lời tốt. Nhưng cá nhân thích sử dụng hơn String.format(...).

Hãy thử mẫu này như một bài kiểm tra.

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

Mã dưới đây sẽ hoạt động:

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

1

Hehe, tò mò. Tôi nghĩ rằng đây là một "lỗi có chủ đích", có thể nói như vậy.

Lý do cơ bản là cách lớp Integer được viết. Về cơ bản, parseInt được "tối ưu hóa" cho các số dương. Khi phân tích cú pháp chuỗi, nó xây dựng kết quả một cách tích lũy, nhưng bị phủ định. Sau đó, nó lật dấu hiệu của kết quả cuối cùng.

Thí dụ:

66 = 0x42

phân tích cú pháp như:

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

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

return -66 * (-1) = 66

Bây giờ, hãy xem ví dụ FFFF8000 của bạn

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.

Chỉnh sửa (bổ sung): để parseInt () hoạt động "nhất quán" cho -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE, chúng sẽ phải triển khai logic để "xoay" khi đạt tới -Integer.MAX_VALUE trong kết quả tích lũy, bắt đầu lại ở cuối tối đa của dải số nguyên và tiếp tục xuống dưới từ đó. Tại sao họ không làm điều này, người ta sẽ phải hỏi Josh Bloch hoặc bất cứ ai thực hiện nó ngay từ đầu. Nó có thể chỉ là một sự tối ưu hóa.

Tuy nhiên,

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

hoạt động tốt, chỉ vì lý do này. Trong sourcee cho Integer, bạn có thể tìm thấy nhận xét này.

// Accumulating negatively avoids surprises near MAX_VALUE

2
// Accumulating negatively avoids surprises near MAX_VALUE-> nhưng nó giới thiệu bất ngờ giảm 0 ^^
brimborium
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.