强烈建议使用UTF编码:

来源:互联网 发布:sql join left join 编辑:程序博客网 时间:2024/05/16 00:48

Java的乱码问题由来已久,有点经验的开发人员肯定遇到过乱码问题,有事是从Web上接受的乱码,有时是从数据库中读取的乱码,有时是从外部接口中接收到的乱码文件,这些都让我们困惑不已,甚至是痛苦不堪,看如下代码:

public static void main(String[] args) throws Exception{String str = “汉字”;//读取字节byte[] b = str.getBytes(“UTF-8”);//重新生成一个新的字符串System.out.println(new String(b));}
Java文件是通过IDE工具默认创建的,编码格式是GBK。大家想想看上面的输出结果会是什么?可能是乱码吧?两个编码格式不相同。我们暂时不公布结果,先解释一下Java中的编码规则。

Java程序涉及的编码包括两部分:

(1)Java文件编码

如果我们使用记事本创建一个.java后缀的文件,则文件的编码格式就是操作系统默认的格式。如果是使用IDE工具创建的,如Eclipse,则依赖于IDE的设置,Eclipse默认是操作系统编码(Windows一般为GBK)。

(2)Class文件编码

通过javac命令生成的后缀名为.javac的文件是UTF-8编码的UNICODE文件,这在任何操作系统上都是一样的,只要是Class文件就会是UNICODE格式。UTF是UNICODE的存储和传输格式,它是为了解决UNICODE的高位占用冗余空间而产生的,使用UTF编码就标志着字符集使用的是UNICODE。

再回到我们的例子中,getBytes方法会根据指定的字符集提取出字节数组(这里按照UNICODE格式来提取),然后程序又通过new String(Byte[]  bytes)重新生成一个字符串。String这个构造函数通过操作系统默认的字符集解码指定的byte数组,构造一个新的String,如果操作系统是UTF-8编码的话,输出是正确的,如果不是,则会是乱码。由于这里使用的是默认编码GBK,那么输出的结果也就是乱码了。
我们再详细分解一下运行步骤:

步骤1:创建Client.java文件。

该文件的默认编码GBK(如果使用Eclipse,则可以在属性查看到)。

步骤2:编码代码(同上)。

步骤3:保存,并使用javac编译。

注意我们没有使用"javac-encoding GBK Client.java"显示声明Java的编码格式,javac会自动按照操作系统的编码(GBK)读取Client.java文件,然后将其编译成.class文件。

步骤4:生成.class文件。

编译结束,生成.class文件,并保存到硬盘上。此时.class文件使用的是UTF-8格式编码的UNICODE字符集,可以通过javac命令阅读class文件。其中“汉字”变量也已经由GBK编码转变成UNICODE格式了。

步骤5:运行main方法,提取“汉字”的字节数组。

“汉字”原本是按照UTF-8格式保存的,要再提取出来当然没有任何问题了。

步骤6:重组字符串。

读取操作系统的编码格式(GBK),然后重新编码变量b的所有字节。问题就在这里产生了:因为UNICODE的存储格式是两个字节表示一个字符(注意这里是指UCS-2标准),虽然GBK也是2个字节表示一个字符,但两者之间没有影射关系,要想转换只能读取影射表,不能实现自动转换------于是JVM就按照默认的编码格式(GBK)读取了UNICODE的两个字节。

步骤7:输出乱码,程序运行结束。

问题清楚了,解决方案也随之产生了,方案有两个。

步骤8:修改代码。

明确指定编码即可,代码如下:

System.out.println(new String(b, "UTF-8"));
步骤9:修改操作系统的编码格式。

各个操作系统的修改方式不同,不再赘述。

我们可以把字符串读取字节的过程看作是数据传输的需要(比如网络、存储),再重组字符串则是业务逻辑的需要,这样就可使乱码现场重现,通过JDBC读取的字节数组是GBK的,而业务逻辑编码时采用的是UTF-8,于是乱码产生了。对于此类问题,最好的解决方案就是使用统一的编码格式,要么是GBK,要么是UTF-8,各个组件、接口、逻辑层都用UTF-8,拒绝独树一帜的情况。
问题清楚了,我们再来看一下代码“:

public static void main(String[] args) throws Exception{String str = “汉字”;//读取字节byte[] b = str.getBytes(“GB2312”);//重新生成一个新的字符串System.out.println(new String(b));}

仅仅修改了读取字节的编码格式(修改成了GB2312格式的),结果会是怎样的?又或者将其修改成GB18030,结果又是怎样的?结果都是“汉字”,不是乱码。哈哈!这是因为GB2312是中文字符集的V1.0版,GBK是V2.0版本,GB18030是V3.0版本,版本是向下兼容的,只是它们包含的汉字数量不同而已,注意,UNICODE可不在这个序列之中的。

1 0
原创粉丝点击