Java的UTF-16字符编码

18

我试图理解Java中的字符编码。在Java中,使用UTF-16编码将字符存储在16位中。因此,当我将包含6个字符的字符串转换为字节时,我得到了6个字节,而不是我预期的12个字节。我是否忽略了某些概念?

package learn.java;

public class CharacterTest {

    public static void main(String[] args) {
        String str = "Hadoop";
        byte bt[] = str.getBytes();
        System.out.println("the length of character array is " + bt.length);
    } 
}

O/p:字符数组的长度为6

根据@Darshan的说法,尝试使用UTF-16编码获取字节时,结果也不符合预期。

package learn.java;

    public class CharacterTest {

        public static void main(String[] args) {

            String str = "Hadoop";
            try{
                byte bt[] = str.getBytes("UTF-16");
                System.out.println("the length of character array is " + bt.length);

            }
            catch(Exception e)
            {

            }
        } 
    }

o/p: the length of character array is 14

str.getBytes("UTF-16");但我想知道输出是14 - Darshan Patel
1
是的Darshan,我也是这么认为的。应该是12对吧!!! - priyaranjan
7
是的,为此您需要使用 utf-16leutf-16be。请参考以下[链接]http://rosettacode.org/wiki/String_length获取更多详细信息。 - Darshan Patel
1
你的前两个字节是 0x76 0x77,表示接下来的字节使用(默认)大端记法,而不是(备选)小端记法。这种前缀称为字节顺序标记(BOM)。如果没有 BOM,则每个字符将有 12 个字节,每个字符占用两个字节。 - tucuxi
5个回答

14
在UTF-16版本中,由于插入了一个标记来区分大端(默认)和小端,所以你会得到14个字节。如果你指定UTF-16LE,你将得到12个字节(小端,没有添加字节顺序标记)。
请参见http://www.unicode.org/faq/utf_bom.html#gen7

编辑 - 使用此程序查看不同编码生成的实际字节:

public class Test {
    public static void main(String args[]) throws Exception {
        // bytes in the first argument, encoded using second argument
        byte[] bs = args[0].getBytes(args[1]);
        System.err.println(bs.length + " bytes:");

        // print hex values of bytes and (if printable), the char itself
        char[] hex = "0123456789ABCDEF".toCharArray();
        for (int i=0; i<bs.length; i++) {
            int b = (bs[i] < 0) ? bs[i] + 256 : bs[i];
            System.err.print(hex[b>>4] + "" + hex[b&0xf] 
                + ( ! Character.isISOControl((char)b) ? ""+(char)b : ".")
                + ( (i%4 == 3) ? "\n" : " "));
        }
        System.err.println();   
    }
}

例如,在使用UTF-8编码时(在其他JVM默认编码下,FE和FF的字符会显示不同),输出结果如下:
$ javac Test.java  && java -cp . Test hello UTF-16
12 bytes:
FEþ FFÿ 00. 68h
00. 65e 00. 6Cl
00. 6Cl 00. 6Fo

$ javac Test.java  && java -cp . Test hello UTF-16LE
10 bytes:
68h 00. 65e 00.
6Cl 00. 6Cl 00.
6Fo 00. 

$ javac Test.java  && java -cp . Test hello UTF-16BE
10 bytes:
00. 68h 00. 65e
00. 6Cl 00. 6Cl
00. 6Fo

2
我很困惑,BOM不应该是FE FF吗?为什么你的打印输出中是76 ~ 77呢? - Roland
感谢你的发现,Roland - 几个小错别字合作导致了非常不正确的十六进制输出。 - tucuxi

3
根据 String.getBytes() 方法的文档,该方法使用平台默认字符集将字符串编码为一个字节序列。

我假设,你所用的平台默认字符集将是 ISO-8859-1(或类似的一字节字符集)。这些字符集将一个字符编码为一个字节。

如果你想指定编码,请使用 String.getBytes(Charset)String.getBytes(String) 方法。

关于 16 位存储:这是 Java 内部存储字符和字符串的方式,它基于最初的 Unicode 规范。


2

String.getBytes() 使用默认的平台编码。请尝试使用以下代码:

byte bt[] = str.getBytes("UTF-16");

1

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接