2010-05-19 4 views
6

Ich versuche, die Portnummer 9876 (oder 0x2694 in hex) in einer Zwei-Byte-Array darstellen:eine Zahl in einer Byte-Array (Java-Programmierung) Darstellen

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

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

Aber ich eine Warnung über mögliche bekommen Verlust an Präzision:

foo.java:5: possible loss of precision 
found : int 
required: byte 
    sendData[1] = 0x94; 
       ^
1 error 

Wie kann ich die Nummer 9876 in einem zwei-Byte-Array repräsentieren ohne Präzision zu verlieren?

HINWEIS: Ich wählte den Code von @ Björn als die richtige Antwort, aber der Code von @glowcoder funktioniert auch gut. Es ist nur ein anderer Ansatz für das gleiche Problem. Danke euch allen!

+4

Beachten Sie, dass über den Draht zum Senden von Datenstrukturen Abflachung ist in der Regel mit einem Dataoutputstream (oder deren Unterklasse Object) erfolgt in Java. Keine Notwendigkeit, die Bitfiddling jedes Mal neu zu erfinden :-) – meriton

+1

@meriton: und noch besser, verwenden Sie 'java.nio.ByteBuffer', die all dies tun können, nicht mit IOException beschäftigen und endianness zu kontrollieren. –

Antwort

1

Meine erste Antwort wäre bitshifting, aber auf einem zweiten Gedanken ich denke, mit outputstreams könnte besser sein und einfacher zu verstehen. Ich vermeide normalerweise das Casting, aber wenn du keine generische Lösung suchst, denke ich, das wäre in Ordnung.:)

mit Hilfe von Streams, eine generische Lösung:

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

Und es umgekehrt:

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

Sie können dies auch generisch mit java.nio.ByteBuffer tun und die Endianess bei Bedarf steuern. Ich habe eine Antwort für diese Möglichkeit hinzugefügt. –

6

Haben Sie versucht, auf ein Byte zu übertragen? z.B.

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

Das wird mich dazu bringen, die Präzision zu verlieren, oder? –

+1

@Mark: Es wird dem Compiler klar machen, dass Sie genau das tun, was Sie tun möchten. 0x94 liegt im Bereich eines Bytes, daher gibt es hier keinen wirklichen Genauigkeitsverlust. –

+0

Nein, es liegt nicht im Bereich eines Bytes. Alles in Java ist signiert, und 0x94 wird als Int gelesen und in ein Byte umgewandelt. – corsiKa

1

Sie müssen zu (Byte) als Standard Zahl Typ in Java java ist Int, die größer als Byte ist. Solange der Wert in Byte passt, ist es in Ordnung zu werfen.

1

Versuchen Sie folgendes:

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

Oder diese:

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

Sie Daten in Byte, um es zu einem Byte zuzuweisen werfen müssen!

, das nicht Sie Präzision verloren bedeutet, nur 0x26 Schreiben bedeutet einen int zu Java-Compiler ..

Aber auch beachten Sie: Bereich eines Bytes von -128 bis 127 ist, so im Falle von 0x94=148 wird es sein, dargestellt nach Byte Casting als '-108', so wird es nicht richtig in mathematischen Berechnungen funktionieren ..

0

Es ist, weil alles in Java signiert ist. 0x94 (148) ist größer als Byte.MAX_VALUE (2^7-1).

Was Sie brauchen, ist

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

Beachten Sie, dass dies alle 4 Bytes des Int ... nur zwei von ihnen benötigt. Der Rest ist davon einfach. – corsiKa

+0

das ist zwei falsch - es ist nicht weil alles signiert ist, weil 0x94 ist ein int, kein Byte, und zweitens ist der char-Typ unsigned, und drittens - ist das Code ein Witz? Wenn Sie nur mit dem Kerl rummachen, könnte es ein +1 wert sein :) das Original war in Ordnung, wenn Sie mit (Byte) –

+2

0x94 ist ein int, weil es nicht in ein Byte passt, weil Bytes signiert sind. Sie haben Recht, dass Zeichen unsigniert sind - es ist jedoch die Ausnahme von der Regel, weil es nicht beabsichtigt ist, eine Zahl zu sein - die JavaGods entschieden, dass alle ihre Nummern signiert werden. Kannst du es wie eine Nummer für die String-Optimierung verwenden? Ja, du kannst. Soll es als Nummer benutzt werden? Nein. Erweitert die Klasse 'Character' die Klasse' Number'? Drittens, nein, dieser Code ist kein Witz, es ist ein legitimer Weg, jedes int in ein Byte-Array umzuwandeln, um seine Bits genau darzustellen. Ich habe es in der Vergangenheit für die TCP/IP-Paketerstellung verwendet. – corsiKa

3

0x94 148 in dezimal, die den Bereich von Byte in Java (-128 bis 127) übersteigt. Sie können eine der folgenden Aktionen ausführen:

1) Ein Abguss wird gut funktionieren, weil es die binäre Darstellung erhalten wird (keine aussagekräftigen Bits für 0x00 bis 0xFF abgeschnitten sind):

sendData[1] = (byte)0x94; 

2) Die binäre Darstellung von 0x94 als Byte mit Vorzeichen ist -108 (-0x6C), so dass die folgenden wird die gleiche Wirkung hat:

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

Und um das vorzeichenbehaftete Byte wieder in seine vorzeichenlose int-Form zu konvertieren, können Sie einfach 'b & 0xff' schreiben. –

3

Björn gab eine gute generische Antwort mit Streams verwenden. Sie können dies auch mit java.nio.ByteBuffer tun, was zu etwas weniger Code führt und Sie können auch die Endianität (Byte-Reihenfolge) der Ausgabe steuern.

den Byte-Array zu erstellen:

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

es rückgängig zu machen:

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