Saya ingin menyimpan beberapa data ke dalam array byte di Jawa. Pada dasarnya hanya angka yang bisa memakan waktu hingga 2 Bytes per angka.
Saya ingin tahu bagaimana saya dapat mengubah integer menjadi array byte sepanjang 2 byte dan sebaliknya. Saya menemukan banyak solusi googling tetapi kebanyakan dari mereka tidak menjelaskan apa yang terjadi dalam kode. Ada banyak hal yang berubah yang saya tidak begitu mengerti jadi saya akan menghargai penjelasan dasarnya.
java
types
endianness
Chris
sumber
sumber
Jawaban:
Gunakan kelas yang ditemukan di
java.nio
namespace, khususnyaByteBuffer
,. Itu bisa melakukan semua pekerjaan untuk Anda.byte[] arr = { 0x00, 0x01 }; ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default short num = wrapped.getShort(); // 1 ByteBuffer dbuf = ByteBuffer.allocate(2); dbuf.putShort(num); byte[] bytes = dbuf.array(); // { 0, 1 }
sumber
ByteBuffer
.wrap
danallocate
, metode tersebut tidak mengembalikan instance dari kelas abstrakByteBuffer
.Char
,Short
,Int
. Saya kira saya bisa memasukkan hingga 4 byte dan membuang 4 byte setiap kali, tapi saya lebih suka tidak.byte[] toByteArray(int value) { return ByteBuffer.allocate(4).putInt(value).array(); } byte[] toByteArray(int value) { return new byte[] { (byte)(value >> 24), (byte)(value >> 16), (byte)(value >> 8), (byte)value }; } int fromByteArray(byte[] bytes) { return ByteBuffer.wrap(bytes).getInt(); } // packing an array of 4 bytes to an int, big endian, minimal parentheses // operator precedence: <<, &, | // when operators of equal precedence (here bitwise OR) appear in the same expression, they are evaluated from left to right int fromByteArray(byte[] bytes) { return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF); } // packing an array of 4 bytes to an int, big endian, clean code int fromByteArray(byte[] bytes) { return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8 ) | ((bytes[3] & 0xFF) << 0 ); }
Saat mengemas byte yang ditandatangani ke dalam int, setiap byte perlu ditutup-tutupi karena itu diperpanjang tanda menjadi 32 bit (bukan diperpanjang nol) karena aturan promosi aritmatika (dijelaskan dalam JLS, Konversi, dan Promosi).
Ada teka-teki menarik terkait hal ini yang dijelaskan dalam Java Puzzlers ("A Big Delight in Every Byte") oleh Joshua Bloch dan Neal Gafter. Ketika membandingkan nilai byte dengan nilai int, byte tanda diperpanjang ke int dan kemudian nilai ini dibandingkan dengan int lainnya.
byte[] bytes = (…) if (bytes[0] == 0xFF) { // dead code, bytes[0] is in the range [-128,127] and thus never equal to 255 }
Perhatikan bahwa semua tipe numerik ditandatangani di Java dengan pengecualian char sebagai tipe integer 16-bit unsigned.
sumber
& 0xFF
itu tidak perlu.& 0xFF
s diperlukan karena memberitahu JVM untuk mengubah byte yang ditandatangani menjadi integer dengan hanya bit-bit yang ditetapkan. Jika tidak, byte -1 (0xFF) akan berubah menjadi int -1 (0xFFFFFFFF). Saya bisa saja salah dan bahkan jika saya salah, itu tidak menyakitkan dan membuat segalanya lebih jelas.byte b = 0; b |= 0x88; System.out.println(Integer.toString(b, 16)); //Output: -78 System.out.println(Integer.toString(b & 0xFF, 16)); //Output: 88
byte
dengan 0xFF (int
), JVM akan mentransmisikanbyte
keint
dengan 1 diperpanjang atau 0 diperpanjang sesuai dengan bit utama terlebih dahulu. Tidak ada byte unsigned di Java,byte
s selalu ditandatangani.ByteBuffer.getInt()
:Reads the next four bytes at this buffer's current position
, hanya 4 byte pertama akan diurai, yang seharusnya tidak apa yang Anda inginkan.Anda juga dapat menggunakan BigInteger untuk byte dengan panjang variabel. Anda dapat mengubahnya menjadi panjang, int atau pendek, mana saja yang sesuai dengan kebutuhan Anda.
new BigInteger(bytes).intValue();
atau untuk menunjukkan polaritas:
new BigInteger(1, bytes).intValue();
Untuk mendapatkan kembali byte:
new BigInteger(bytes).toByteArray()
sumber
intValueExact
, bukanintValue
Implementasi dasar akan menjadi seperti ini:
public class Test { public static void main(String[] args) { int[] input = new int[] { 0x1234, 0x5678, 0x9abc }; byte[] output = new byte[input.length * 2]; for (int i = 0, j = 0; i < input.length; i++, j+=2) { output[j] = (byte)(input[i] & 0xff); output[j+1] = (byte)((input[i] >> 8) & 0xff); } for (int i = 0; i < output.length; i++) System.out.format("%02x\n",output[i]); } }
Untuk memahami banyak hal, Anda dapat membaca artikel WP ini: http://en.wikipedia.org/wiki/Endianness
Kode sumber di atas akan dikeluarkan
34 12 78 56 bc 9a
. 2 byte pertama (34 12
) mewakili integer pertama, dll. Kode sumber di atas mengkodekan integer dalam format little endian.sumber
/** length should be less than 4 (for int) **/ public long byteToInt(byte[] bytes, int length) { int val = 0; if(length>4) throw new RuntimeException("Too big to fit in int"); for (int i = 0; i < length; i++) { val=val<<8; val=val|(bytes[i] & 0xFF); } return val; }
sumber
Seseorang dengan persyaratan di mana mereka harus membaca dari bit, katakanlah Anda harus membaca hanya dari 3 bit tetapi Anda memerlukan integer yang ditandatangani kemudian gunakan yang berikut:
data is of type: java.util.BitSet new BigInteger(data.toByteArray).intValue() << 32 - 3 >> 32 - 3
Angka ajaib
3
dapat diganti dengan jumlah bit (bukan byte) yang Anda gunakan.sumber
Seringkali, jambu biji memiliki apa yang Anda butuhkan.
Untuk beralih dari array byte ke int
Ints.fromBytesArray
:, doc di siniUntuk beralih dari int ke byte array
Ints.toByteArray
:, doc di sinisumber
saya pikir ini adalah mode terbaik untuk dilemparkan ke int
public int ByteToint(Byte B){ String comb; int out=0; comb=B+""; salida= Integer.parseInt(comb); out=out+128; return out; }
byte comvert pertama ke String
comb=B+"";
langkah selanjutnya adalah comvert ke int
tetapi byte berada dalam kemarahan -128 hingga 127 untuk alasan ini, saya pikir lebih baik menggunakan rage 0 hingga 255 dan Anda hanya perlu melakukan ini:
out=out+256;
sumber