Chcę przechowywać niektóre dane w tablicach bajtów w Javie. Zasadniczo tylko liczby, które mogą zająć do 2 bajtów na liczbę.
Chciałbym wiedzieć, jak mogę przekonwertować liczbę całkowitą na 2-bajtową tablicę bajtów i odwrotnie. Znalazłem wiele rozwiązań googlujących, ale większość z nich nie wyjaśnia, co dzieje się w kodzie. Jest wiele zmiennych rzeczy, których tak naprawdę nie rozumiem, więc doceniłbym podstawowe wyjaśnienie.
java
types
endianness
Chris
źródło
źródło
Odpowiedzi:
Użyj klas znajdujących się w
java.nio
przestrzeni nazw, w szczególności klasyByteBuffer
. Może wykonać całą pracę za Ciebie.źródło
ByteBuffer
.wrap
iallocate
, nie zwracają one wystąpienia klasy abstrakcyjnejByteBuffer
.Char
,Short
,Int
. Przypuszczam, że mógłbym dopełnić do 4 bajtów i za każdym razem odrzucić czwarty, ale wolałbym tego nie robić.Podczas pakowania bajtów ze znakiem w int, każdy bajt musi być zamaskowany, ponieważ jest rozszerzany do 32 bitów (a nie rozszerzany o zero) ze względu na arytmetyczną regułę promocji (opisaną w JLS, Conversions and Promotions).
Jest z tym związana interesująca łamigłówka opisana w Java Puzzlers („A Big Delight in Every Byte”) autorstwa Joshua Blocha i Neala Gaftera. Podczas porównywania wartości bajtu z wartością int, bajt jest rozszerzany ze znakiem do int, a następnie ta wartość jest porównywana z drugą wartością int
Należy zauważyć, że wszystkie typy liczbowe są podpisane w języku Java, z wyjątkiem typu char będącego 16-bitową liczbą całkowitą bez znaku.
źródło
& 0xFF
są niepotrzebne.& 0xFF
s są konieczne, ponieważ nakazuje JVM konwersję bajtu ze znakiem na liczbę całkowitą z ustawionymi tylko tymi bitami. W przeciwnym razie bajt -1 (0xFF) zamieni się w int -1 (0xFFFFFFFF). Mogę się mylić, a nawet jeśli jestem, to nie boli i wyjaśnia sprawy.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
0xFF (int
), JVM rzucibyte
toint
z rozszerzeniem na 1 lub rozszerzeniem 0 zgodnie z początkowym bitem. W Javie nie ma bajtu bez znaku ,byte
są one zawsze podpisane.ByteBuffer.getInt()
:Reads the next four bytes at this buffer's current position
tylko pierwsze 4 bajty będą przetwarzane, która nie powinna być, co chcesz.Możesz również użyć BigInteger dla bajtów o zmiennej długości. Możesz przekształcić go w długi, int lub krótki, w zależności od potrzeb.
lub do oznaczenia polaryzacji:
Aby odzyskać bajty, wystarczy:
źródło
intValueExact
nieintValue
Podstawowa implementacja wyglądałaby tak:
Aby zrozumieć rzeczy, możesz przeczytać ten artykuł WP: http://en.wikipedia.org/wiki/Endianness
Zostanie wyświetlony powyższy kod źródłowy
34 12 78 56 bc 9a
. Pierwsze 2 bajty (34 12
) reprezentują pierwszą liczbę całkowitą itd. Powyższy kod źródłowy koduje liczby całkowite w formacie little endian.źródło
źródło
Ktoś z wymaganiem, w którym muszą czytać z bitów, powiedzmy, że musisz czytać tylko z 3 bitów, ale potrzebujesz liczby całkowitej ze znakiem, a następnie użyj następującego:
Magiczną liczbę
3
można zastąpić liczbą używanych bitów (nie bajtów) .źródło
Jak często, guawa ma to, czego potrzebujesz.
Aby przejść od tablicy bajtów do int
Ints.fromBytesArray
:, doc tutajAby przejść od int do tablicy bajtów:,
Ints.toByteArray
doc tutajźródło
Myślę, że to najlepszy tryb do przesyłania na int
najpierw zamień bajt na String
następnym krokiem jest zamiana na int
ale bajt jest w wściekłości od -128 do 127 z tego powodu, myślę, że lepiej jest użyć wściekłości od 0 do 255 i wystarczy zrobić to:
źródło