关于一个字符占多少个字节的问题

来源:互联网 发布:网络伤感情歌对唱 编辑:程序博客网 时间:2024/03/29 18:56
首先解释为什么说char占两个字节
Java code
?
1
2
3
4
5
6
public static void main(String[] args) {
    System.out.printf("The max value of type char is %d.%n"
            (int)Character.MAX_VALUE);
    System.out.printf("The min value of type char is %d.%n"
            (int)Character.MIN_VALUE);
}

运行上面的程序,输出
The max value of type char is 65535.
The min value of type char is 0.
说明char的范围从0到65535,那么正好是两个字节所能表示的范围(65535十六进制就是0xFFFF,一个字节能表示0~0xFF,两个字节能表示0~0xFFFF),所以说一个char占两个字节。

那么char的值到底是什么呢?比如当我这样写char c = '放';
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception {
    char c = '放';
    System.out.printf("The value of char %c is %d.%n", c, (int)c);
     
    String str = String.valueOf(c);
    byte[] bys = str.getBytes("Unicode");
    for (int i = 0; i < bys.length; i++) {
        System.out.printf("%X ", bys[i]);
    }
    System.out.println();
     
    int unicode = (bys[2] & 0xFF) << 8 | (bys[3 0xFF]);
    System.out.printf("The unicode value of %c is %d.%n", c, unicode);
}

运行输出:
The value of char 放 is 25918.
FE FF 65 3E 
The unicode value of 放 is 25918.
首先你看到,这个char的值是25918,那他是什么呢?先不管它,接着我把这个char放在一个String里,并进行Unicode编码,得到四个字节FE FF 65 3E,前面两个实际上与内容无关,是BOM,即字节序标识,FE FF表示是Big Endian,也就是高位在前,低位在后,所以按照这个规则,讲653E转换为10进制int,发现最后输出25918,也就是这个字符的Unicode值是25918,所以你现在知道一个char到底存储的是什么了吧。

至于GBK,UTF-8,UTF-16的关系,我先抛开GBK,因为它有点特殊。
首先你要知道UTF-8和UTF-16还有UTF-32是为了方便传输和存储的而产生的对Unicode字符的编码方式。
先说UTF-8,随着全球化Unicode流行起来,不管你做什么,支持Unicode都将是潮流,就算你可能永远也用不到,但这对西方国家就不太好,因为以前ASCII字符集,一个字符只需要一个字节,而现在用Unicode一个英文字母也需要两个字节,如果需要传输和存储,那会浪费一半的空间或流量,所以就想出了一种变长编码方式,那就是UTF-8,它对ASCII字符集内的字符,只用一个字节编码,而其他字符按照一定规则进行两、三、四字节编码,具体规则是:
Unicode编码(十六进制)    UTF-8 字节流(二进制)
000000 - 00007F                0xxxxxxx
000080 - 0007FF                110xxxxx 10xxxxxx
000800 - 00FFFF               1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF               11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

但这样做一些东方国家不干了,因为他们的字符基本都是在000800 - 00FFFF这个区间,用UTF-8反倒要多用一个字节,总共需要三个字节才能表示,而且用UTF-8处理他们的字符,不能直接转换,需要做一些运算,以‘放’为例,它的Unicode码是25918,二进制表示是0110010100111110,如果要转成UTF-8,首先取高四位0110,和1110拼接,组成11100110,然后中间六位010100,与10拼接构成10010100,最后低六位111110,与10拼接构成10111110,所以三个字节是11100110 10010100 10111110,也就是十六进制的E6  94 BE,也就是你上面写的-26 -108 -66。可以看到这个运算量虽然不大,基本是位操作,但如果你每个字符都要这么操作实在是有损效率,综合这几点考虑,于是又弄了一个UTF-16,不严谨地来说它等价于Unicode原生编码,它统一采用双字节表示一个字符(其实有四字节区域,但现在一般没有用到),而由于它用多字节表示,和Unicode一样需要字节序标识,你上面代码里发现它得到-2, -1, 101, 62,转为十六进制就是FE FF 65 3E,和我第二个实例程序中相同,说明UTF-16的码值(如表示‘放’的65 3E)和Unicode原生编码是相同的。

UTF-32的诞生其实也不奇怪,因为UTF-16还是一个变长编码方式,一个字符可能由两个或四个字节表示,有些有强迫症的人总觉得不好,所以为了他们就有了UTF-32,它统一使用四字节表示一个字符,因为用得不多所以不详细说了。

最后说说GBK是个什么东西。GBK是国标扩(展)的拼音首字母,是我国在1995年制定的专门针对汉语和一些少数名族语言的编码方式,和Unicode之间没有一一对应的关系,也就是说Unicode中有的字符GBK不一定有,GBK有的字符Unicode也不一定有,而且GBK和Unicode中共有字符,他们的编码值没有一种简单的对应关系,也就是无法通过简单计算得到,只能通过查表转换。为什么会有GBK这种奇葩呢?其实是当时Unicode还没制定好,更没在全球范围内推广,而中国人要用电脑总不可能永远用英语吧?所以我国就自行制定了一个国标,当时是GB2312,(其实台湾地区针对繁体还有一个Big5,但这里就不详述了),GB2312后来增加了很多字符,包括很多少数名族的语言,成为了一个新的编码标准,那就是GBK。
0 0