再谈Java程序相关字符编码

之前一篇关于Java编码的文章请见:http://www.liuzhaocn.com/?p=1166

 

可以简单的将与Java有关的字符编码分成两类

1、Java源文件及JVM编码。

2、关联系统传递给Java程序的字符编码。

谈到编码,基本上我们指的是字符编码,即人类可阅读的文字在计算机中的存储与显示,其他类型编码我不懂,就不讨论了。

 

先说第一种情况。Java源文件及JVM中,字符是怎么表示的。又分两种:

1.1Java文件保存编码。

1.2JVM虚拟机运行编码。

 

1.1

我们用eclipse或者notepad++或者vim写了一个.java源文件,将其保存的时候,可以选择ANSI,GBK,UTF-8等。

实际在硬盘存储的文件编码格式,是根据用户的选择,具有多样性。

 

 

1.2

Java编译器在对源文件编译前,首先会源文件转换为Unicode编码,然后再进行编译。

比如:javac Demo.java

默认采用操作系统的编码解码Demo.java,比如,我们将Demo.java按照UTF-8保存成文件,操作系统默认编码是GBK,则编译的时候就会报错。

这时候需要指定保存的.java文件的编码格式。用:javac -encoding UTF-8 Demo.java

编译之后的.class文件中的字符,都是Unicode编码(具体来说是UTF-16BE)。

 

2、

先说一个很基础的类:java.lang.String类。String类型在JVM中存储的是Unicode编码(UTF-16BE)。同理char类型也是(16位,2字节)。

错误的理解:

以前,我总以为String类是有不同的 编码格式的,比如这个String是UTF-8的,那个String是GBK的。

比如:

byte[] bytes=…;

String newStr = new String(bytes, “GB2312”);

以前总模糊的使用,总以为是将string设置为GB2312,或者意味着将字符串由GB2312转换成了源文件的保存格式(比如UTF-8)。

正确的理解:

给定的输入源bytes的编码格式是GB2312,用GB2312解码bytes,并转换成Unicode编码(具体说是UTF-16BE)。JDK文档里说的清楚:

通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于 byte 数组的长度。当给定 byte 在给定字符集中无效的情况下,抛出UnsupportedEncodingException异常。

跟Java程序关联的其他系统,向Java程序发送字符的时候,就有可能出现问题。

常见的关联情况有:前台表单填写、文件读取、数据库读取、SOCKET通信、其他关联等。

基本上都是IO操作,最终传过来的信息以字节数组byte[]的方式需要Java程序处理。以从数据库中读取文本为例。

ResultSet rs;
bytep[] bytes = rs.getBytes();
String str = new String(bytes, “gb2312”);

首先需要知道文本在数据库中存放的格式,在这里是GB2312,这样才能正确的将文本读取到str对象中。

有时候我们会碰到这种写法来处理乱码的问题:

str = new String(str.getBytes(“iso8859-1”), “gb2312”);

这是因为str之前用错误的iso8859-1进行了解码,用iso8859-1编码还原成原来的byte[],再用正确的gb2312进行解码。

再说一下char类型,char类型在Java中16位存储,2个字节,与UTF-16位数一致,所以char[]与String的效果是一样的。

版权声明:除标明转载的文章外皆为原创文章
转载请注明: 转载自Liudroid的博客,作者:Liudroid
本文链接地址: 再谈Java程序相关字符编码

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注