Java negativo int para hex e volta falhar
Pergunta
public class Main3 {
public static void main(String[] args) {
Integer min = Integer.MIN_VALUE;
String minHex = Integer.toHexString(Integer.MIN_VALUE);
System.out.println(min + " " + minHex);
System.out.println(Integer.parseInt(minHex, 16));
}
}
Dá
-2147483648 80000000
Exception in thread "main" java.lang.NumberFormatException: For input string: "80000000"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:459)
at Main3.main(Main3.java:7)
Whats up?
Solução
É documentado que Integer.toHexString
retorna uma representação de string do número inteiro como um valor não assinado - enquanto Integer.parseInt
leva um int assinado. Se você usar Integer.toString(value, 16)
vez você vai conseguir o que deseja.
Outras dicas
Isso é algo que sempre me incomodou. Se você inicializar um int com um literal hexadecimal, você pode usar toda a gama de valores positivos até 0xFFFFFF
; qualquer coisa maior que 0x7FFFFF
realmente vai ser um valor negativo. Isto é muito útil para mascarar bit e outras operações onde você só se preocupam com o locais dos bits, não seus significados.
Mas se você usar Integer.parseInt () para converter uma string para um inteiro, qualquer coisa maior do que "0x7FFFFFFF"
é tratado como um erro. Há provavelmente uma boa razão por que eles fizeram isso dessa forma, mas ainda é frustrante.
A solução mais simples é usar Long.parseLong () em vez disso, em seguida, converter o resultado para int.
int n = (int)Long.parseLong(s, 16);
É claro, você só deve fazer isso se tiver certeza o número vai ser na Integer.MIN_VALUE..Integer.MAX_VALUE
gama.
De acordo com a documentação, toHexString
retornos "uma representação de string do argumento inteiro como um não assinado inteiro em base 16."
Assim, a operação inversa correta é provavelmente Integer.parseUnsignedInt
que foi introduzido como parte de Java 8:
public class Main3 {
public static void main(String[] args) {
Integer min = Integer.MIN_VALUE;
String minHex = Integer.toHexString(Integer.MIN_VALUE);
System.out.println(min + " " + minHex);
System.out.println(Integer.parseUnsignedInt(minHex, 16));
}
Tente isto:
public class Main3 {
public static void main(String[] args) {
Integer min = Integer.MIN_VALUE;
String minHex = Integer.toHexString(Integer.MIN_VALUE);
System.out.println(min + " " + minHex);
System.out.println(Integer.parseInt( "-" + minHex, 16));
}
}
para obter este:
-2147483648 80000000
-2147483648
Você precisa incluem sinal negativo .
Eu não tenho acesso a testar isso agora, mas eu aposto que se você tentou este valor em vez disso:
Integer min = Integer.MIN_VALUE + 1;
Não seria bombardear, mas iria dar-lhe um número positivo (não negativo) quando executou ParseInt(min,16)
.
A string de bits realmente não tem informação suficiente para determinar sinal neste contexto de modo que você precisa para fornecê-la. (Considere o caso em que você usa min = "F"
. É isso +/- F? Se você converteu-o em pedaços e viu 1111, e você sabia que era um byte, você pode concluir que ele é negativo, mas que de um monte de ifs.
Este parece trabalhar para mim:
public class Main3 {
public static void main(String[] args) {
Integer min = Integer.MIN_VALUE;
String minHex = Integer.toHexString(Integer.MIN_VALUE);
System.out.println(min + " " + minHex);
System.out.println((int)Long.parseLong(minHex, 16));
}
}
O inteiro é analisado como um "assinado longa" que lidar com esse número positivo grande e, em seguida, o sinal é encontrado de volta, lançando-a "int".