Bisakah kita membuat byte yang tidak ditandatangani di Jawa

185

Saya mencoba untuk mengkonversi byte yang ditandatangani di unsigned. Masalahnya adalah data yang saya terima tidak ditandatangani dan Java tidak mendukung byte yang tidak ditandatangani, jadi ketika membaca data itu memperlakukannya sebagai ditandatangani.

Saya mencoba untuk mengubahnya dengan solusi berikut yang saya dapatkan dari Stack Overflow.

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

Tetapi ketika sekali lagi itu dikonversi dalam byte, saya mendapatkan data yang ditandatangani yang sama. Saya mencoba menggunakan data ini sebagai parameter ke fungsi Java yang hanya menerima byte sebagai parameter, jadi saya tidak bisa menggunakan tipe data lainnya. Bagaimana saya bisa memperbaiki masalah ini?

dln
sumber
2
Guava: UnsignedBytes.toint (nilai byte)
jacktrades
20
java.lang.Byte.toUnsignedInt (nilai byte);
themarketka

Jawaban:

107

Saya tidak yakin saya mengerti pertanyaan Anda.

Saya baru saja mencoba ini dan untuk byte -12 (nilai yang ditandatangani) mengembalikan integer 244 (setara dengan nilai byte yang tidak ditandatangani tetapi diketik sebagai int):

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

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

Apa itu yang ingin kamu lakukan?

Java tidak mengizinkan untuk menyatakan 244 sebagai bytenilai, seperti yang akan C. Untuk mengekspresikan bilangan bulat positif di atas Byte.MAX_VALUE(127) Anda harus menggunakan tipe bilangan bulat lainnya, seperti short, intatau long.

Guillaume
sumber
1
byte b = (byte)unsignedToBytes((byte) -12); sekarang coba cetak b
Jigar Joshi
101
Mengapa Anda menerima ini sebagai jawaban yang benar? Semua yang dilakukannya persis sama dengan metode yang Anda sebutkan dalam pertanyaan Anda - konversikan satu byte ke integer yang tidak ditandatangani.
Adamski
1
Sangat penting untuk kadang-kadang menandatangani nilai, kadang tidak ditandatangani, jadi mungkin inilah alasan dia menerima jawaban ini. (byte) (b & 0xff) tidak memiliki arti, tetapi (byte) (Math.min ((b & 0xff) * 2, 255)) memiliki arti, misalnya dalam grafik komputer itu hanya akan membuat Pixed diwakili oleh byte dua kali lebih cerah. :-)
iirekm
3
Itu juga bisa disebut byteToUnigned
Hernán Eche
195

Fakta bahwa primitif ditandatangani di Jawa tidak relevan dengan bagaimana mereka diwakili dalam memori / transit - byte hanya 8 bit dan apakah Anda mengartikannya sebagai rentang yang ditandatangani atau tidak, itu terserah Anda. Tidak ada bendera ajaib untuk mengatakan "ini ditandatangani" atau "ini tidak ditandatangani".

Ketika primitif ditandatangani, kompiler Java akan mencegah Anda menetapkan nilai lebih tinggi dari +127 ke byte (atau lebih rendah dari -128). Namun, tidak ada yang menghentikan Anda untuk menurunkan int (atau pendek) untuk mencapai hal ini:

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"
}
Adamski
sumber
5
Bagi banyak operasi itu tidak membuat perbedaan, namun untuk beberapa operasi itu tidak. Anda bisa menggunakan byte sebagai unsigned, atau menggunakan char yang unsigned.
Peter Lawrey
62
Mengakses array dengan angka yang berpotensi negatif tidak tidak relevan.
Stefan
3
@Stefan - Maksud saya tidak relevan dalam konteks bagaimana mereka diwakili di kawat.
Adamski
6
Yang agak tidak relevan dengan pertanyaan itu. Karena ia menyebutkan bahwa ia perlu meneruskannya ke fungsi yang hanya menerima parameter byte, tidak masalah cuaca, kami menafsirkannya sebagai representasi byte unicorn. Java akan selalu memperlakukannya sebagai angka yang ditandatangani, yang bisa menjadi masalah untuk contoh ketika fungsi ini menggunakan parameter sebagai indeks. Namun untuk bersikap adil saya juga menurunkan 2 jawaban teratas lainnya, karena mereka juga tidak menjawab pertanyaan.
Stefan
2
@Stefan +1 untuk Anda. Sangat relevan jika Anda menggunakan byte untuk mengakses array 256 elemen. Itu contoh yang bagus untuk menunjukkan mengapa semua orang harus mulai belajar C dan C ++ sebelum pindah ke Jawa atau C #
Gianluca Ghettini
46

Panduan lengkap untuk bekerja dengan byte yang tidak ditandatangani di Jawa:

Byte tidak bertanda di Java

(Sumber untuk jawaban ini.)


Bahasa Jawa tidak menyediakan apa pun seperti unsignedkata kunci. A bytesesuai dengan spesifikasi bahasa mewakili nilai antara −128 - 127. Misalnya, jika bytedilemparkan ke intJava akan menafsirkan bit pertama sebagai tanda dan menggunakan ekstensi tanda .

Yang sedang berkata, tidak ada yang mencegah Anda dari melihat bytehanya sebagai 8 bit dan menafsirkan bit-bit itu sebagai nilai antara 0 dan 255. Perlu diingat bahwa tidak ada yang dapat Anda lakukan untuk memaksa interpretasi Anda pada metode orang lain. Jika suatu metode menerima a byte, maka metode itu menerima nilai antara −128 dan 127 kecuali secara eksplisit dinyatakan sebaliknya.

Berikut adalah beberapa konversi / manipulasi yang berguna untuk kenyamanan Anda:

Konversi ke / dari 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

(Atau, jika Anda menggunakan Java 8+, gunakan Byte.toUnsignedInt.)

Parsing / pemformatan

Cara terbaik adalah dengan menggunakan konversi di atas:

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

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

Aritmatika

Representasi 2-pelengkap "hanya berfungsi" untuk penambahan, pengurangan, dan penggandaan:

// 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

Divisi membutuhkan konversi manual dari operan:

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
aioobe
sumber
1
'char' tidak mewakili angka.
logoff
26
Singkatnya: Anda salah .
aioobe
36

Tidak ada byte primitif yang tidak ditandatangani di Jawa. Hal yang biasa adalah melemparkannya ke tipe yang lebih besar:

int anUnsignedByte = (int) aSignedByte & 0xff;
Peter Knego
sumber
Apakah para pemain perlu int?
nich
Ini bisa menjadi pemeran tersirat, tetapi ada juga pemeran. Dan pemeran itu menandatangani ekstensi. Dan itu masalah. Jika Anda melakukan pemeran eksplisit, Anda setidaknya dapat melihat ini terjadi.
foo
4

Catatan tambahan, jika Anda ingin mencetaknya, Anda bisa mengatakannya

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
Kyle Kinkade
sumber
6
mengapa begitu rumit? println(b & 0xff)sudah cukup
phuclv
0

Jika Anda mencari sesuatu seperti ini.

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

Adamski memberikan jawaban terbaik, tetapi itu tidak cukup lengkap, jadi bacalah jawabannya, karena menjelaskan detail saya tidak.

Jika Anda memiliki fungsi sistem yang memerlukan byte yang tidak ditandatangani untuk diteruskan, Anda dapat melewati byte yang ditandatangani karena akan secara otomatis memperlakukannya sebagai byte yang tidak ditandatangani.

Jadi, jika fungsi sistem memerlukan empat byte, misalnya, 192 168 0 1 sebagai byte yang tidak ditandatangani, Anda dapat meneruskan -64 -88 0 1, dan fungsi tersebut masih akan berfungsi, karena tindakan meneruskannya ke fungsi akan menghapus tanda tangani mereka .

Namun Anda tidak mungkin memiliki masalah ini karena fungsi sistem tersembunyi di belakang kelas untuk kompatibilitas lintas platform, meskipun beberapa metode baca java.io mengembalikan byte yang tidak ditandai sebagai int.

Jika Anda ingin melihat ini berfungsi, cobalah menulis byte yang ditandatangani ke file dan membacanya kembali sebagai byte yang tidak ditandatangani.

Ewe Loon
sumber
1
Tidak ada byte yang ditandatangani atau tidak ditandatangani.
Vlastimil Ovčáčík
Bagaimana tepatnya Anda menulis dan membaca byte dalam contoh Anda?
Vlastimil Ovčáčík
0

Anda juga bisa:

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

Penjelasan:

Katakanlah a = (byte) 133;

Dalam memori itu disimpan sebagai: "1000 0101" (hex 0x85)

Jadi perwakilannya menerjemahkan unsigned = 133, bertanda = -123 (sebagai pelengkap 2)

a << 24

Ketika shift kiri dilakukan 24 bit ke kiri, hasilnya sekarang adalah integer 4 byte yang direpresentasikan sebagai:

"10000101 00000000 00000000 00000000" (atau "0x85000000" dalam hex)

maka kita miliki

(a << 24) >>> 24

dan itu bergeser lagi pada 24 bit yang tepat tetapi mengisi dengan nol terkemuka. Jadi hasilnya untuk:

"00000000 00000000 00000000 10000101" (atau "0x00000085" dalam hex)

dan itu adalah representasi yang tidak ditandatangani yang sama dengan 133.

Jika Anda mencoba melakukan cast a = (int) a; maka apa yang akan terjadi adalah ia mempertahankan representasi byte 2 dari byte dan menyimpannya sebagai int juga sebagai pelengkap 2's:

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

Dan itu diterjemahkan sebagai: -123

mark_infinite
sumber
2
Pada 2019, ini tidak perlu. Gunakan saja java.lang.Byte.toUnsignedInt(byte value). Dan jika Anda belum menggunakan Java 8, tingkatkan ASAP. Java 7 dan sebelumnya adalah akhir dari kehidupan.
Stephen C
0

Saya mencoba menggunakan data ini sebagai parameter ke fungsi Java yang hanya menerima byte sebagai parameter

Ini tidak jauh berbeda dari fungsi yang menerima bilangan bulat yang ingin Anda berikan nilai lebih besar dari 2 ^ 32-1.

Kedengarannya seperti itu tergantung pada bagaimana fungsi didefinisikan dan didokumentasikan; Saya dapat melihat tiga kemungkinan:

  1. Mungkin secara eksplisit mendokumentasikan bahwa fungsi memperlakukan byte sebagai nilai yang tidak ditandatangani, dalam hal ini fungsi tersebut mungkin harus melakukan apa yang Anda harapkan tetapi tampaknya salah diimplementasikan. Untuk case integer, fungsi mungkin akan mendeklarasikan parameter sebagai integer yang tidak ditandatangani, tetapi itu tidak mungkin untuk case byte.

  2. Ini mungkin mendokumentasikan bahwa nilai untuk argumen ini harus lebih besar dari (atau mungkin sama dengan) nol, dalam hal ini Anda menyalahgunakan fungsi (melewati parameter di luar kisaran), berharap untuk melakukan lebih dari yang dirancang untuk melakukan. Dengan beberapa tingkat dukungan debug Anda mungkin mengharapkan fungsi untuk melemparkan pengecualian atau gagal pernyataan.

  3. Dokumentasi mungkin tidak mengatakan apa-apa, dalam hal ini parameter negatif, yah, parameter negatif dan apakah itu memiliki makna tergantung pada apa fungsi tidak. Jika ini tidak berarti maka mungkin fungsi tersebut harus benar-benar didefinisikan / didokumentasikan sebagai (2). Jika ini bermakna dalam cara yang tidak jelas (misalnya nilai-nilai non-negatif digunakan untuk mengindeks ke dalam array, dan nilai-nilai negatif digunakan untuk mengindeks kembali dari akhir array sehingga -1 berarti elemen terakhir) dokumentasi harus mengatakan apa itu berarti dan saya berharap itu bukan apa yang Anda ingin lakukan.

Kevin Martin
sumber
Hmmm, saya rasa saya baru saja memposting balasan yang ditujukan untuk pertanyaan lain tentang penandatanganan byte, tapi saya kira itu masih sedikit relevan di sini juga ...
Kevin Martin
-1

Jika Anda memiliki fungsi yang harus melewati byte yang ditandatangani, apa yang Anda harapkan untuk dilakukan jika Anda melewati byte yang tidak ditandatangani?

Mengapa Anda tidak bisa menggunakan tipe data lainnya?

Tanpa Anda dapat menggunakan byte sebagai byte yang tidak ditandatangani dengan terjemahan sederhana atau tanpa terjemahan. Itu semua tergantung pada bagaimana itu digunakan. Anda perlu mengklarifikasi apa yang ingin Anda lakukan dengannya.

Peter Lawrey
sumber
-1

Meskipun mungkin tampak menjengkelkan (berasal dari C) bahwa Java tidak memasukkan byte yang tidak ditandatangani dalam bahasa itu sebenarnya bukan masalah besar karena operasi "b & 0xFF" yang sederhana menghasilkan nilai yang tidak ditandatangani untuk (ditandatangani) byte b dalam (jarang) situasi yang sebenarnya dibutuhkan. Bit tidak benar-benar berubah - hanya interpretasi (yang penting hanya ketika melakukan misalnya beberapa operasi matematika pada nilai-nilai).

Bob
sumber
lihat jawaban orang lain, menurut Anda jawaban Anda yang terbaik / bermanfaat? jelaskan sedikit dan tambahkan dalam komentar
Jubin Patel
8
Ini tidak jarang hanya karena Anda belum menemukannya. Cobalah menerapkan protokol dan Anda akan menemukan ini sejuta kali. Yang mengganggu adalah bahwa sebagian besar kasus penggunaan yang saya temui berurusan dengan byte, Anda ingin berurusan dengan byte yang tidak ditandatangani (karena mereka byte, bukan angka). Yang gila adalah SETIAP operasi bitwise akan mengubahnya menjadi int, yang berarti nilai "negatif" akan menjadi nilai yang sama sekali berbeda ketika diperpanjang. Ya, Anda bisa menyiasatinya dengan selalu menutupi, tetapi itu buang-buang waktu, prosesor, dan menyebabkan bug yang benar-benar tidak jelas jika Anda lupa.
Thor84no
Saya setuju dengan Thor84no: byte bukan angka, dan seharusnya tidak memiliki tanda. Di sisi lain, karena mereka bukan angka kita bahkan tidak boleh memiliki / menggunakan operator + dan -. Menggunakan hanya operator bitwise bekerja dengan baik, di sisi lain operator shift tidak berfungsi seperti yang diinginkan, dan memang java mempromosikan byte yang digeser ke int.
user1708042
1
@ VlastimilOvčáčík Itu benar-benar tidak mungkin dalam hal ini, itu adalah hal yang membingungkan. Anda BAIK mengulangi di x & 0xFFmana-mana Anda membutuhkannya atau Anda mengulangi sesuatu seperti di behaveLikeAnUnsignedByte(x)mana - mana. Ini diperlukan untuk setiap tempat Anda menggunakan nilai byte atau array byte yang perlu ditandatangani, tidak ada cara yang mungkin untuk menghindari pengulangan ini. Anda tidak dapat menulis implementasi protokol yang membaca dan menulis nilai byte dengan hanya satu referensi ke variabel byte. Pandangan sederhana Anda mungkin menjelaskan mengapa mereka tidak pernah peduli untuk memperbaikinya.
Thor84no
-1

Tidak ada byte yang tidak ditandatangani di Jawa, tetapi jika Anda ingin menampilkan byte, Anda dapat melakukannya,

int myInt = 144;

byte myByte = (byte) myInt;

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

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

Keluaran:

myChar : 90

Untuk informasi lebih lanjut, silakan periksa, Cara menampilkan nilai hex / byte di Jawa .

Jyo the Whiff
sumber
Tidak perlu mendefinisikan ini sendiri. java.lang.Byte.toUnsignedInt(byte value);ada untuk ini.
Alexander - Reinstate Monica
-2

Sesuai keterbatasan di Jawa, byte yang tidak ditandatangani hampir tidak mungkin dalam format tipe data saat ini. Anda dapat pergi ke beberapa perpustakaan lain dari bahasa lain untuk apa yang Anda implementasikan dan kemudian Anda dapat memanggil mereka menggunakan JNI .

Pritesh Jain
sumber
Saya tidak berpikir dia ingin menyimpannya sebagai byte yang ditandatangani. Dia menerimanya sebagai byte yang ditandatangani, dan dia ingin menyimpannya sebagai int, yang sangat valid. Masalahnya adalah bahwa di mana pun dia mendapatkan input mewakili nilai antara 0 dan 255 sebagai byte, tetapi Java mengartikannya sebagai dua-dua nilai pelengkap yang ditandatangani karena java tidak mendukung byte yang ditandatangani.
Zac
-2

Iya dan tidak. Saya sudah menggali sekitar dengan masalah ini. Seperti saya mengerti ini:

Faktanya adalah bahwa java telah menandatangani interger -128 ke 127 .. Dimungkinkan untuk menyajikan unsigned di java dengan:

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

Jika Anda misalnya menambahkan -12 nomor yang ditandatangani menjadi unsigned Anda mendapatkan 244. Tetapi Anda dapat menggunakan nomor itu lagi di masuk, itu harus digeser kembali ke yang ditandatangani dan itu akan menjadi lagi -12.

Jika Anda mencoba menambahkan 244 ke byte java, Anda akan keluar dariIndexException.

Bersulang..

Sindri Þór
sumber
3
Tidak perlu mendefinisikan ini sendiri. java.lang.Byte.toUnsignedInt(byte value);ada untuk ini.
Alexander - Reinstate Monica
-3

Jika Anda ingin byte yang tidak ditandatangani di Jawa, cukup kurangi 256 dari angka yang Anda minati. Ini akan menghasilkan komplemen dua dengan nilai negatif, yang merupakan angka yang diinginkan dalam byte yang tidak ditandatangani.

Contoh:

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.

Anda perlu menggunakan peretasan yang kotor saat menggunakan leJOS untuk memprogram bata NXT .

XapaJIaMnu
sumber
Anda menyadari bahwa nilai biner dari 255 juga 1111 1111, jadi tidak diperlukan substraksi, kan?
Nick White
@NickWhite, ya dalam biner. Tapi java menggunakan komplemen 2's di mana 255 bukan 11111111
XapaJIaMnu
Maaf, tapi ini salah. Coba beberapa percobaan. Nilai masuk speed_unsignedsudah ditandatangani. Cetak dan lihat. (Dan - 256tidak ada yang berhasil di sini.)
Stephen C