【问题标题】:strange behaviour of java getBytes vs getBytes(charset)java getBytes vs getBytes(charset) 的奇怪行为
【发布时间】:2015-10-15 04:54:39
【问题描述】:

考虑以下几点:

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    【讨论】:

    • UTF-16 对 Unicode 进行编码,并且在上述情况下需要使用一对“代理”字符对一个字符进行编码。编码与 UTF-8 一样安全,标记高位。因此int String.codePointAt(int i)Character.charCount(int cp)。您将java中的文本视为amorph“Unicode”是正确的。在您需要字节的那一刻,UTF32 可能是一种选择。转换 UTF-8 字节或 UTF-16 字符只会部分正确,并且是不允许的。
    • 我是这么认为的,但here 有人认为情况可能并非如此,我错了。 char 数组似乎总是 UTF-16BE,只要底层字符串是。注意提出问题的人:)
    • @MaartenBodewes 是的,当时这是一个有远见的值得称赞的设计决策,让String 为 Unicode 文本,char 2 个字节,二进制数据使用byte[]。直到今天,有时一种其他语言也有它们的小麻烦。
    【解决方案2】:

    问题一:

    在这两个部分中:为什么输出 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 检索。


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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-29
      • 2016-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      相关资源
      最近更新 更多