Java中文乱码——1、Java编解码基础

来源:互联网 发布:iis7 php http503 编辑:程序博客网 时间:2024/05/21 15:00
        相信大家平时遇到过不少中文乱码问题,大家是怎么解决的,是使用new String(s.getByte(“ISO-8859-1"), “GBK")这样的方式吗?如果是的话,那么大家有没有问过自己以下问题:
        a)s.getByte(“ISO-8859-1")做了什么?
        b)newString(byte[], “GBK")又做了什么?
        c)这个转换过程的意义是干什么?
        d)转码前后,占内存大小改变了吗?变大还是变小了?

一、常见字符集简介

        详见http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
ASCII
        7bits,不支持中文
ISO-8859-1
        8bits,不支持中文
UTF-8
        西文1字节,中文3字节
GBK/GB2312/GB18030
        西文1字节,中文一般都是2字节
Unicode
        2字节,也称utf-16,可以和任意其它字符集互转

二、编解码基础

        在特定字符集中,字符和code一一对应,比如:unicode中汉字“中”对应code 0x4e2d。
        Java内部采用unicode来表示一个字符,我们将unicode字符转换成字节的过程,称为“编码”;将字节恢复成unicode字符的过程,称为“解码”。 此处要强调3点:
        1、String内部包含一个字符数组char[]
        2、该char[]采用Unicode,也就是UTF-16字符集来表示
        3、该char[]可以看成是1个byte[],其中当然1char=2bytes
        此外,个人更喜欢把编解码过程统一看成byte[]之间的转换。假设编解码都采用charsetA,那么其中前者是从UTF-16到charsetA的转换,后者则相反。

三、转码过程理解

1、s.getByte(“ISO-8859-1")做了什么

        它的意思是说,将字符串s中的char[]用ISO-8859-1 code序列byte[]来表示。即
char[] => ISO-8859-1 byte[]
        也可以理解成
UTF-16 byte[] a =>  ISO-8859-1 byte[] b

2、new String(byte[], “GBK")做了什么


        它的意思是说,我这里有个byte数组,请先将它看成GBK的code序列,然后再将每个code解析为可读字符。即
GBK byte[] => char[]
        或者说
GBK byte[] b => UTF-16 byte[] c

3、这个转换过程的意义是什么

        把两步连在一起,就成了
UTF-16 byte[] a => ISO-8859-1 byte[] b = GBK byte[] b => UTF-16 byte[] c

        再者,乱码一般发生在io过程中,io采用byte[]来传输数据,因此其实最前面还有一个过程

ISO-8859-1 byte[] b => UTF-16 byte[] a
        把这三步连在一起就成了
ISO-8859-1 byte[] b => UTF-16 byte[] a => ISO-8859-1 byte[] b = GBK byte[] b => UTF-16 byte[] c
        于是,它的含义就出来了:把一个原本以ISO-8859-1来理解的byte[] b,重新以GBK来理解。

4、转码前后,占内存大小改变了吗?变大还是变小了?

        由于UTF-16是定长编码的,因此,要看内存大小是否改变,只需要看分别以ISO-8859-1和GBK来理解同一个byte[]时,最终的字符数是否会变化。
        很显然,如果byte[]中全都是ascii字符,那么字符数肯定一样,否则肯定就不一样。
        那么是变大还是变小了?
        我们知道ISO-8859-1是单字节的,GBK是可变字节的,那么如果两者最终得到的字节数不一样,肯定是按照ISO-8859-1的方式去理解会得到更多的字符。
        总结起来就是:如果转码后不包含中文,则大小不变,否则变小。
        不过,实话说,这个结论貌似也没有什么实用价值。

四、默认编码

        聊完转码过程,我们再聊聊默认编码的问题。
        我们知道s.getByte("ISO-8859-1")是指UTF-16 byte[] a =>  ISO-8859-1 byte[] b,那么s.getByte()呢?类似地,newString(byte[], "GBK")是指GBK byte[] b => UTF-16 byte[] c,那么newString(byte[])呢?
        其实,当我们没有指定编码集时,系统会默认指定一个编码集,那么这个默认编码集是怎么指定的?
        首先、它由JVM参数file.encoding决定;
        其次、如果没有指定file.encoding,则它由系统变量决定。Linux下由环境编码NLS_LANG决定;Window下也是由环境变量NLS_LANG决定;在Eclipse下则是由启动脚本common页下的“Encoding设置”决定;
        最后、如果真的是啥都没指定,那么默认就是ISO-8859-1



参考

        http://openwebx.org/docs/requestcontexts.html#webx3.requestcontexts.setlocale
0 0
原创粉丝点击