Muszę przekonwertować liczbę na bajt bez znaku. Liczba jest zawsze mniejsza lub równa 255, więc zmieści się w jednym bajcie.
Muszę również przekonwertować ten bajt z powrotem na tę liczbę. Jak miałbym to zrobić w Javie? Wypróbowałem kilka sposobów i żaden nie działa. Oto, co próbuję teraz zrobić:
int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);
a teraz przekonwertować ten bajt z powrotem na liczbę:
Byte test = new Byte(binaryByte);
int msgSize = test.intValue();
Oczywiście to nie działa. Z jakiegoś powodu zawsze konwertuje liczbę na 65
. Jakieś sugestie?
Odpowiedzi:
Bajt jest zawsze podpisywany w Javie. Możesz jednak uzyskać jego wartość bez znaku, łącząc ją binarnie z 0xFF:
int i = 234; byte b = (byte) i; System.out.println(b); // -22 int i2 = b & 0xFF; System.out.println(i2); // 234
źródło
0xFF
wynikiem w postaci liczby całkowitej bez znaku? Pewne wyjaśnienie byłoby naprawdę pomocne.Java 8 zapewnia
Byte.toUnsignedInt
konwersjębyte
naint
bez znaku. W JDK Oracle jest to po prostu zaimplementowane,return ((int) x) & 0xff;
ponieważ HotSpot już rozumie, jak zoptymalizować ten wzorzec, ale może być wbudowany w inne maszyny wirtualne. Co ważniejsze, nie jest potrzebna żadna wcześniejsza wiedza, aby zrozumieć, do czego służy wezwanietoUnsignedInt(foo)
.W sumie, Java 8 dostarcza metod do konwersji
byte
ishort
do unsignedint
ilong
, aint
do niepodpisanylong
. Metoda konwersjibyte
na bez znakushort
została celowo pominięta, ponieważ JVM zapewnia tylko działania arytmetyczneint
ilong
tak.Aby przekonwertować int powrotem do bajta, wystarczy użyć obsady:
(byte)someInt
. Wynikająca z tego zawężona konwersja pierwotna spowoduje odrzucenie wszystkich oprócz ostatnich 8 bitów.źródło
Jeśli potrzebujesz tylko przekonwertować oczekiwaną 8-bitową wartość z wartości int ze znakiem na wartość bez znaku, możesz użyć prostego przesuwania bitów:
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
Jeśli używasz czegoś innego niż
int
typ podstawowy, musisz oczywiście dostosować wielkość przesunięcia: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.htmlPamiętaj też, że nie możesz używać
byte
typu, ponieważ spowoduje to podpisanie wartości, o której wspominali inni respondenci. Najmniejszym typem pierwotnym, którego można użyć do reprezentowania 8-bitowej wartości bez znaku, byłby ashort
.źródło
W
Integer.toString(size)
nawróceni wezwanie do reprezentowania char swojej całkowitej, czyli char'5'
. Reprezentacją ASCII tego znaku jest wartość 65.Najpierw musisz przeanalizować ciąg z powrotem do wartości całkowitej, np. Używając
Integer.parseInt
, aby odzyskać oryginalną wartość int.String
Podsumowując, w przypadku konwersji ze znakiem / bez znaku najlepiej jest pominąć obraz i użyć manipulacji bitami, jak sugeruje @JB.źródło
String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
String.getBytes()
zwraca wartości ASCII znaków zawartych w tekście, a nie wartości liczbowe cyfr. Musisz przeanalizować ciąg na wartość liczbową, jak zasugerowałem powyżej.Rozwiązanie działa dobrze (dzięki!), Ale jeśli chcesz uniknąć rzutowania i pozostawić pracę niskiego poziomu JDK, możesz użyć DataOutputStream, aby zapisać swoje int i DataInputStream, aby je odczytać. Są one automatycznie traktowane jako niepodpisane bajtów to:
Do konwersji int na bajty binarne;
ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); int val = 250; dos.write(byteVal); ... dos.flush();
Czytanie ich z powrotem w:
// 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. przydatne do obsługi binarnych formatów danych (np. płaskie formaty wiadomości itp.)
źródło
Z wyjątkiem
char
wszystkich innych liczbowych typów danych w Javie są podpisane.Jak wspomniano w poprzedniej odpowiedzi, wartość bez znaku można uzyskać, wykonując
and
operację z0xFF
. W tej odpowiedzi wyjaśnię, jak to się dzieje.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
Jeśli twój komputer jest 32-bitowy,
int
typ danych wymaga 32-bitów do przechowywania wartości.byte
potrzebuje tylko 8-bitów.int
Zmiennai
jest przedstawiony w pamięci w sposób następujący (w postaci 32-bitowej liczby całkowitej).0{24}11101010
Następnie
byte
zmiennab
jest reprezentowana jako:11101010
Ponieważ
byte
s są bez znaku, ta wartość reprezentuje-22
. (Wyszukaj uzupełnienie do 2, aby dowiedzieć się więcej o tym, jak reprezentować ujemne liczby całkowite w pamięci)Wtedy, jeśli rzucisz,
int
to nadal będzie,-22
ponieważ rzucanie zachowuje znak liczby.1{24}11101010
Rzutowana
32-bit
wartośćb
wykonaniaand
operacji z0xFF
.1{24}11101010 & 0{24}11111111 =0{24}11101010
Wtedy otrzymasz
234
odpowiedź.źródło
Chociaż jest już za późno, chciałbym wnieść swój wkład w tę sprawę, ponieważ może to wyjaśnić, dlaczego rozwiązanie podane przez JB Nizet działa. Natknąłem się na ten mały problem podczas pracy z parserem bajtów i samodzielną konwersją ciągów. Podczas kopiowania z typu całkowitego o większym rozmiarze do typu całkowitego o mniejszym rozmiarze, zgodnie z tym, co mówi ten dokument java:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 Zwężająca się konwersja liczby całkowitej ze znakiem na typ całkowy T po prostu odrzuca wszystko oprócz n najniższego bitów porządkowych, gdzie n to liczba bitów użytych do reprezentacji typu T. Oprócz możliwej utraty informacji o wielkości wartości liczbowej może to spowodować, że znak wartości wynikowej będzie różny od znaku wartości wejściowej .
Możesz być pewien, że bajt jest typem całkowitym, zgodnie z tym dokumentem java https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html bajt: Typ danych bajtowych to 8-bitowe podpisane dwa uzupełnienie liczby całkowitej.
Tak więc w przypadku rzutowania liczby całkowitej (32 bity) na bajt (8 bitów) wystarczy skopiować ostatnie (najmniej znaczące 8 bitów) tej liczby całkowitej do podanej zmiennej bajtowej.
int a = 128; byte b = (byte)a; // Last 8 bits gets copied System.out.println(b); // -128
Druga część historii dotyczy sposobu, w jaki operandy jednoargumentowe i binarne Java promują operandy. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 Konwersja prymitywów poszerzających (§5.1.2) jest stosowana do konwersji jednego lub obu operandów zgodnie z opisem według następujących zasad:
Jeśli jeden z operandów jest typu double, drugi jest konwertowany na double.
W przeciwnym razie, jeśli jeden z operandów jest typu float, drugi jest konwertowany na float.
W przeciwnym razie, jeśli jeden z operandów jest typu long, drugi jest konwertowany na long.
W przeciwnym razie oba operandy są konwertowane na typ int.
Zapewniamy, że jeśli pracujesz z typem całkowitym int i / lub niższym, zostanie on podwyższony do typu 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
Ja też podrapałem się po głowie :). Rgettman ma na to dobrą odpowiedź. Operatory bitowe w Javie tylko dla liczb całkowitych i długich?
źródło
Jeśli chcesz użyć prymitywnych klas opakowania, zadziała to, ale wszystkie typy java są domyślnie podpisane.
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)); }
źródło
Obsługa bajtów i liczb całkowitych bez znaku z 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
źródło
w 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); } }
wynik: 254
źródło