java getBytes vs getBytes(charset)

时间:2015-07-24 13:30:33

标签: java utf-8 character-encoding utf-32

考虑以下事项:

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)不同,即使我特别提到了字符串' s charset
  2. 为什么utf-32部分中getByte的两个字节输出都与实际的byte[] b不同? (即如何将字符串转换回原始字节数组?)

2 个答案:

答案 0 :(得分:2)

问题1:

  

在两个部分中:为什么输出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 编码器。你不应该使用字符解码器

答案 1 :(得分:2)

Java String / char (16位UTF-16!) / Reader / Writer 用于Unicode文本。因此,所有脚本都可以组合成文本。

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

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

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