Como obter os bytes de uma String?
Existe um método para isso: getBytes(). Mas ele pode não fazer exatamente o que você imagina.
Question
Como obter os bytes de uma String?
Less Short Answer
Uma String encapsula um array de bytes, num campo privado chamado value. Antes era um array de char, mas desde o Java 9 (Compact Strings, JEP 254) é um array de byte. A string também tem um campo coder, que assume um de dois valores: LATIN1 (um byte por caractere) ou UTF16 (dois bytes por caractere).
Então você poderia esperar que getBytes() te devolvesse esse array interno. Não devolve. Quando você chama getBytes(), os caracteres da string são codificados com o charset padrão, e o que você recebe é um array novo com essa codificação.
javaString s = "Olá";
byte[] utf8 = s.getBytes(StandardCharsets.UTF_8); // [79, 108, -61, -95]: 4 bytes, "á" ocupa dois
byte[] latin1 = s.getBytes(StandardCharsets.ISO_8859_1); // [79, 108, -31]: 3 bytes
byte[] utf16 = s.getBytes(StandardCharsets.UTF_16); // 8 bytes: um BOM (FE FF) + 2 bytes por charMesma string, três arrays de bytes diferentes. Nenhum deles é "os bytes da string": são os bytes da string numa determinada codificação.
Use um Charset Explícito
O getBytes() sem argumentos usa Charset.defaultCharset(). Se você quer um resultado previsível, passe o charset você mesmo.
javabyte[] imprevisivel = s.getBytes(); // depende do charset padrão
byte[] previsivel = s.getBytes(StandardCharsets.UTF_8); // sempre UTF-8A sobrecarga que recebe um Charset também é mais agradável que a que recebe o nome do charset: getBytes("UTF-8") lança a exceção checada UnsupportedEncodingException, a versão com Charset não.
CharsetEncoder: Quando Você Precisa de Controle
Em vez de getBytes(), você também pode usar charset.newEncoder().encode(...). A diferença aparece com caracteres que o charset não consegue representar: getBytes() os substitui silenciosamente (por ? no Latin-1), enquanto um CharsetEncoder reporta um erro por padrão.
javaString s = "€uro";
byte[] comPerda = s.getBytes(StandardCharsets.ISO_8859_1);
System.out.println(new String(comPerda, StandardCharsets.ISO_8859_1)); // ?uro: o € sumiu, sem erro
CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
ByteBuffer buffer = encoder.encode(CharBuffer.wrap(s));
// lança UnmappableCharacterException: você fica sabendo que os dados não cabemVocê pode configurar esse comportamento com onMalformedInput() e onUnmappableCharacter() (REPORT, REPLACE ou IGNORE), e o encoder trabalha com buffers, o que é útil quando você processa grandes volumes de texto em fluxo.
De Onde Vem o Charset Padrão
Uma última palavra. Se você não definiu o charset padrão, ele é lido do ambiente: historicamente a JVM o obtinha do sistema operacional (o locale e a codificação da plataforma). Então você podia escrever e testar sua aplicação num país, fazer o deploy num ambiente de nuvem em outro país, e obter em produção um charset diferente daquele com que desenvolveu.
Desde o Java 18 (JEP 400), o charset padrão é UTF-8 em todas as plataformas, o que elimina boa parte dessa surpresa. A codificação do sistema operacional continua disponível, exposta na propriedade de sistema native.encoding, e você pode recuperar o comportamento antigo com -Dfile.encoding=COMPAT.
javaSystem.out.println(Charset.defaultCharset()); // UTF-8 no Java 18+
System.out.println(System.getProperty("native.encoding")); // ex.: Cp1252 numa máquina WindowsEntão o conselho vale para qualquer versão: se os bytes importam (arquivos, rede, hashing, assinaturas), sempre nomeie o charset.
One Last Word
Algo de que você precisa estar ciente!