由于Java编程中的中文问题是一个老生常谈的问题,在阅读了许多关于Java中文问题解决方法之后,结合作者的编程实践,我发现过去谈的许多方法都不能清晰地说明问题及解决问题,尤其是跨平台时的中文问题。 于是我给出此篇文章,内容包括对控制台运行的class、Servelets、JSP及EJB类中的中文问题我剖析和建议解决办法。希望大家指教。
Abstract:本文深入分析了Java程序设计中Java编译器对Java源文件和JVM对class类文件的编码/解码过程,通过此过程的解析透视出了Java编程中中文问题产生的根本原因,最后给出了建议的最优化的解决Java中文问题的方法。
1、中文问题的来源
计算机最初的操作系统支持的编码是单字节的字符编码,于是,在计算机中一切处理程序最初都是以单字节编码的英文为准进行处理。
随着计算机的发展,为了适应世界其它民族的语言(当然包括我们的汉字),人们提出了UNICODE编码,它采用双字节编码,兼容英文字符和其它民族的双字节字符编码,所以,目前,大多数国际性的软件内部均采用UNICODE编码,在软件运行时,它获得本地支持系统(多数时间是操作系统)默认支持的编码格式,然后再将软件内部的UNICODE转化为本地系统默认支持的格式显示出来。
Java的JDK和JVM即是如此,我这里说的JDK是指国际版的JDK,我们大多数程序员使用的是国际化的JDK版本,以下所有的JDK均指国际化的JDK版本。我们的汉字是双字节编码语言,为了能让计算机处理中文,我们自己制定的gb2312、GBK、GBK2K等标准以适应计算机处理的需求。
所以,大部分的操作系统为了适应我们处理中文的需求,均定制有中文操作系统,它们采用的是GBK,GB2312编码格式以正确显示我们的汉字。如:中文Windows默认采用的是GBK编码显示,在中文 Windows2000中保存文件时默认采用的保存文件的编码格式也是GBK的,即所有在中文Windows2000中保存的文件它的内部编码默认均采用 GBK编码,注意:GBK是在GB2312基础上扩充来的。
由于Java语言内部采用UNICODE编码,所以在Java程序运行时,就存在着一个从UNICODE编码和对应的操作系统及浏览器支持的编码格式转换输入、输出的问题,这个转换过程有着一系列的步骤,如果其中任何一步出错,则显示出来的汉字就会出是乱码,这就是我们常见的Java中文问题。
同时,Java是一个跨平台的编程语言,也即我们编写的程序不仅能在中文 windows上运行,也能在中文Linux等系统上运行,同时也要求能在英文等系统上运行(我们经常看到有人把在中文Windows2000上编写的 Java程序,移植到英文Linux上运行)。这种移植操作也会带来中文问题。
还有,有人使用英文的操作系统和英文的IE等浏览器,来运行带中文字符的程序和浏览中文网页,它们本身就不支持中文,也会带来中文问题。
几乎所有的浏览器默认在传递参数时都是以UTF-8编码格式来传递,而不是按中文编码传递,所以,传递中文参数时也会有问题,从而带来乱码现象。
总之,以上几个方面是Java中的中文问题的主要来源,我们把以上原因造成的程序不能正确运行而产生的问题称作:Java中文问题。
2、Java编码转换的详细过程
我们常见的Java程序包括以下类别:
*直接在console上运行的类(包括可视化界面的类)
*JSP代码类(注:JSP是Servlets类的变型)
*Servelets类
*EJB类
*其它不可以直接运行的支持类
这些类文件中,都有可能含有中文字符串,并且我们常用前三类Java程序和用户直接交互,用于输出和输入字符,如:我们在JSP和Servlet中得到客户端送来的字符,这些字符也包括中文字符。无论这些Java类的作用如何,这些Java程序的生命周期都是这样的:
*编程人员在一定的操作系统上选择一个合适的编辑软件来实现源程序代码并以.Java扩展名保存在操作系统中,例如我们在中文Windows2000中用记事本编辑一个Java源程序。
*编程人员用JDK中的Javac.exe来编译这些源代码,形成.class类(JSP文件是由容器调用JDK来编译的)。
*直接运行这些类或将这些类布署到WEB容器中去运行,并输出结果。
那么,在这些过程中,JDK和JVM是如何将这些文件如何编码和解码并运行的呢?
这里,我们以中文Windows2000操作系统为例说明Java类是如何来编码和被解码的。
第一步,我们在中文Windows2000中用编辑软件如记事本编写一个Java源程序文件(包括以上五类Java程序),程序文件在保存时默认采用了操作系统默认支持GBK编码格式(操作系统默认支持的格式为file.encoding格式)形成了一个.Java文件,也即,Java程序在被编译前,我们的Java源程序文件是采用操作系统默认支持的file.encoding编码格式保存的,Java源程序中含有中文信息字符和英文程序代码;要查看系统的file.encoding参数,可以用以下代码:
public class ShowSystemDefaultEncoding
{
public static void main(String[] args)
{
String encoding =
System.getProperty("file.encoding");
System.out.println(encoding);
}
}
第二步,我们用JDK的Javac.exe文件编译我们的Java源程序,由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的Java源程序的编码格式,则Javac.exe首先获得我们操作系统默认采用的编码格式,也即在编译Java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(它保存的就是操作系统默认的编码格式,如Windows2000,它的值为 GBK),然后JDK就把我们的Java源程序从file.encoding编码格式转化为Java内部默认的UNICODE格式放入内存中。
然后,Javac把转换后的unicode格式的文件进行编译成.class类文件,此时.class文件是UNICODE编码的,它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件。
对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.encoding格式转化为UNICODE格式了。
这一步中,对于JSP源程序文件是不同的,对于JSP,这个过程是这样的:即WEB容器调用JSP编译器,JSP编译器先查看JSP文件中是否设置有文件编码格式,如果JSP文件中没有设置JSP文件的编码格式,则JSP编译器调用JDK先把JSP文件用JVM默认的字符编码格式(也即WEB容器所在的操作系统的默认的file.encoding)转化为临时的Servlet类,然后再把它编译成UNICODE格式的class类,并保存在临时文件夹中。
如:在中文Windows2000上,WEB容器就把JSP文件从GBK编码格式转化为UNICODE格式,然后编译成临时保存的Servlet类,以响应用户的请求。
第三步,运行第二步编译出来的类,分为三种情况:
A、 直接在console上运行的类
B、 EJB类和不可以直接运行的支持类(如JavaBean类)
C、 JSP代码和Servlet类
D、 Java程序和数据库之间
下面我们分这四种情况来看。
A、直接在console上运行的类
这种情况,运行该类首先需要JVM支持,即操作系统中必须安装有JRE。运行过程是这样的:首先Java启动JVM,此时JVM读出操作系统中保存的 class文件并把内容读入内存中,此时内存中为UNICODE格式的class类,然后JVM运行它,如果此时此类需要接收用户输入,则类会默认用 file.encoding编码格式对用户输入的串进行编码并转化为unicode保存入内存(用户可以设置输入流的编码格式)。
程序运行后,产生的字符串(UNICODE编码的)再回交给JVM,最后JRE把此字符串再转化为file.encoding格式(用户可以设置输出流的编码格式)传递给操作系统显示接口并输出到界面上。以上每一步的转化都需要正确的编码格式转化,才能最终不出现乱码现象。 B、EJB类和不可以直接运行的支持类(如JavaBean类)
由于EJB类和不可以直接运行的支持类,它们一般不与用户直接交互输入和输出,它们常常与其它的类进行交互输入和输出,所以它们在第二步被编译后,就形成了内容是UNICODE编码的类保存在操作系统中了,以后只要它与其它的类之间的交互在参数传递过程中没有丢失,则它就会正确的运行。
C、JSP代码和Servlet类
经过第二步后,JSP文件也被转化为Servlets类文件,只不过它不像标准的Servlets一校存在于classes目录中,它存在于WEB容器的临时目录中,故这一步中我们也把它做为Servlets来看。
对于Servlets,客户端请求它时,WEB容器调用它的JVM来运行Servlet,首先,JVM把Servlet的class类从系统中读出并装入内存中,内存中是以UNICODE编码的Servlet类的代码,然后JVM在内存中运行该Servlet类,如果Servlet在运行的过程中,需要接受从客户端传来的字符如:表单输入的值和URL中传入的值,此时如果程序中没有设定接受参数时采用的编码格式,则WEB容器会默认采用ISO- 8859-1编码格式来接受传入的值并在JVM中转化为UNICODE格式的保存在WEB容器的内存中。
Servlet运行后生成输出,输出的字符串是UNICODE格式的,紧接着,容器将Servlet运行产生的UNICODE格式的串(如html语法,用户输出的串等)直接发送到客户端浏览器上并输出给用户,如果此时指定了发送时输出的编码格式,则按指定的编码格式输出到浏览器上,如果没有指定,则默认按ISO-8859-1编码发送到客户的浏览器上。
分享到:
相关推荐
### Java中文问题及最优解决方法 #### 背景与挑战 在开发过程中,使用Java进行编程时,中文字符的处理一直是开发者面临的一个难题。由于Java本身的编码方式、不同操作系统之间的编码差异以及运行环境的不同,可能...
### JAVA中文问题解析和最优解决办法 #### 一、引言 随着信息技术的快速发展与全球化进程的加速,软件开发越来越需要支持多语言环境,特别是中文环境。Java作为一门跨平台的编程语言,广泛应用于Web应用、企业级...
Java编程中的中文问题主要源于字符编码的不匹配和转换过程中的错误。计算机早期主要使用单字节编码,如ASCII,但随着多语言需求的增加,Unicode编码应运而生,它支持双字节编码,包括英文和其他语言。Java JDK和JVM...
### Java遗传算法寻找最优路径 #### 一、遗传算法概览 遗传算法(Genetic Algorithm, GA)是一种基于自然选择和遗传学原理的全局优化技术。它通过模拟自然界中的生物进化过程来解决优化问题,包括搜索空间较大的...
### JSP中文乱码问题最优解决方法 在Web开发中,特别是使用Java Server Pages(JSP)进行网页设计时,中文乱码问题是一个常见的技术挑战。本文将详细探讨如何有效地解决JSP页面中的中文乱码问题,并提供具体的解决...
通过具体实例,展示了如何使用动态规划解决此类问题,并给出了详细的代码实现及逻辑解析。这种方法不仅能够找到从起点到各个节点的最短路径,还能提供到达这些最短路径时的决策路径,对于理解和应用最短路径问题具有...
### 解析Java虚拟机器开发:权衡优化、高效和安全的最优方案 #### Java虚拟机(JVM)概览 Java虚拟机(JVM)是一种能够执行编译后的Java字节码的虚拟机环境。它提供了运行Java应用程序所需的基础平台,并且在设计上...
使用工具如VisualVM、JConsole和JProfiler进行性能监控,发现和解决瓶颈问题。分析CPU、内存和线程状态,可以帮助定位优化点。 7. **最新技术趋势** 随着JDK版本更新,新的JVM特性不断推出,如Project Panama的本...
《数据结构与算法经典问题解析 Java语言描述》第二版是一本深入探讨计算机科学核心领域的书籍,专注于使用Java语言来阐述和实现数据结构和算法。这本书是程序员和计算机科学学生的宝贵资源,因为它涵盖了从基础到...
"tsp的项目 旅行商最优路线 java源码+ATT48.txt+eil51.txt" 这个标题表明我们正在探讨一个关于旅行商问题(Traveling Salesman Problem,简称TSP)的项目。旅行商问题是运筹学中的一个经典问题,目标是寻找最短的...
这本书“数据结构与算法经典问题解析-Java语言描述”旨在帮助读者深入理解这些概念,并通过具体的Java代码实现来提升解决实际问题的能力。 1. **数据结构**: - **数组**:是最基本的数据结构,它是一系列相同类型...
标签“TSP JAVA 仿真算法 神经网络算法”提供了关键信息点,TSP是核心问题,JAVA是实现的语言,而仿真算法和神经网络算法是解决问题的方法。 ** Hopfield神经网络算法详解:** Hopfield神经网络是一种能量函数递减...
《Java解惑中文版》是一本专为Java程序员设计的指南,旨在帮助读者解决在编程过程中遇到的各种问题,提升程序的健壮性。本书深入浅出地探讨了Java语言的核心概念、常见疑惑以及最佳实践,旨在使开发者能够编写出更...
以下是对贪心法求解着色问题的详细解析。 ### 贪心算法原理 贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。在解决着色问题时,贪心策略...
Java的23种设计模式是软件工程中非常重要的概念,它们是解决常见编程问题的成熟解决方案,被广泛应用于各种复杂的软件开发中。设计模式不是具体的代码或库,而是一种通用的、可重用的设计方案,它描述了在特定上下文...
在这个“java常见算法题解析大全”中,你将找到一系列涵盖不同难度级别的算法问题,旨在帮助Java开发者提升技能,增强解决问题的能力。 首先,让我们了解一下折半查找(Binary Search)算法。这是一种在有序数组中...