2010-05-19 16 views
6

sto cercando di rappresentare il numero di porta 9876 (o 0x2694 in esadecimale) in un array di due byte:Rappresentazione di un numero in un array di byte (programmazione Java)

class foo { 
    public static void main (String args[]) { 
    byte[] sendData = new byte[1]; 

    sendData[0] = 0x26; 
    sendData[1] = 0x94; 
    } 
} 

ma ottengo un avvertimento sui possibili perdita di precisione:

Come si può rappresentare il numero 9876 in un array a due byte senza perdere la precisione?

NOTA: Ho selezionato il codice da @ Björn come risposta corretta, ma anche il codice di @glowcoder funziona correttamente. È solo un approccio diverso allo stesso problema. Grazie a tutti!

+4

noti che appiattimento strutture di dati per l'invio oltre il filo di solito è fatto con un DataOutputStream (o la sua sottoclasse ObjectOutputStream) in Giava. Non c'è bisogno di reinventare il bit-stop ogni volta :-) – meriton

+1

@meriton: e meglio ancora, usa 'java.nio.ByteBuffer' che può fare tutto questo, non avere a che fare con IOException e controllare anche l'endianness. –

risposta

1

la mia prima risposta sarebbe bitshifting, ma su un secondo pensiero penso utilizzando outputstreams potrebbe essere meglio e più semplice da capire. Di solito evito il casting, ma se non stai cercando una soluzione generica, immagino che sarebbe okay.:)

Uso di corsi d'acqua, una soluzione generica:

public byte[] intToByteArray(final int i) throws java.io.IOException { 
    java.io.ByteArrayOutputStream b = new java.io.ByteArrayOutputStream(); 
    java.io.DataOutputStream d = new java.io.DataOutputStream(b); 
    d.writeInt(i); 
    d.flush(); 

    return b.toByteArray(); 
} 

E per invertire tale tendenza:

public int byteArrayToInt(final byte[] b) throws IOException { 
    java.io.ByteArrayInputStream ba = new java.io.ByteArrayInputStream(b); 
    java.io.DataInputStream d = new java.io.DataInputStream(ba); 

    return d.readInt(); 
} 
+0

Puoi anche farlo genericamente con java.nio.ByteBuffer e controllare anche endianess se necessario. Ho aggiunto una risposta per questa possibilità. –

6

Hai provato a trasmettere su un byte? per esempio.

sendData[1] = (byte)0x94; 
+0

Questo mi farà perdere la precisione, vero? –

+1

@Mark: renderà chiaro al compilatore che stai facendo esattamente ciò che vuoi fare. 0x94 si trova nell'intervallo di un byte, quindi non vi è alcuna perdita effettiva di precisione qui. –

+0

No, non è compreso nell'intervallo di un byte. Tutto in java è firmato e 0x94 viene letto come int e inserito in un byte. – corsiKa

1

Devi cast (byte) di default tipo di numero in Java è int, che è più grande di byte. Finché il valore si adatta al byte, è corretto eseguire il cast.

1

Prova questo:

sendData[0] =(byte)0x26 
sendData[1] =(byte)0x94 

O questo:

sendData[0] =(byte)38 
sendData[1] =(byte)148 

È necessario eseguire il cast i dati in byte per assegnarlo a un byte!

questo non significa che hai perso la precisione, solo scrivendo 0x26 significa un int al compilatore Java ..

Ma nota anche: gamma di un byte è da -128 a 127, quindi in caso di 0x94=148 sarà rappresentato dopo il byte casting come '-108', quindi non funzionerà correttamente nei calcoli matematici ..

0

È perché tutto in Java è firmato. 0x94 (148) è maggiore di Byte.MAX_VALUE (2^7-1).

Quello che vi serve è

public static byte[] intToByteArray(int value) { 
    byte[] b = new byte[4]; 
    for (int i = 0; i < 4; i++) { 
     int offset = (b.length - 1 - i) * 8; 
     b[i] = (byte) ((value >>> offset) & 0xFF); 
    } 
    return b; 
} 
+0

Nota, questo fa tutti e 4 i byte dell'int ... ne servono solo due. Il resto è semplice da questo. – corsiKa

+0

è sbagliato - non è perché tutto è firmato, è perché 0x94 è un int, non un byte, e in secondo luogo il tipo di carattere non è firmato, e in terzo luogo - quel codice è uno scherzo? Se stai solo scherzando con il ragazzo potrebbe valere un +1 :) l'originale andava bene se downcast con (byte) –

+2

0x94 è un int perché non si adatta a un byte 'perché i byte sono firmati'. Hai ragione che i caratteri non sono firmati, tuttavia è un'eccezione alla regola perché non è "previsto" come numero - i JavaGod hanno deciso che tutti i loro numeri saranno firmati. Puoi usarlo come un numero per l'ottimizzazione delle stringhe? Si, puoi. Era destinato ad essere usato come numero? No. La classe 'Character' estende la classe' Number'? No. Terzo, questo codice non è uno scherzo, è un modo legittimo per convertire qualsiasi int a un array di byte per rappresentare accuratamente i suoi bit. L'ho usato per la creazione di pacchetti TCP/IP in passato. – corsiKa

3

0x94 è 148 in decimali, che supera l'intervallo di byte in Java (da -128 a 127). È possibile effettuare una delle seguenti operazioni:

1) Un cast funziona bene perché manterrà la rappresentazione binaria (nessun bit significativi vengono troncati per 0x00 a 0xFF):

sendData[1] = (byte)0x94; 

2) Il binario rappresentazione di 0x94 come un byte con segno è -108 (-0x6C), quindi la seguente avrà lo stesso effetto:

sendData[1] = -0x6C; //or -108 in decimal 
+0

E per convertire nuovamente il byte firmato nel suo modulo int unsigned, puoi semplicemente scrivere 'b & 0xff'. –

3

Björn ha dato una buona risposta generica con l'utilizzo di flussi. Puoi anche fare la stessa cosa usando java.nio.ByteBuffer che produce un codice leggermente inferiore e puoi anche controllare l'endianess (ordine dei byte) dell'output.

Per creare la matrice di byte:

public static byte[] toByteArray(int bits) { 
    ByteBuffer buf = ByteBuffer.allocate(4); 
    buf.putInt(bits); 
    return buf.array(); 
} 

invertirla:

public static int fromByteArray(byte[] b) { 
    ByteBuffer buf = ByteBuffer.wrap(b); 
    return buf.getInt(); 
} 
Problemi correlati