前面三篇博客侧重介绍字符、编码问题,通过这三篇博客各位博友对各种字符编码有了一个初步的了解,要了解 java 的中文问题这是必须要了解的。但是了解这些仅仅只是一个开始,以下博客将侧重介绍 java 乱码是如何产生的、存在哪些乱码的情况、该如何从根本上解决乱码问题。各位随博主一起征服令人厌烦的 java 乱码问题吧!!!
我们总是用一个 java 类文件和用户进行最直接的交互(输入、输出),这些交互内容包含的文字可能会包含中文。无论这些 java 类是与数据库交互,还是与前端页面交互,他们的生命周期总是这样的:
1、程序员在操作系统上通过编辑器编写程序代码并且以. java 的格式保存操作系统中,这些文件我们称之为源文件。
2、通过 JDK 中的 javac.exe 编译这些源文件形成. class 类。
3、直接运行这些类或者部署在 WEB 容器中运行,得到输出结果。
这些过程是从宏观上面来观察的,了解这个肯定是不行的,我们需要真正来了解 java 是如何来编码和被解码的:
第一步:当我们用编辑器编写 java 源文件,程序文件在保存时会采用操作系统默认的编码格式(一般我们中文的操作系统采用的是 GBK 编码格式)形成一个. java 文件。java 源文件是采用操作系统默认支持的 file.encoding 编码格式保存的。下面代码可以查看系统的 file.encoding 参数值。
1
|
System.out.println(System.getProperty(
"file.encoding"
));
|
第二步:当我们使用 javac.exe 编译我们的 java 文件时,JDK 首先会确认它的编译参数 encoding 来确定源代码字符集,如果我们不指定该编译参数,JDK 首先会获取操作系统默认的 file.encoding 参数,然后 JDK 就会把我们编写的 java 源程序从 file.encoding 编码格式转化为 JAVA 内部默认的 UNICODE 格式放入内存中。
第三步:JDK 将上面编译好的且保存在内存中信息写入 class 文件中,形成. class 文件。此时. class 文件是 Unicode 编码的,也就是说我们常见的. class 文件中的内容无论是中文字符还是英文字符,他们都已经转换为 Unicode 编码格式了。
在这一步中对对 JSP 源文件的处理方式有点儿不同:WEB 容器调用 JSP 编译器,JSP 编译器首先会查看 JSP 文件是否设置了文件编码格式,如果没有设置则 JSP 编译器会调用调用 JDK 采用默认的编码方式将 JSP 文件转化为临时的 servlet 类,然后再编译为. class 文件并保持到临时文件夹中。
第四步:运行编译的类:在这里会存在一下几种情况
1、直接在 console 上运行。
2、JSP/Servlet 类。
3、java 类与数据库之间。
这三种情况每种情况的方式都会不同,
这种情况下,JVM 首先会把保存在操作系统中的 class 文件读入到内存中,这个时候内存中 class 文件编码格式为 Unicode,然后 JVM 运行它。如果需要用户输入信息,则会采用 file.encoding 编码格式对用户输入的信息进行编码同时转换为 Unicode 编码格式保存到内存中。程序运行后,将产生的结果再转化为 file.encoding 格式返回给操作系统并输出到界面去。整个流程如下:
在上面整个流程中,凡是涉及的编码转换都不能出现错误,否则将会产生乱码。
由于 JSP 文件最终也会转换为 servlet 文件(只不过存储的位置不同而已),所以这里我们也将 JSP 文件纳入其中。
当用户请求 Servlet 时,WEB 容器会调用它的 JVM 来运行 Servlet。首先 JVM 会把 servlet 的 class 加载到内存中去,内存中的 servlet 代码是 Unicode 编码格式的。然后 JVM 在内存中运行该 Servlet,在运行过程中如果需要接受从客户端传递过来的数据(如表单和 URL 传递的数据),则 WEB 容器会接受传入的数据,在接收过程中如果程序设定了传入参数的的编码则采用设定的编码格式,如果没有设置则采用默认的 ISO-8859-1 编码格式,接收的数据后 JVM 会将这些数据进行编码格式转换为 Unicode 并且存入到内存中。运行 Servlet 后产生输出结果,同时这些输出结果的编码格式仍然为 Unicode。紧接着 WEB 容器会将产生的 Unicode 编码格式的字符串直接发送置客户端,如果程序指定了输出时的编码格式,则按照指定的编码格式输出到浏览器,否则采用默认的 ISO-8859-1 编码格式。整个过程流程图如下:
我们知道 java 程序与数据库的连接都是通过 JDBC 驱动程序来连接的,而 JDBC 驱动程序默认的是 ISO-8859-1 编码格式的,也就是说我们通过 java 程序向数据库传递数据时,JDBC 首先会将 Unicode 编码格式的数据转换为 ISO-8859-1 的编码格式,然后在存储在数据库中,即在数据库保存数据时,默认格式为 ISO-8859-1。