Como converter Int em Byte sem Sinal e Voltar


92

Preciso converter um número em um byte sem sinal. O número é sempre menor ou igual a 255 e, portanto, caberá em um byte.

Também preciso converter esse byte de volta nesse número. Como eu faria isso em Java? Já tentei de várias maneiras e nenhuma funcionou. Aqui está o que estou tentando fazer agora:

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

e agora para converter esse byte de volta no número:

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

Claramente, isso não funciona. Por algum motivo, ele sempre converte o número em 65. Alguma sugestão?


Eu também tentei este método: crazysquirrel.com/computing/java/basics/… - não funciona.
darksky

Respostas:


200

Um byte é sempre assinado em Java. Você pode obter seu valor sem sinal binário-e-o com 0xFF, embora:

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

Ainda estou fazendo 65 ... Por que isso?
darksky

1
Ele está armazenando o número que você deseja no byte. Java apenas o considera como um número assinado em vez de um não assinado. Mas cada bit é o mesmo como se fosse um número sem sinal. A conversão de sua string em bytes é outra questão não relacionada. Poste separadamente, em uma nova pergunta.
JB Nizet

1
use getInt para voltar seu int e transforme o int como um byte. Um int é um int. De onde vem não importa.
JB Nizet

18
Por que bit a bit e com 0xFFresulta em um inteiro sem sinal? Alguma explicação seria muito útil.
user462455

2
Java 8 usa o mesmo método: public static int toUnsignedInt (byte x) {return ((int) x) & 0xff; }
Daniel De León

55

Java 8 oferece Byte.toUnsignedIntconversão bytepara intconversão sem sinal. No JDK da Oracle, isso é implementado simplesmente return ((int) x) & 0xff;porque o HotSpot já entende como otimizar esse padrão, mas pode ser intrinsecado em outras VMs. Mais importante, nenhum conhecimento prévio é necessário para entender o que faz uma chamada toUnsignedInt(foo).

No total, o Java 8 fornece métodos para converter bytee shortpara sem sinal inte longe intpara sem sinal long. Um método para converter bytepara não assinado shortfoi omitido deliberadamente porque a JVM fornece apenas aritmética em inte de longqualquer maneira.

Para converter uma volta int para um byte, é só usar um elenco: (byte)someInt. A conversão primitiva de estreitamento resultante descartará todos, exceto os últimos 8 bits.


7

Se você só precisa converter um valor esperado de 8 bits de um int assinado em um valor não assinado, você pode usar o deslocamento de bits simples:

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 estiver usando algo diferente de int tipo base, obviamente você precisará ajustar a quantidade de deslocamento: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Além disso, lembre-se de que você não pode usar o bytetipo, pois isso resultará em um valor com sinal, conforme mencionado por outros respondentes. O menor tipo primitivo que você poderia usar para representar um valor sem sinal de 8 bits seria a short.


3

A Integer.toString(size)chamada é convertida na representação char do seu inteiro, ou seja, o char '5'. A representação ASCII desse caractere é o valor 65.

Você precisa analisar a string de volta para um valor inteiro primeiro, por exemplo, usando Integer.parseInt , para obter de volta o valor int original.

Em Stringresumo , para uma conversão com / sem sinal, é melhor sair de cena e usar a manipulação de bits como @JB sugere.


Tão assim? (Ainda obtendo 65 aqui)String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
darksky

@Nayefc, atualizei minha resposta exatamente quando você estava escrevendo seu comentário :-)
Péter Török

Tudo bem, obrigado! Por alguma razão ainda imprime 65. O que isto significa? Se mostrar apenas 65, o que realmente está sendo armazenado no byte, então não entendi. Verifique também minha pergunta, eu editei e adicionei uma seção sobre a conversão de strings :)
darksky

@Nayefc, novamente, String.getBytes()produz os valores ASCII dos caracteres contidos no texto, não os valores numéricos dos dígitos. Você precisa analisar a string em um valor numérico, como sugeri acima.
Péter Török

1
@Nayefc, então essa é uma questão totalmente diferente. E AFAIS deve funcionar. Crie uma nova pergunta, incluindo a entrada e saída reais da conversão e o código completo para reproduzir o caso.
Péter Török

3

A solução funciona bem (obrigado!), Mas se você quiser evitar o lançamento e deixar o trabalho de baixo nível para o JDK, você pode usar um DataOutputStream para gravar seus int's e um DataInputStream para lê-los de volta. Eles são tratados automaticamente como não assinados bytes então:

Para converter int's em bytes binários;

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

Lendo-os de volta em:

// 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. útil para lidar com formatos de dados binários (por exemplo, formatos de mensagens simples, etc.)


3

Exceto char, todos os outros tipos de dados numéricos em Java são assinados.

Como disse em uma resposta anterior, você pode obter o valor sem sinal executando uma andoperação com 0xFF. Nesta resposta, vou explicar como isso acontece.

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 sua máquina for de 32 bits, o inttipo de dados precisará de 32 bits para armazenar valores. byteprecisa de apenas 8 bits.

A intvariável ié representada na memória da seguinte maneira (como um inteiro de 32 bits).

0{24}11101010

Então, a bytevariável bé representada como:

11101010

Como bytes não têm sinal, este valor representa-22 . (Pesquise o complemento de 2 para aprender mais sobre como representar inteiros negativos na memória)

Então, se você lançar for para int, ainda assim será -22porque o lançamento preserva o sinal de um número.

1{24}11101010

O 32-bitvalor fundido de bexecutar andoperação com 0xFF.

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

Então você obtém 234a resposta.


1

Tratamento de bytes e inteiros sem sinal com 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

Embora seja tarde demais, gostaria de dar minha opinião sobre isso, pois pode esclarecer por que a solução fornecida por JB Nizet funciona. Eu me deparei com este pequeno problema trabalhando em um analisador de bytes e na conversão de strings. Quando você copia de um tipo integral de tamanho maior para um tipo integral de tamanho menor, pois este documento java diz que isso acontece:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 Uma conversão de estreitamento de um inteiro com sinal em um tipo integral T simplesmente descarta todos, exceto o n mais baixo bits de ordem, onde n é o número de bits usados ​​para representar o tipo T. Além de uma possível perda de informação sobre a magnitude do valor numérico, isso pode fazer com que o sinal do valor resultante seja diferente do sinal do valor de entrada .

Você pode ter certeza de que um byte é um tipo integral, pois este documento java diz https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html byte: O tipo de dados de byte é um dois de 8 bits assinado complemento inteiro.

Portanto, no caso de converter um inteiro (32 bits) em um byte (8 bits), basta copiar o último (8 bits menos significativos) desse inteiro para a variável de byte fornecida.

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

A segunda parte da história envolve como os operadores unários e binários Java promovem operandos. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 A conversão primitiva de ampliação (§5.1.2) é aplicada para converter um ou ambos os operandos, conforme especificado pelas seguintes regras:

Se um dos operandos for do tipo double, o outro será convertido em double.

Caso contrário, se um dos operandos for do tipo float, o outro será convertido para float.

Caso contrário, se um dos operandos for do tipo long, o outro será convertido em long.

Caso contrário, ambos os operandos são convertidos para o tipo int.

Fique tranquilo, se você estiver trabalhando com tipo integral int e / ou inferior, ele será promovido 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

Também arranhei minha cabeça em torno disso :). Há uma boa resposta para isso aqui por rgettman. Operadores bit a bit em java apenas para inteiros e longos?


0

Se você quiser usar as classes de wrapper primitivas, isso funcionará, mas todos os tipos java são assinados por padrão.

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

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

resultado: 254

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.