1

考虑以下:

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?(即如何将字符串转换回其原始字节数组?)
4

2 回答 2

3

问题一:

在这两个部分中:为什么输出getBytes()getBytes(charSet)不同,即使我已经特别提到了字符串的字符集

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

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


问题2:

为什么 utf-32 部分的两个字节输出getByte都与实际不同byte[] b?(即如何将字符串转换回其原始字节数组?)

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

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

您可以使用 的实例更改此行为CharsetDecoder,使用 检索Charset.newDecoder


如果要将随机字节数组编码为 String 实例,则应使用十六进制或base 64 编码器。您不应该为此使用字符解码器

于 2015-07-24T13:40:51.073 回答
2

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

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

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

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

于 2015-07-24T13:51:16.500 回答