Come convertire Int in byte senza segno e ritorno


92

Devo convertire un numero in un byte senza segno. Il numero è sempre minore o uguale a 255, quindi si adatterà a un byte.

Devo anche riconvertire quel byte in quel numero. Come lo farei in Java? Ho provato diversi modi e nessuno funziona. Ecco cosa sto cercando di fare ora:

int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);

e ora per riconvertire quel byte nel numero:

Byte test = new Byte(binaryByte);
int msgSize = test.intValue();

Chiaramente, questo non funziona. Per qualche motivo, converte sempre il numero in 65. Eventuali suggerimenti?


Ho anche provato questo metodo: crazysquirrel.com/computing/java/basics/… - non funziona.
darksky

Risposte:


200

Un byte è sempre firmato in Java. Puoi ottenere il suo valore senza segno binario e aggiungendolo con 0xFF, però:

int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234

Ho ancora 65 anni ... Perché?
darksky

1
Sta memorizzando il numero che vuoi nel byte. Java lo considera semplicemente un numero firmato piuttosto che uno non firmato. Ma ogni bit è uguale a se fosse un numero senza segno. La conversione della stringa in byte è un'altra domanda non correlata. Pubblicalo separatamente, in una nuova domanda.
JB Nizet

1
usa getInt per recuperare il tuo int e trasformare l'int come un byte. Un int è un int. Da dove viene non importa.
JB Nizet

18
Perché bit a bit e con 0xFFrisultato in un numero intero senza segno? Qualche spiegazione sarebbe davvero utile.
user462455

2
Java 8 utilizza lo stesso metodo: public static int toUnsignedInt (byte x) {return ((int) x) & 0xff; }
Daniel De León

55

Java 8 prevede la Byte.toUnsignedIntconversione bytein inttramite conversione non firmata. Nel JDK di Oracle questo è implementato semplicemente return ((int) x) & 0xff;perché HotSpot comprende già come ottimizzare questo pattern, ma potrebbe essere intrinseco su altre VM. Ancora più importante, non è necessaria alcuna conoscenza preliminare per capire cosa fa una chiamata a toUnsignedInt(foo).

In totale, Java 8 fornisce metodi per convertire bytee shortin non firmato inte long, e intin non firmato long. Un metodo per convertire bytein unsigned è shortstato deliberatamente omesso perché la JVM fornisce solo dati aritmetici inte longcomunque.

Per convertire un int di nuovo a un byte, basta usare un cast: (byte)someInt. La conversione primitiva di restringimento risultante scarterà tutti tranne gli ultimi 8 bit.


7

Se hai solo bisogno di convertire un valore atteso a 8 bit da un int con segno a un valore senza segno, puoi usare un semplice spostamento di bit:

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

Se usi qualcosa di diverso dal inttipo di base, dovrai ovviamente regolare la quantità di spostamento: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Inoltre, tieni presente che non puoi usare il bytetipo, così facendo si otterrà un valore con segno come menzionato da altri rispondenti. Il tipo primitivo più piccolo che potresti usare per rappresentare un valore senza segno a 8 bit sarebbe un short.


3

La Integer.toString(size)chiamata viene convertita nella rappresentazione char del tuo intero, cioè il char '5'. La rappresentazione ASCII di quel carattere è il valore 65.

È necessario prima analizzare la stringa in un valore intero, ad esempio utilizzando Integer.parseInt , per recuperare il valore int originale.

In Stringconclusione , per una conversione con segno / senza segno, è meglio lasciare fuori dall'immagine e utilizzare la manipolazione dei bit come suggerisce @JB.


Quindi così? (Ancora 65 qui)String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
darksky

@Nayefc, ho aggiornato la mia risposta proprio mentre scrivevi il tuo commento :-)
Péter Török

Va bene grazie! Per qualche ragione, tuttavia, stampa ANCORA 65. Cosa significa questo? Se mostra solo 65, cosa viene effettivamente memorizzato nel byte, non lo capisco. Controlla anche la mia domanda, l'ho modificata e ho aggiunto una sezione sulla conversione delle stringhe :)
darksky

@Nayefc, ancora una volta, String.getBytes()restituisce i valori ASCII dei caratteri contenuti nel testo, non i valori numerici delle cifre. Devi analizzare la stringa in un valore numerico, come ho suggerito sopra.
Péter Török

1
@Nayefc, quindi questa è in realtà una domanda completamente diversa. E AFAIS dovrebbe funzionare. Crea una nuova domanda, includendo l'input e l'output effettivi della conversione e il codice completo per riprodurre il caso.
Péter Török

3

La soluzione funziona bene (grazie!), Ma se vuoi evitare il casting e lasciare il lavoro di basso livello al JDK, puoi usare un DataOutputStream per scrivere i tuoi int e un DataInputStream per leggerli di nuovo. Sono trattati automaticamente come non firmati byte quindi:

Per convertire gli int in byte binari;

ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int val = 250;
dos.write(byteVal);
...
dos.flush();

Leggendoli di nuovo in:

// 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. utile per la gestione di formati di dati binari (es. formati di messaggi flat, ecc.)


3

Tranne che chartutti gli altri tipi di dati numerici in Java sono firmati.

Come detto in una risposta precedente, puoi ottenere il valore senza segno eseguendo andun'operazione con 0xFF. In questa risposta spiegherò come accade.

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

Se la tua macchina è a 32 bit, il inttipo di dati necessita di 32 bit per memorizzare i valori. bytenecessita solo di 8 bit.

La intvariabile iè rappresentata nella memoria come segue (come numero intero a 32 bit).

0{24}11101010

Quindi la bytevariabile bè rappresentata come:

11101010

Poiché bytes sono senza segno, questo valore rappresenta-22 . (Cerca il complemento di 2 per saperne di più su come rappresentare numeri interi negativi in ​​memoria)

Quindi se cast è a intsarà ancora -22perché il casting preserva il segno di un numero.

1{24}11101010

Il 32-bitvalore cast di beseguire l' andoperazione con 0xFF.

 1{24}11101010 & 0{24}11111111
=0{24}11101010

Quindi ottieni 234come risposta.


1

Gestione di byte e interi senza segno con 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

1

Anche se è troppo tardi, vorrei dare il mio contributo in merito in quanto potrebbe chiarire perché la soluzione fornita da JB Nizet funziona. Mi sono imbattuto in questo piccolo problema lavorando su un parser di byte e sulla conversione di stringhe da solo. Quando si copia da un tipo integrale di dimensioni maggiori a un tipo integrale di dimensioni inferiori, poiché questo documento java dice che questo accade:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 Una conversione restrittiva di un intero con segno in un tipo integrale T scarta semplicemente tutto tranne il n più basso bit dell'ordine, dove n è il numero di bit utilizzati per rappresentare il tipo T. Oltre a una possibile perdita di informazioni sull'ampiezza del valore numerico, ciò può far sì che il segno del valore risultante differisca dal segno del valore di input .

Puoi essere sicuro che un byte è un tipo integrale poiché questo documento java dice https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html byte: il tipo di dati byte è un due con segno a 8 bit complemento intero.

Quindi, nel caso di cast di un intero (32 bit) in un byte (8 bit), copi semplicemente l'ultimo (8 bit meno significativi) di quell'intero nella variabile byte specificata.

int a = 128;
byte b = (byte)a; // Last 8 bits gets copied
System.out.println(b);  // -128

La seconda parte della storia riguarda il modo in cui gli operatori unari e binari Java promuovono gli operandi. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 La conversione primitiva di ampliamento (§5.1.2) viene applicata per convertire uno o entrambi gli operandi come specificato secondo le seguenti regole:

Se uno degli operandi è di tipo double, l'altro viene convertito in double.

Altrimenti, se uno degli operandi è di tipo float, l'altro viene convertito in float.

Altrimenti, se uno degli operandi è di tipo long, l'altro viene convertito in long.

Altrimenti, entrambi gli operandi vengono convertiti nel tipo int.

Stai tranquillo, se stai lavorando con il tipo integrale int e / o inferiore verrà promosso a 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

Mi sono grattato la testa anche su questo :). C'è una buona risposta per questo qui da rgettman. Operatori bit per bit in java solo per interi e lunghi?


0

Se vuoi usare le classi wrapper primitive, funzionerà, ma tutti i tipi java sono firmati per impostazione predefinita.

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));
}

-1

in 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);
    }
}

risultato: 254

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.