Chúng ta có thể tạo byte không dấu trong Java không


185

Tôi đang cố gắng chuyển đổi một byte đã ký trong unsign. Vấn đề là dữ liệu tôi đang nhận không được ký và Java không hỗ trợ byte không dấu, vì vậy khi đọc dữ liệu, nó xử lý nó như đã ký.

Tôi đã thử chuyển đổi nó bằng giải pháp sau đây tôi nhận được từ Stack Overflow.

public static int unsignedToBytes(byte a)
{
    int b = a & 0xFF;
    return b;
}

Nhưng khi một lần nữa nó được chuyển đổi theo byte, tôi nhận được cùng một dữ liệu đã ký. Tôi đang cố gắng sử dụng dữ liệu này làm tham số cho một hàm của Java chỉ chấp nhận một byte làm tham số, vì vậy tôi không thể sử dụng bất kỳ loại dữ liệu nào khác. Làm thế nào tôi có thể khắc phục vấn đề này?


2
Quả ổi: UnsignBytes.toint (giá trị byte)
jacktrades

19
java.lang.Byte.toUnsiltInt (giá trị byte);
themarketka

Câu trả lời:


107

Tôi không chắc là tôi hiểu câu hỏi của bạn.

Tôi vừa thử cái này và với byte -12 (giá trị đã ký), nó trả về số nguyên 244 (tương đương với giá trị byte không dấu nhưng được gõ dưới dạng int):

  public static int unsignedToBytes(byte b) {
    return b & 0xFF;
  }

  public static void main(String[] args) {
    System.out.println(unsignedToBytes((byte) -12));
  }

Có phải đó là những gì bạn muốn làm?

Java không cho phép biểu thị 244 dưới dạng bytegiá trị, như C. Để thể hiện các số nguyên dương ở trên Byte.MAX_VALUE(127), bạn phải sử dụng một loại số nguyên khác, như short, inthoặc long.


1
byte b = (byte)unsignedToBytes((byte) -12); bây giờ hãy thử in b
Jigar Joshi

101
Tại sao bạn chấp nhận đây là câu trả lời đúng? Tất cả những gì nó làm giống hệt như phương pháp bạn đề cập trong câu hỏi của bạn - chuyển đổi một byte thành một số nguyên không dấu.
Adamski

1
Điều quan trọng là đôi khi có các giá trị được ký, đôi khi không được ký, vì vậy có lẽ đây là lý do anh ấy chấp nhận câu trả lời này. (byte) (b & 0xff) không có ý nghĩa gì, nhưng (byte) (Math.min ((b & 0xff) * 2, 255)) có ý nghĩa, ví dụ như trong đồ họa máy tính, nó sẽ chỉ tạo ra hình ảnh đại diện bởi byte sáng hơn hai lần. :-)
iirekm

3
Nó cũng có thể được gọi là byteToUnsiated
Hernán Eche

193

Thực tế là các nguyên hàm được ký trong Java không liên quan đến cách chúng được biểu thị trong bộ nhớ / chuyển tuyến - một byte chỉ là 8 bit và bạn có hiểu đó là phạm vi đã ký hay không là tùy thuộc vào bạn. Không có cờ ma thuật nào để nói "cái này được ký" hay "cái này không dấu".

Khi các nguyên thủy được ký, trình biên dịch Java sẽ ngăn bạn gán giá trị cao hơn +127 cho một byte (hoặc thấp hơn -128). Tuy nhiên, không có gì ngăn bạn hạ thấp một int (hoặc ngắn) để đạt được điều này:

int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)

/*
 * Will print a negative int -56 because upcasting byte to int does
 * so called "sign extension" which yields those bits:
 * 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
 *
 * But you could still choose to interpret this as +200.
 */
System.out.println(b); // "-56"

/*
 * Will print a positive int 200 because bitwise AND with 0xFF will
 * zero all the 24 most significant bits that:
 * a) were added during upcasting to int which took place silently
 *    just before evaluating the bitwise AND operator.
 *    So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
 * b) were set to 1s because of "sign extension" during the upcasting
 *
 * 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
 * &
 * 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
 * =======================================
 * 0000 0000 0000 0000 0000 0000 1100 1000 (200)
 */
System.out.println(b & 0xFF); // "200"

/*
 * You would typically do this *within* the method that expected an 
 * unsigned byte and the advantage is you apply `0xFF` only once
 * and than you use the `unsignedByte` variable in all your bitwise
 * operations.
 *
 * You could use any integer type longer than `byte` for the `unsignedByte` variable,
 * i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
 * it would get casted to `int` anyway.
 */
void printUnsignedByte(byte b) {
    int unsignedByte = b & 0xFF;
    System.out.println(unsignedByte); // "200"
}

5
Đối với nhiều hoạt động, nó không có sự khác biệt, tuy nhiên đối với một số hoạt động thì không. Dù bằng cách nào bạn cũng có thể sử dụng một byte là không dấu hoặc sử dụng char không dấu.
Peter Lawrey

61
Truy cập vào một mảng với một số có khả năng tiêu cực không phải là không liên quan.
Stefan

3
@Stefan - Ý tôi là không liên quan trong bối cảnh chúng được thể hiện trên dây như thế nào.
Adamski

5
Mà có phần không liên quan đến câu hỏi. Vì anh ta đã đề cập rằng anh ta cần chuyển nó đến một hàm chỉ chấp nhận các tham số byte, không quan trọng thời tiết, chúng tôi hiểu nó là biểu diễn byte của một con kỳ lân. Java sẽ luôn coi nó là một số đã ký, có thể gây rắc rối cho một ví dụ khi hàm này sử dụng tham số làm chỉ mục. Tuy nhiên, để công bằng, tôi cũng đánh giá thấp 2 câu trả lời hàng đầu khác, vì họ cũng không trả lời câu hỏi.
Stefan

2
@Stefan +1 cho bạn. Hoàn toàn phù hợp nếu bạn đang sử dụng byte để truy cập vào một mảng gồm 256 phần tử. Đó là một ví dụ tuyệt vời để chứng minh tại sao mọi người nên bắt đầu học C và C ++ trước khi chuyển sang Java hoặc C #
Gianluca Ghettini

46

Ngôn ngữ Java không cung cấp bất cứ thứ gì như unsignedtừ khóa. A bytetheo đặc tả ngôn ngữ đại diện cho một giá trị trong khoảng −128 - 127. Chẳng hạn, nếu a byteđược truyền tới intJava sẽ diễn giải bit đầu tiên là phần mở rộng dấu và sử dụng dấu .

Điều đó đang được nói, không có gì ngăn cản bạn xem byteđơn giản là 8 bit và diễn giải các bit đó thành giá trị trong khoảng từ 0 đến 255. Hãy nhớ rằng bạn không thể làm gì để buộc bạn phải giải thích theo phương pháp của người khác. Nếu một phương thức chấp nhận a byte, thì phương thức đó chấp nhận một giá trị trong khoảng từ −128 đến 127 trừ khi có quy định rõ ràng khác.

Dưới đây là một số chuyển đổi / thao tác hữu ích để thuận tiện cho bạn:

Chuyển đổi sang / từ int

// From int to unsigned byte
int i = 200;                    // some value between 0 and 255
byte b = (byte) i;              // 8 bits representing that value

// From unsigned byte to int
byte b = 123;                   // 8 bits representing a value between 0 and 255
int i = b & 0xFF;               // an int representing the same value

(Hoặc, nếu bạn đang dùng Java 8+, hãy sử dụng Byte.toUnsignedInt.)

Phân tích cú pháp / định dạng

Cách tốt nhất là sử dụng các chuyển đổi trên:

// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");

// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));

Mỹ phẩm

Biểu diễn 2 phần bổ sung "chỉ hoạt động" để cộng, trừ và nhân:

// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;

byte sum  = (byte) (b1 + b2);  // 215
byte diff = (byte) (b1 - b2);  // 185
byte prod = (byte) (b2 * b2);  // 225

Bộ phận yêu cầu chuyển đổi thủ công các toán hạng:

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));

1
'char' không đại diện cho một số.
đăng xuất

26
Nói ngắn gọn: Bạn đã sai .
aioobe

36

Không có byte không dấu nguyên thủy trong Java. Điều thông thường là chuyển nó thành loại lớn hơn:

int anUnsignedByte = (int) aSignedByte & 0xff;

Là diễn viên đến một int cần thiết?
nich

Nó có thể là một diễn viên ngầm, nhưng có một trong hai cách. Và diễn viên đó đã ký gia hạn. Và đó là một vấn đề. Nếu bạn thực hiện một vai diễn rõ ràng, ít nhất bạn có thể thấy điều này đang xảy ra.
foo


4

Một ghi chú bên cạnh, nếu bạn muốn in nó ra, bạn chỉ có thể nói

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));

6
sao phức tạp vậy println(b & 0xff)là đủ
phuclv

0

Nếu nghĩ rằng bạn đang tìm kiếm một cái gì đó như thế này.

public static char toUnsigned(byte b) {
    return (char) (b >= 0 ? b : 256 + b);
}

0

Adamski cung cấp câu trả lời tốt nhất, nhưng nó chưa hoàn chỉnh, vì vậy hãy đọc câu trả lời của anh ấy, vì nó giải thích chi tiết tôi không biết.

Nếu bạn có một hàm hệ thống yêu cầu một byte không dấu được truyền cho nó, bạn có thể truyền một byte đã ký vì nó sẽ tự động coi nó là một byte không dấu.

Vì vậy, nếu một hàm hệ thống yêu cầu bốn byte, ví dụ 192 168 0 1 dưới dạng các byte không dấu, bạn có thể vượt qua -64 -88 0 1 và hàm vẫn sẽ hoạt động, bởi vì hành động chuyển chúng đến hàm sẽ không ký chúng .

Tuy nhiên, bạn không có khả năng gặp vấn đề này vì các hàm hệ thống bị ẩn sau các lớp để tương thích đa nền tảng, mặc dù một số phương thức đọc java.io trả về các byte không được ghi là int.

Nếu bạn muốn thấy điều này hoạt động, hãy thử viết các byte đã ký vào một tệp và đọc lại chúng dưới dạng các byte không dấu.


1
Không có những thứ như byte được ký hoặc không dấu.
Vlastimil Ovčáčík

Làm thế nào chính xác là bạn đã viết và đọc các byte trong ví dụ của bạn?
Vlastimil Ovčáčík

0

Bạn cũng có thể:

public static int unsignedToBytes(byte a)
{
    return (int) ( ( a << 24) >>> 24);
}    

Giải trình:

hãy cùng nói nào a = (byte) 133;

Trong bộ nhớ, nó được lưu dưới dạng: "1000 0101" (0x85 ở dạng hex)

Vì vậy, đại diện của nó dịch unsign = 133, đã ký = -123 (dưới dạng bổ sung 2)

một << 24

Khi dịch chuyển trái được thực hiện 24 bit sang trái, kết quả bây giờ là số nguyên 4 byte được biểu diễn dưới dạng:

"10000101 00000000 00000000 00000000" (hoặc "0x85000000" ở dạng hex)

sau đó chúng tôi có

(một << 24) >>> 24

và nó dịch chuyển một lần nữa vào đúng 24 bit nhưng lấp đầy các số 0 đứng đầu. Vì vậy, nó dẫn đến:

"00000000 00000000 00000000 10000101" (hoặc "0x00000085" ở dạng hex)

và đó là biểu diễn không dấu bằng 133.

Nếu bạn đã cố gắng truyền a = (int) a; thì điều gì sẽ xảy ra là nó giữ biểu diễn phần bù 2 của byte và lưu nó dưới dạng phần bù của 2:

(int) "10000101" ---> "11111111 11111111 11111111 10000101"

Và nó được dịch là: -123


2
Năm 2019, điều này là không cần thiết. Chỉ cần sử dụng java.lang.Byte.toUnsignedInt(byte value). Và nếu bạn chưa sử dụng Java 8, hãy nâng cấp ASAP. Java 7 và trước đó là cuối đời.
Stephen C

0

Tôi đang cố gắng sử dụng dữ liệu này làm tham số cho hàm của Java, chỉ chấp nhận một byte làm tham số

Điều này không khác biệt cơ bản với một hàm chấp nhận một số nguyên mà bạn muốn truyền một giá trị lớn hơn 2 ^ 32-1.

Nghe có vẻ như nó phụ thuộc vào cách xác định và ghi lại chức năng; Tôi có thể thấy ba khả năng:

  1. Nó có thể tài liệu rõ ràng rằng hàm xử lý byte như một giá trị không dấu, trong trường hợp đó, hàm có thể sẽ làm những gì bạn mong đợi nhưng dường như được thực hiện sai. Đối với trường hợp số nguyên, hàm có thể sẽ khai báo tham số là số nguyên không dấu, nhưng điều đó là không thể đối với trường hợp byte.

  2. Nó có thể chứng minh rằng giá trị cho đối số này phải lớn hơn (hoặc có thể bằng) 0, trong trường hợp đó bạn đang sử dụng sai hàm (truyền tham số ngoài phạm vi), hy vọng nó sẽ làm được nhiều hơn so với thiết kế làm Với một số mức hỗ trợ gỡ lỗi, bạn có thể mong đợi hàm sẽ đưa ra một ngoại lệ hoặc không xác nhận.

  3. Tài liệu có thể không nói gì, trong trường hợp đó, một tham số âm là, một tham số âm và liệu điều đó có ý nghĩa gì hay không phụ thuộc vào chức năng của nó. Nếu điều này là vô nghĩa thì có lẽ chức năng thực sự cần được định nghĩa / ghi lại là (2). Nếu điều này có ý nghĩa theo cách không gây khó chịu (ví dụ: các giá trị không âm được sử dụng để lập chỉ mục thành một mảng và các giá trị âm được sử dụng để lập chỉ mục từ cuối mảng, do đó -1 có nghĩa là phần tử cuối cùng), tài liệu sẽ nói nó là gì có nghĩa là và tôi hy vọng rằng đó không phải là những gì bạn muốn nó làm gì.


Hmmm, tôi nghĩ rằng tôi vừa đăng một câu trả lời dành cho một câu hỏi khác về tính hợp lệ của byte, nhưng tôi cho rằng nó vẫn còn một chút liên quan ở đây nữa ...
Kevin Martin

-1

Nếu bạn có một hàm phải được truyền một byte đã ký, bạn mong đợi nó sẽ làm gì nếu bạn truyền một byte không dấu?

Tại sao bạn không thể sử dụng bất kỳ loại dữ liệu khác?

Thông thường, bạn có thể sử dụng một byte như một byte không dấu với đơn giản hoặc không có bản dịch. Tất cả phụ thuộc vào cách nó được sử dụng. Bạn sẽ cần phải làm rõ những gì bạn muốn làm với nó.


-1

Mặc dù có vẻ khó chịu (đến từ C) rằng Java không bao gồm byte không dấu trong ngôn ngữ nhưng thực sự nó không phải là vấn đề lớn vì một thao tác "b & 0xFF" đơn giản mang lại giá trị không dấu cho byte b (đã ký) trong (hiếm) tình huống mà nó thực sự cần thiết Các bit không thực sự thay đổi - chỉ diễn giải (điều này chỉ quan trọng khi thực hiện ví dụ một số phép toán trên các giá trị).


nhìn người khác trả lời, bạn nghĩ câu trả lời của bạn là tốt nhất / hữu ích? mô tả một chút và thêm nó trong các bình luận
Jubin Patel

8
Nó không hiếm chỉ vì bạn không bắt gặp nó. Hãy thử thực hiện một giao thức và bạn sẽ bắt gặp điều này một triệu lần. Điều khó chịu là phần lớn các trường hợp sử dụng mà tôi gặp phải khi xử lý byte, bạn muốn xử lý các byte không dấu (vì chúng là byte chứ không phải số). Điều điên rồ là bất kỳ hoạt động bitwise nào sẽ chuyển đổi nó thành int, có nghĩa là bất kỳ giá trị "âm" nào sẽ là các giá trị hoàn toàn khác nhau khi được mở rộng. Có, bạn có thể khắc phục bằng cách luôn luôn che giấu, nhưng thật lãng phí thời gian, bộ xử lý và gây ra các lỗi thực sự tối nghĩa nếu bạn quên.
Thor84no

Tôi đồng ý với Thor84no: byte không phải là số và không nên có dấu. Mặt khác, vì chúng không phải là số nên chúng ta thậm chí không nên có / sử dụng toán tử + và -. Chỉ sử dụng các toán tử bitwise hoạt động tốt, mặt khác các toán tử dịch chuyển không hoạt động như người ta muốn, và thực sự java thúc đẩy một byte chuyển sang một int.
dùng1708042

1
@ VlastimilOvčáčík Điều đó thực sự không thể trong trường hợp này, đó là điều kích động. Bạn EITHER lặp lại x & 0xFFở mọi nơi bạn cần hoặc bạn lặp lại một cái gì đó như behaveLikeAnUnsignedByte(x)ở mọi nơi. Điều này là cần thiết cho mỗi nơi bạn sử dụng một giá trị byte hoặc một mảng byte cần được đánh dấu, không có cách nào có thể hiểu được để tránh sự lặp lại này. Bạn không thể viết việc thực hiện một giao thức đọc và ghi các giá trị byte chỉ với một tham chiếu đến một biến byte. Quan điểm đơn giản của bạn có thể giải thích tại sao họ không bao giờ quan tâm để sửa nó mặc dù.
Thor84no

-1

Không có byte không dấu trong Java, nhưng nếu bạn muốn hiển thị một byte, bạn có thể làm,

int myInt = 144;

byte myByte = (byte) myInt;

char myChar = (char) (myByte & 0xFF);

System.out.println("myChar :" + Integer.toHexString(myChar));

Đầu ra:

myChar : 90

Để biết thêm thông tin, vui lòng kiểm tra, Cách hiển thị giá trị hex / byte trong Java .


Không cần phải tự xác định điều này. java.lang.Byte.toUnsignedInt(byte value);tồn tại cho điều này.
Alexander - Phục hồi Monica

-2

Theo giới hạn trong Java, byte không dấu gần như không thể ở định dạng kiểu dữ liệu hiện tại. Bạn có thể tìm một số thư viện khác của ngôn ngữ khác cho những gì bạn đang triển khai và sau đó bạn có thể gọi chúng bằng JNI .


Tôi không nghĩ anh ấy muốn lưu trữ nó như một byte đã ký. Anh ta đang nhận nó dưới dạng một byte đã ký và anh ta muốn lưu trữ nó dưới dạng int, điều này là hoàn toàn hợp lệ. Vấn đề của anh ta là bất cứ nơi nào anh ta nhận được đầu vào từ đó đại diện cho một giá trị từ 0 đến 255 dưới dạng byte, nhưng Java diễn giải như là một twos bổ sung giá trị đã ký vì java không hỗ trợ các byte đã ký.
Zac

-2

Có và không. Ive đã đào xung quanh với vấn đề này. Giống như tôi hiểu điều này:

Thực tế là java đã ký interger -128 đến 127 .. Có thể trình bày một dấu không dấu trong java với:

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

Ví dụ, nếu bạn thêm -12 số đã ký thành không dấu, bạn sẽ nhận được 244. Nhưng bạn có thể sử dụng lại số đó trong chữ ký, nó phải được chuyển trở lại thành đã ký và nó sẽ lại là -12.

Nếu bạn cố gắng thêm 244 vào byte java, bạn sẽ nhận được outOfIndexException.

Chúc mừng ..


3
Không cần phải tự xác định điều này. java.lang.Byte.toUnsignedInt(byte value);tồn tại cho điều này.
Alexander - Phục hồi Monica

-3

Nếu bạn muốn các byte không dấu trong Java, chỉ cần trừ 256 từ số bạn quan tâm. Nó sẽ tạo ra hai phần bù có giá trị âm, là số mong muốn trong các byte không dấu.

Thí dụ:

int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.

Bạn cần sử dụng các bản hack bẩn như vậy khi sử dụng leJOS để lập trình gạch NXT .


Bạn có nhận ra rằng giá trị nhị phân của 255 cũng là 1111 1111, vì vậy không cần có giá trị cơ bản, phải không?
Nick White

@NickWhite, có trong nhị phân. Nhưng java sử dụng phần thưởng của 2 trong đó 255 không phải là 11111111
XapaJIaMnu

Xin lỗi, nhưng điều này chỉ sai. Hãy thử một số thí nghiệm. Giá trị trong speed_unsignedđược ký kết. In nó và xem. (Và - 256không đạt được gì ở đây.)
Stephen C
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.