给出如下结论:
在Class输出字符串前,会将Unicode的字符串按照某一种内码重新生成字节流,然后把字节流输入,相当于进行了一步“String.getBytes(???)”操作。???代表某一种字符集。
如果是Servlet,那么,这种内码就是在HttpServletResponse.setContentType()方法中指定的内码,也就是上文定义的<Servlet-charset>。
如果是JSP,那么,这种内码就是在<%@ page contentType=""%>中指定的内码,也就是上文定义的<Jsp-charset>。
如果是Java程序,那么,这种内码就是file.encoding中指定的内码,默认为ISO8859-1。
当输出对象是浏览器时
以流行的浏览器IE为例。IE支持多种内码。假如IE接收到了一个字节流“D6 D0 CE C4”,你可以尝试用各种内码去查看。你会发现用“简体中文”时能得到正确的结果。因为“D6 D0 CE C4”本来就是简体中文中“中文”两个字的编码。
OK,完整地看一遍。
JSP:源文件为GB2312格式的文本文件,且JSP源文件中有“中文”这两个汉字
如果指定了<Jsp-charset>为GB2312,转化过程如下表。
表4 Jsp-charset = GB2312时的变化过程
| 序号 | 步骤说明 | 结果 |
| 1 | 编写JSP源文件,且存为GB2312格式 | D6 D0 CE C4 (D6D0=中 CEC4=文) |
| 2 | jspc把JSP源文件转化为临时JAVA文件,并把字符串按照GB2312映射到Unicode,并用UTF格式写入JAVA文件中 | E4 B8 AD E6 96 87 |
| 3 | 把临时JAVA文件编译成CLASS文件 | E4 B8 AD E6 96 87 |
| 4 | 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 | 4E 2D 65 87(在Unicode中4E2D=中 6587=文) |
| 5 | 根据Jsp-charset=GB2312把Unicode转化为字节流 | D6 D0 CE C4 |
| 6 | 把字节流输出到IE中,并设置IE的编码为GB2312(作者按:这个信息隐藏在HTTP头中) | D6 D0 CE C4 |
| 7 | IE用“简体中文”查看结果 | “中文”(正确显示) |
| 序号 | 步骤说明 | 结果 |
| 1 | 编写JSP源文件,且存为GB2312格式 | D6 D0 CE C4 (D6D0=中 CEC4=文) |
| 2 | jspc把JSP源文件转化为临时JAVA文件,并把字符串按照ISO8859-1映射到Unicode,并用UTF格式写入JAVA文件中 | C3 96 C3 90 C3 8E C3 84 |
| 3 | 把临时JAVA文件编译成CLASS文件 | C3 96 C3 90 C3 8E C3 84 |
| 4 | 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 | 00 D6 00 D0 00 CE 00 C4 (啥都不是!!!) |
| 5 | 根据Jsp-charset=ISO8859-1把Unicode转化为字节流 | D6 D0 CE C4 |
| 6 | 把字节流输出到IE中,并设置IE的编码为ISO8859-1(作者按:这个信息隐藏在HTTP头中) | D6 D0 CE C4 |
| 7 | IE用“西欧字符”查看结果 | 乱码,其实是四个ASCII字符,但由于大于128,所以显示出来的怪模怪样 |
| 8 | 改变IE的页面编码为“简体中文” | “中文”(正确显示) |
| 序号 | 步骤说明 | 结果 |
| 1 | 编写JSP源文件,且存为GB2312格式 | D6 D0 CE C4 (D6D0=中 CEC4=文) |
| 2 | jspc把JSP源文件转化为临时JAVA文件,并把字符串按照ISO8859-1映射到Unicode,并用UTF格式写入JAVA文件中 | C3 96 C3 90 C3 8E C3 84 |
| 3 | 把临时JAVA文件编译成CLASS文件 | C3 96 C3 90 C3 8E C3 84 |
| 4 | 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 | 00 D6 00 D0 00 CE 00 C4 |
| 5 | 根据Jsp-charset=ISO8859-1把Unicode转化为字节流 | D6 D0 CE C4 |
| 6 | 把字节流输出到IE中 | D6 D0 CE C4 |
| 7 | IE用发出请求时的页面的编码查看结果 | 视情况而定。如果是简体中文,则能正确显示,否则,需执行表5中的第8步 |
| 序号 | 步骤说明 | 结果 |
| 1 | 编写Servlet源文件,且存为GB2312格式 | D6 D0 CE C4 (D6D0=中 CEC4=文) |
| 2 | 用javac –encoding GB2312把JAVA源文件编译成CLASS文件 | E4 B8 AD E6 96 87 (UTF) |
| 3 | 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 | 4E 2D 65 87 (Unicode) |
| 4 | 根据Servlet-charset=GB2312把Unicode转化为字节流 | D6 D0 CE C4 (GB2312) |
| 5 | 把字节流输出到IE中并设置IE的编码属性为Servlet-charset=GB2312 | D6 D0 CE C4 (GB2312) |
| 6 | IE用“简体中文”查看结果 | “中文”(正确显示) |
| 序号 | 步骤说明 | 结果 |
| 1 | 编写Servlet源文件,且存为GB2312格式 | D6 D0 CE C4 (D6D0=中 CEC4=文) |
| 2 | 用javac –encoding ISO8859-1把JAVA源文件编译成CLASS文件 | C3 96 C3 90 C3 8E C3 84 (UTF) |
| 3 | 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 | 00 D6 00 D0 00 CE 00 C4 |
| 4 | 根据Servlet-charset=ISO8859-1把Unicode转化为字节流 | D6 D0 CE C4 |
| 5 | 把字节流输出到IE中并设置IE的编码属性为Servlet-charset=ISO8859-1 | D6 D0 CE C4 (GB2312) |
| 6 | IE用“西欧字符”查看结果 | 乱码(原因同表5) |
| 7 | 改变IE的页面编码为“简体中文” | “中文”(正确显示) |
| 序号 | 步骤说明 | 结果 | 域 |
| 1 | 在IE中输入“中文” | D6 D0 CE C4 | IE |
| 2 | IE把字符串转变成UTF,并送入传输流中 | E4 B8 AD E6 96 87 | |
| 3 | Servlet接收到输入流,用readUTF读取 | 4E 2D 65 87(unicode) | Servlet |
| 4 | 编程者在Servlet中必须把字符串根据GB2312还原为字节流 | D6 D0 CE C4 | |
| 5 | 编程者根据数据库内码ISO8859-1生成新的字符串 | 00 D6 00 D0 00 CE 00 C4 | |
| 6 | 把新生成的字符串提交给JDBC | 00 D6 00 D0 00 CE 00 C4 | |
| 7 | JDBC检测到数据库内码为ISO8859-1 | 00 D6 00 D0 00 CE 00 C4 | JDBC |
| 8 | JDBC把接收到的字符串按照ISO8859-1生成字节流 | D6 D0 CE C4 | |
| 9 | JDBC把字节流写入数据库中 | D6 D0 CE C4 | |
| 10 | 完成数据存储工作 | D6 D0 CE C4 数据库 | |
|
以下是从数据库中取出数的过程 | |||
| 11 | JDBC从数据库中取出字节流 | D6 D0 CE C4 | JDBC |
| 12 | JDBC按照数据库的字符集ISO8859-1生成字符串,并提交给Servlet | 00 D6 00 D0 00 CE 00 C4 (Unicode) | |
| 13 | Servlet获得字符串 | 00 D6 00 D0 00 CE 00 C4 (Unicode) | Servlet |
| 14 | 编程者必须根据数据库的内码ISO8859-1还原成原始字节流 | D6 D0 CE C4 | |
| 15 | 编程者必须根据客户端字符集GB2312生成新的字符串 | 4E 2D 65 87 (Unicode) |
|
|
Servlet准备把字符串输出到客户端 | |||
| 16 | Servlet根据<Servlet-charset>生成字节流 | D6D0 CE C4 | Servlet |
| 17 | Servlet把字节流输出到IE中,如果已指定<Servlet-charset>,还会设置IE的编码为<Servlet-charset> | D6 D0 CE C4 | |
| 18 | IE根据指定的编码或默认编码查看结果 | “中文”(正确显示) | IE |