java getBytes 与 getBytes(charset) 的奇怪行为

strange behaviour of java getBytes vs getBytes(charset)

考虑以下因素:

public static void main(String... strings) throws Exception {
    byte[] b = { -30, -128, -94 };

    //section utf-32
    String string1 = new String(b,"UTF-32");
    System.out.println(string1);   //prints ?
    printBytes(string1.getBytes("UTF-32")); //prints 0 0 -1 -3 
    printBytes(string1.getBytes());  //prints 63

    //section utf-8
    String string2 = new String(b,"UTF-8"); 
    System.out.println(string2);  // prints •
    printBytes(string2.getBytes("UTF-8"));  //prints -30 -128 -94 
    printBytes(string2.getBytes());  //prints -107 
}

public static void printBytes(byte[] bytes){
    for(byte b : bytes){
        System.out.print(b +  " " );
    }

    System.out.println();
}

输出:

?
0 0 -1 -3 
63 
•
-30 -128 -94 
-107 

所以我有两个问题:

  1. 在两个部分中:为什么输出 getBytes()getBytes(charSet) 不同,即使我已经特别提到了字符串的字符集
  2. 为什么utf-32 段中getByte 的两个字节输出与实际的byte[] b 不同? (即如何将字符串转换回其原始字节数组?)

问题 1:

in both sections : why the output getBytes() and getBytes(charSet) are different even though I have specifically mentioned the string's charset

您指定的字符集在将字符串 字符编码 到字节数组期间使用(即仅在方法本身中)。它不是 String 实例本身的一部分。您设置字符串的字符集,字符集未存储。

Java没有字符集的内部字节编码;它在内部使用 char 数组。如果您在未指定字符集的情况下调用 String.getBytes(),它将使用 平台默认设置 - 例如Windows-1252 在 Windows 台机器上。


问题 2:

why both of the byte outputs of getByte in section utf-32 are different from the actual byte[] b? (i.e. how can I convert back a string to its original byte array?)

你不能总是这样做。并非所有字节都代表有效的字符编码。因此,如果这样的编码数组被解码,那么这些编码将被默默地忽略,即字节被简单地跳过。

这已经发生在 String string1 = new String(b,"UTF-32");String string2 = new String(b,"UTF-8"); 期间。

您可以使用 CharsetDecoder, retrieved using Charset.newDecoder 的实例更改此行为。


如果你想编码一个随机字节数组到一个字符串实例中那么你应该使用十六进制或者base 64 编码器.你不应该为此使用字符解码器

Java String / char (16 bits UTF-16!) / Reader / Writer 是用于 Unicode 文本。所以所有的脚本都可以合并在一个文本中。

Java byte (8 bits) / InputStream / OutputStream 用于二进制数据。如果该数据表示文本,则需要知道其编码才能从中生成文本。

所以从字节到文本的转换总是需要一个字符集。通常存在一个没有字符集的重载方法,然后它默认为 System.getProperty("file.encoding"),这在每个平台上都可能不同。 如果数据是跨平台的,则使用默认值绝对不可移植。

所以你误以为编码属于字符串。这是可以理解的,因为在 C/C++ 中 unsigned char 和 byte 在很大程度上是可以互换的,编码是一场噩梦。