Java >> Java tutorial >  >> Tag >> byte

Konverter et byte-array til en numerisk repræsentation i Java

1. Oversigt

I denne øvelse vil vi udforske forskellige metoder til at konvertere en byte matrix til en numerisk værdi (int , lang , flyde , dobbelt ) og omvendt.

Byten er den grundlæggende informationsenhed i computerlagring og -behandling. De primitive typer defineret i Java-sproget er en bekvem måde at manipulere flere bytes på på samme tid. Derfor er der et iboende konverteringsforhold mellem en byte array og primitive typer.

Siden den korte og char typer kun består af to bytes, de behøver ikke meget opmærksomhed. Så vi vil fokusere på konverteringen mellem en byte array og int , lang , flyde og dobbelt typer.

2. Brug af Skift-operatører

Den mest ligetil måde at konvertere en byte på array til en numerisk værdi bruger skiftoperatorerne.

2.1. Byte Array til int og lang

Når du konverterer en byte array til en int værdi, bruger vi << (venstre skift) operatør:

int value = 0;
for (byte b : bytes) {
    value = (value << 8) + (b & 0xFF);
}

Normalt er længden af ​​bytes array i ovenstående kodestykke skal være lig med eller mindre end fire. Det er fordi en int værdi optager fire bytes. Ellers vil det føre til int rækkeviddeoverløb.

For at verificere rigtigheden af ​​konverteringen, lad os definere to konstanter:

byte[] INT_BYTE_ARRAY = new byte[] {
    (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE
};
int INT_VALUE = 0xCAFEBABE;

Hvis vi ser nærmere på disse to konstanter, INT_BYTE_ARRAY og INT_VALUE , vil vi opdage, at de er forskellige repræsentationer af det hexadecimale tal 0xCAFEBABE .

Lad os derefter kontrollere, om denne konvertering er korrekt:

int value = convertByteArrayToIntUsingShiftOperator(INT_BYTE_ARRAY);

assertEquals(INT_VALUE, value);

På samme måde, når du konverterer en byte array til en lang værdi, kan vi genbruge ovenstående kodestykke med to ændringer:værdien 's type er lang og længden af ​​bytes skal være lig med eller mindre end otte.

2.2. int og lang til Byte Array

Når du konverterer en int værdi til en byte array, kan vi bruge >> (signeret højre skift) eller >>> (usigneret højre skift) operatør:

byte[] bytes = new byte[Integer.BYTES];
int length = bytes.length;
for (int i = 0; i < length; i++) {
    bytes[length - i - 1] = (byte) (value & 0xFF);
    value >>= 8;
}

I ovenstående kodestykke kan vi erstatte >> operatør med >>> operatør. Det er fordi vi kun bruger de bytes, som værdien parameter oprindeligt indeholder. Så det rigtige skift med tegn-udvidelse eller nul-udvidelse vil ikke påvirke det endelige resultat.

Derefter kan vi kontrollere rigtigheden af ​​ovenstående konvertering:

byte[] bytes = convertIntToByteArrayUsingShiftOperator(INT_VALUE);

assertArrayEquals(INT_BYTE_ARRAY, bytes);

Når du konverterer en lang værdi til en byte array, behøver vi kun at ændre Integer.BYTES til Long.BYTES og sørg for, at typen af ​​værdi er lang .

2.3. Byte Array til at flyde og dobbelt

Når du konverterer en byte array til en float , gør vi brug af Float.intBitsToFloat() metode :

// convert bytes to int
int intValue = 0;
for (byte b : bytes) {
    intValue = (intValue << 8) + (b & 0xFF);
}

// convert int to float
float value = Float.intBitsToFloat(intValue);

Fra kodestykket ovenfor kan vi lære, at en byte array kan ikke transformeres direkte til en float værdi. Grundlæggende tager det to separate trin:Først overfører vi fra en byte array til en int værdi, og så fortolker vi det samme bitmønster til en float værdi.

For at verificere rigtigheden af ​​konverteringen, lad os definere to konstanter:

byte[] FLOAT_BYTE_ARRAY = new byte[] {
    (byte) 0x40, (byte) 0x48, (byte) 0xF5, (byte) 0xC3
};
float FLOAT_VALUE = 3.14F;

Lad os derefter kontrollere, om denne konvertering er korrekt:

float value = convertByteArrayToFloatUsingShiftOperator(FLOAT_BYTE_ARRAY);

assertEquals(Float.floatToIntBits(FLOAT_VALUE), Float.floatToIntBits(value));

På samme måde kan vi bruge en mellemlang lang værdi og Double.longBitsToDouble() metode til at konvertere en byte array til en dobbelt værdi .

2.4. flyde og dobbelt til Byte Array

Når du konverterer en float til en byte array, kan vi drage fordel af Float.floatToIntBits() metode :

// convert float to int
int intValue = Float.floatToIntBits(value);

// convert int to bytes
byte[] bytes = new byte[Float.BYTES];
int length = bytes.length;
for (int i = 0; i < length; i++) {
    bytes[length - i - 1] = (byte) (intValue & 0xFF);
    intValue >>= 8;
}

Lad os derefter kontrollere, om denne konvertering er korrekt:

byte[] bytes = convertFloatToByteArrayUsingShiftOperator(FLOAT_VALUE);

assertArrayEquals(FLOAT_BYTE_ARRAY, bytes);

I analogi kan vi gøre brug af Double.doubleToLongBits() metode til at konvertere en dobbelt værdi til en byte matrix .

3. Brug af ByteBuffer

java.nio.ByteBuffer klasse giver en pæn, samlet måde at oversætte mellem en byte matrix og en numerisk værdi (int , lang , flyde , dobbelt ).

3.1. Byte-array til numerisk værdi

Nu bruger vi ByteBuffer klasse for at konvertere en byte array til en int værdi:

ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.put(bytes);
buffer.rewind();
int value = buffer.getInt();

Derefter bruger vi ByteBuffer klasse for at konvertere en int værdi til en byte array:

ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.putInt(value);
buffer.rewind();
byte[] bytes = buffer.array();

Vi skal bemærke, at ovenstående to kodestykker følger samme mønster:

  • For det første bruger vi ByteBuffer.allocate(int) metode til at få en ByteBuffer objekt med en specificeret kapacitet.
  • Derefter sætter vi den oprindelige værdi (en byte matrix eller en int værdi) i ByteBuffer objekt, såsom buffer.put(bytes) og buffer.putInt(værdi) metoder.
  • Derefter nulstiller vi placeringen af ​​ByteBuffer objekt til nul, så vi kan læse fra starten.
  • Til sidst får vi målværdien fra ByteBuffer objekt ved hjælp af metoder som buffer.getInt() og buffer.array() .

Dette mønster er meget alsidigt, og det understøtter konvertering af lang , flyde og dobbelt typer. Den eneste ændring, vi skal foretage, er de typerelaterede oplysninger.

3.2. Brug af en eksisterende byte-array

Derudover er ByteBuffer.wrap(byte[]) metode giver os mulighed for at genbruge en eksisterende byte array uden at oprette en ny:

ByteBuffer.wrap(bytes).getFloat();

Vi skal dog også bemærke, at længden af ​​bytes variabel ovenfor er lig med eller større end størrelsen af ​​måltypen (Float.BYTES ). Ellers vil det kaste BufferUnderflowException .

4. Brug af BigInteger

Hovedformålet med java.math.BigInteger klasse skal repræsentere store numeriske værdier, som ellers ikke ville passe ind i en primitiv datatype. Selvom vi kan bruge det til at konvertere mellem en byte matrix og en primitiv værdi ved hjælp af BigInteger er lidt tung til denne slags formål.

4.1. Byte Array til int og lang

Lad os nu bruge BigInteger klasse for at konvertere en byte array til en int værdi:

int value = new BigInteger(bytes).intValue();

Tilsvarende er BigInteger klasse har en longValue() metode til at konvertere en byte array til en lang værdi:

long value = new BigInteger(bytes).longValue();

Desuden BigInteger klasse har også en intValueExact() metode og en longValueExact() metode. Disse to metoder skal bruges med omhu :hvis BigInteger objekt er uden for området for en int eller en lang type, vil begge metoder kaste en ArithmeticException .

Når du konverterer en int eller en lang værdi til en byte array, kan vi bruge det samme kodestykke:

byte[] bytes = BigInteger.valueOf(value).toByteArray();

Men toByteArray() metoden for BigInteger klasse returnerer det mindste antal bytes, ikke nødvendigvis fire eller otte bytes.

4.2. Byte Array til at flyde og dobbelt

Selvom BigInteger klasse har en floatValue() metode, kan vi ikke bruge den til at konvertere en byte array til en float værdi som forventet. Så hvad skal vi gøre? Vi kan bruge en int værdi som et mellemtrin for at konvertere en byte array til en float værdi:

int intValue = new BigInteger(bytes).intValue();
float value = Float.intBitsToFloat(intValue);

På samme måde kan vi konvertere en float værdi til en byte array:

int intValue = Float.floatToIntBits(value);
byte[] bytes = BigInteger.valueOf(intValue).toByteArray();

Ligeledes ved at drage fordel af Double.longBitsToDouble() og Double.doubleToLongBits() metoder, kan vi bruge BigInteger klasse til at konvertere mellem en byte array og en dobbelt værdi.

5. Brug af Guava

Guava-biblioteket giver os praktiske metoder til at udføre denne form for konvertering.

5.1. Byte Array til int og lang

Inden for Guava er Ints klasse i com.google.common.primitives pakken indeholder en fromByteArray() metode. Derfor er det ret nemt for os at konvertere en byte array til en int værdi:

int value = Ints.fromByteArray(bytes);

Ints klasse har også en toByteArray() metode, der kan bruges til at konvertere en int værdi til en byte array:

byte[] bytes = Ints.toByteArray(value);

Og Længerne klasse svarer i brug til Ints klasse:

long value = Longs.fromByteArray(bytes);
byte[] bytes = Longs.toByteArray(value);

Desuden, hvis vi inspicerer kildekoden til fromByteArray() og toByteArray() metoder, kan vi finde ud af, at begge metoder bruger skiftoperatører til at udføre deres opgaver .

5.2. Byte Array til at flyde og dobbelt

Der findes også Flåderne og Doubler klasser i samme pakke. Men ingen af ​​disse to klasser understøtter fromByteArray() og toByteArray() metoder.

Vi kan dog gøre brug af Float.intBitsToFloat() , Float.floatToIntBits() , Double.longBitsToDouble() , og Double.doubleToLongBits() metoder til at fuldføre konverteringen mellem en byte array og en float eller dobbelt værdi. For kortheds skyld har vi udeladt koden her.

6. Brug af Commons Lang

Når vi bruger Apache Commons Lang 3, er det lidt kompliceret at lave den slags konverteringer. Det er fordi Commons Lang-biblioteket bruger little-endian byte arrays som standard . Men byten arrays, vi nævnte ovenfor, er alle i big-endian rækkefølge. Derfor er vi nødt til at transformere en big-endian byte array til en lille-endian byte array og omvendt.

6.1. Byte Array til int og lang

Konverteringen klasse i org.apache.commons.lang3 pakken giver byteArrayToInt() og intToByteArray() metoder.

Lad os nu konvertere en byte array til en int værdi:

byte[] copyBytes = Arrays.copyOf(bytes, bytes.length);
ArrayUtils.reverse(copyBytes);
int value = Conversion.byteArrayToInt(copyBytes, 0, 0, 0, copyBytes.length);

I ovenstående kode laver vi en kopi af de originale bytes variabel. Dette skyldes, at vi nogle gange ikke ønsker at ændre indholdet af den originale byte array.

Lad os derefter konvertere en int værdi til en byte array:

byte[] bytes = new byte[Integer.BYTES];
Conversion.intToByteArray(value, 0, bytes, 0, bytes.length);
ArrayUtils.reverse(bytes);

Konverteringen klasse definerer også byteArrayToLong() og longToByteArray() metoder. Og vi kan bruge disse to metoder til at transformere mellem en byte array og en lang værdi.

6.2. Byte Array til at flyde og dobbelt

Men Konverteringen klasse giver ikke direkte de tilsvarende metoder til at konvertere en float eller dobbelt værdi.

Igen har vi brug for en mellemliggende int eller lang værdi for at transformere mellem en byte array og en float eller dobbelt værdi.

7. Konklusion

I denne artikel illustrerede vi forskellige måder at konvertere en byte på array til en numerisk værdi ved hjælp af almindelig Java gennem shift-operatorer, ByteBuffer , og BigInteger . Derefter så vi de tilsvarende konverteringer ved hjælp af Guava og Apache Commons Lang.

Som sædvanlig kan kildekoden til denne tutorial findes på GitHub.


Java tag