Làm thế nào để chuyển đổi Int thành Byte không dấu và quay lại


92

Tôi cần chuyển đổi một số thành một byte không dấu. Con số luôn nhỏ hơn hoặc bằng 255, và vì vậy nó sẽ vừa với một byte.

Tôi cũng cần chuyển đổi byte đó trở lại thành số đó. Làm cách nào để làm điều đó trong Java? Tôi đã thử một số cách và không hiệu quả. Đây là những gì tôi đang cố gắng làm bây giờ:

int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);

và bây giờ để chuyển đổi byte đó trở lại thành số:

Byte test = new Byte(binaryByte);
int msgSize = test.intValue();

Rõ ràng, điều này không hoạt động. Vì một số lý do, nó luôn chuyển đổi số thành 65. Bất kỳ đề xuất?


Tôi cũng đã thử phương pháp này: crazysquirrel.com/computing/java/basics/… - không hoạt động.
darksky

Câu trả lời:


201

Một byte luôn được ký bằng Java. Tuy nhiên, bạn có thể nhận được giá trị không dấu của nó bằng cách nhị phân-anding nó với 0xFF:

int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234

Tôi vẫn đang 65 tuổi ... Tại sao vậy?
darksky

1
Nó đang lưu trữ số bạn muốn trong byte. Java chỉ coi nó như một số có dấu chứ không phải là một số không có dấu. Nhưng mọi bit đều giống như thể nó là một số không dấu. Chuyển đổi chuỗi của bạn thành byte là một câu hỏi khác, không liên quan. Đăng nó một cách riêng biệt, trong một câu hỏi mới.
JB Nizet

1
sử dụng getInt để lấy lại số nguyên của bạn và biến đổi số nguyên thành một byte. Một int là một int. Nó đến từ đâu không quan trọng.
JB Nizet

19
Tại sao bitwise và với 0xFFkết quả là một số nguyên không dấu? Một số lời giải thích sẽ thực sự hữu ích.
user462455

2
Java 8 sử dụng cùng một phương thức: public static int toUnsignedInt (byte x) {return ((int) x) & 0xff; }
Daniel De León

55

Java 8 cung cấp Byte.toUnsignedIntđể chuyển đổi bytesang intbằng chuyển đổi không dấu. Trong JDK của Oracle, điều này được thực hiện đơn giản return ((int) x) & 0xff;vì HotSpot đã hiểu cách tối ưu hóa mẫu này, nhưng nó có thể được thực hiện trên các máy ảo khác. Quan trọng hơn, không cần phải có kiến ​​thức trước để hiểu một lệnh gọi để toUnsignedInt(foo)làm gì.

Tổng cộng, Java 8 cung cấp các phương thức để chuyển đổi byteshortsang chưa dấu intlongintsang chưa dấu long. Một phương thức để chuyển đổi bytethành không có dấu shortđã được cố tình bỏ qua vì JVM chỉ cung cấp số học trên intlongdù sao.

Để chuyển đổi một int trở lại một byte, chỉ cần sử dụng một dàn diễn viên: (byte)someInt. Kết quả là chuyển đổi nguyên thủy thu hẹp sẽ loại bỏ tất cả trừ 8 bit cuối cùng.


7

Nếu bạn chỉ cần chuyển đổi một giá trị 8 bit mong đợi từ một giá trị int có dấu thành một giá trị không dấu, bạn có thể sử dụng tính năng chuyển bit đơn giản:

int signed = -119;  // 11111111 11111111 11111111 10001001

/**
 * Use unsigned right shift operator to drop unset bits in positions 8-31
 */
int psuedoUnsigned = (signed << 24) >>> 24;  // 00000000 00000000 00000000 10001001 -> 137 base 10

/** 
 * Convert back to signed by using the sign-extension properties of the right shift operator
 */
int backToSigned = (psuedoUnsigned << 24) >> 24; // back to original bit pattern

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

Nếu sử dụng thứ gì đó không phải intlà loại cơ sở, rõ ràng bạn sẽ cần điều chỉnh lượng dịch chuyển: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Ngoài ra, hãy nhớ rằng bạn không thể sử dụng byteloại, làm như vậy sẽ dẫn đến giá trị có chữ ký như những người trả lời khác đã đề cập. Kiểu nguyên thủy nhỏ nhất mà bạn có thể sử dụng để biểu thị giá trị 8-bit không dấu sẽ là a short.


3

Cuộc Integer.toString(size)gọi chuyển đổi thành biểu diễn char của số nguyên của bạn, tức là char '5'. Biểu diễn ASCII của ký tự đó là giá trị 65.

Trước tiên, bạn cần phân tích cú pháp chuỗi trở lại giá trị số nguyên, ví dụ bằng cách sử dụng Integer.parseInt, để lấy lại giá trị int ban đầu.

Điểm mấu chốt là, đối với chuyển đổi có dấu / không dấu, tốt nhất bạn nên thoát Stringra khỏi hình ảnh và sử dụng thao tác bit như @JB đề xuất.


Vì vậy, như thế này? (Vẫn nhận được 65 ở đây)String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
darksky

@Nayefc, tôi cập nhật câu trả lời của tôi cũng giống như bạn đang viết bình luận của bạn :-)
Péter Török

Được rồi, cám ơn! Vì một số lý do mà nó VẪN in ra 65. Điều đó có nghĩa là gì? Nếu nó chỉ hiển thị 65, những gì thực sự đang được lưu trữ trong byte thì tôi không hiểu. Ngoài ra hãy kiểm tra câu hỏi của tôi, tôi sửa nó và thêm một phần về việc chuyển đổi chuỗi :)
darksky

@Nayefc, một lần nữa, trả String.getBytes()về giá trị ASCII của các ký tự có trong văn bản, không phải giá trị số của các chữ số. Bạn cần phân tích cú pháp chuỗi thành giá trị số, như tôi đã gợi ý ở trên.
Péter Török

1
@Nayefc, vì vậy đó thực sự là một câu hỏi hoàn toàn khác. Và AFAIS nó sẽ hoạt động. Tạo một câu hỏi mới, bao gồm đầu vào và đầu ra thực tế của chuyển đổi và mã đầy đủ để tái tạo trường hợp.
Péter Török

3

Giải pháp hoạt động tốt (cảm ơn!), Nhưng nếu bạn muốn tránh truyền và để công việc cấp thấp cho JDK, bạn có thể sử dụng DataOutputStream để ghi int của bạn và DataInputStream để đọc lại chúng. Chúng tự động được coi là chưa được ký byte sau đó:

Để chuyển đổi int thành byte nhị phân;

ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int val = 250;
dos.write(byteVal);
...
dos.flush();

Đọc lại chúng trong:

// important to use a (non-Unicode!) encoding like US_ASCII or ISO-8859-1,
// i.e., one that uses one byte per character
ByteArrayInputStream bis = new ByteArrayInputStream(
   bos.toString("ISO-8859-1").getBytes("ISO-8859-1"));
DataInputStream dis = new DataInputStream(bis);
int byteVal = dis.readUnsignedByte();

Esp. hữu ích để xử lý các định dạng dữ liệu nhị phân (ví dụ: định dạng thông báo phẳng, v.v.)


3

Ngoại trừ char, mọi kiểu dữ liệu số khác trong Java đều được ký.

Như đã nói trong câu trả lời trước, bạn có thể nhận được giá trị không dấu bằng cách thực hiện một andphép toán với 0xFF. Trong câu trả lời này, tôi sẽ giải thích cách nó xảy ra.

int i = 234;
byte b = (byte) i;
System.out.println(b);  // -22

int i2 = b & 0xFF;      
// This is like casting b to int and perform and operation with 0xFF

System.out.println(i2); // 234

Nếu máy của bạn là 32 bit, thì intkiểu dữ liệu cần 32 bit để lưu trữ các giá trị. bytechỉ cần 8-bit.

Các intbiến iđược biểu diễn trong bộ nhớ như sau (như một số nguyên 32-bit).

0{24}11101010

Sau đó, bytebiến bđược biểu diễn dưới dạng:

11101010

bytes không có dấu, giá trị này đại diện cho -22. (Tìm kiếm phần bù của 2 để tìm hiểu thêm về cách biểu diễn số nguyên âm trong bộ nhớ)

Sau đó, nếu bạn ép kiểu thì intnó sẽ vẫn còn -22vì ép kiểu giữ nguyên dấu của một số.

1{24}11101010

Càng đúc 32-bitgiá trị bthực hiện andhoạt động với 0xFF.

 1{24}11101010 & 0{24}11111111
=0{24}11101010

Sau đó, bạn nhận được 234như câu trả lời.


1

Xử lý byte và số nguyên không dấu với BigInteger:

byte[] b = ...                    // your integer in big-endian
BigInteger ui = new BigInteger(b) // let BigInteger do the work
int i = ui.intValue()             // unsigned value assigned to i

1

Mặc dù đã quá muộn, tôi muốn đưa ra ý kiến ​​đóng góp của mình về vấn đề này vì nó có thể làm rõ lý do tại sao giải pháp do JB Nizet đưa ra lại hoạt động. Tôi tình cờ gặp vấn đề nhỏ này khi làm việc trên trình phân tích cú pháp byte và tự chuyển đổi chuỗi. Khi bạn sao chép từ kiểu tích phân có kích thước lớn hơn sang kiểu tích phân có kích thước nhỏ hơn như tài liệu java này cho biết điều này sẽ xảy ra:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 Chuyển đổi thu hẹp một số nguyên có dấu thành một loại tích phân T chỉ đơn giản là loại bỏ tất cả trừ n thấp nhất bit thứ tự, trong đó n là số bit được sử dụng để biểu diễn kiểu T. Ngoài việc có thể mất thông tin về độ lớn của giá trị số, điều này có thể khiến dấu của giá trị kết quả khác với dấu của giá trị đầu vào .

Bạn có thể chắc chắn rằng byte là kiểu tích phân như tài liệu java này cho biết https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html byte: Kiểu dữ liệu byte là 8-bit có ký hai. số nguyên bổ sung.

Vì vậy, trong trường hợp truyền một số nguyên (32 bit) thành một byte (8 bit), bạn chỉ cần sao chép cuối cùng (8 bit quan trọng nhất) của số nguyên đó vào biến byte đã cho.

int a = 128;
byte b = (byte)a; // Last 8 bits gets copied
System.out.println(b);  // -128

Phần thứ hai của câu chuyện liên quan đến cách các toán tử đơn phân và nhị phân trong Java thúc đẩy các toán hạng. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 Mở rộng chuyển đổi nguyên thủy (§5.1.2) được áp dụng để chuyển đổi một hoặc cả hai toán hạng như đã chỉ định theo các quy tắc sau:

Nếu một trong hai toán hạng thuộc loại double, toán hạng kia được chuyển thành double.

Ngược lại, nếu một trong hai toán hạng là kiểu float, thì toán hạng kia sẽ được chuyển thành float.

Ngược lại, nếu một trong hai toán hạng có kiểu là long, thì toán hạng còn lại sẽ được chuyển thành dài.

Nếu không, cả hai toán hạng đều được chuyển đổi thành kiểu int.

Hãy yên tâm, nếu bạn đang làm việc với kiểu tích phân int và / hoặc thấp hơn, nó sẽ được thăng cấp thành int.

// byte b(0x80) gets promoted to int (0xFF80) by the & operator and then
// 0xFF80 & 0xFF (0xFF translates to 0x00FF) bitwise operation yields 
// 0x0080
a = b & 0xFF;
System.out.println(a); // 128

Tôi cũng vò đầu bứt tai vì chuyện này :). Có một câu trả lời tốt cho điều này ở đây bởi rgettman. Toán tử bitwise trong java chỉ dành cho số nguyên và dài?


0

Nếu bạn muốn sử dụng các lớp trình bao bọc nguyên thủy, điều này sẽ hoạt động, nhưng tất cả các kiểu java đều được ký theo mặc định.

public static void main(String[] args) {
    Integer i=5;
    Byte b = Byte.valueOf(i+""); //converts i to String and calls Byte.valueOf()
    System.out.println(b);
    System.out.println(Integer.valueOf(b));
}

-1

trong java 7

public class Main {
    public static void main(String[] args) {
        byte b =  -2;
        int i = 0 ;
        i = ( b & 0b1111_1111 ) ;
        System.err.println(i);
    }
}

kết quả: 254

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.