字符与编码(Java编码转换详细过程)

字符串在java内存中统一用unicode表示( 即utf-16 LE) , 不管是字符串字面量还是从文件中读取的,java使用unicode作为桥梁来处理各种编码的转换。


我们的java程序由.java的类文件组成,在这些类文件中都有可能包含中文字符串。并且我们常常需要和用户直接交互,用于输入和输出字符串。如:我们在jsp和servlet中得到客户端发送过来的字符串,这些字符串中包含中文字符。无论这些java类的作用如何,这些java程序的生命周期都是这样的:

1、编程人员在一定的操作系统上选择一个合适的编辑软件来编辑源文件,并以.java扩展名保存在操作系统中。

2、编程人员用JDK中的javac.exe来编译这些源代码,形成.class类(JSP文件是由容器调用JDK来编译的)。

3、直接运行这些类或将这些类布署到WEB容器中去运行,并输出结果。

那么,在这些过程中,JDK和JVM是如何将这些文件如何编码和解码并运行的呢?

这里,我们以中文win7操作系统为例说明JAVA类是如何来编码和被解码的。

1、我们用记事本软件编写一个Java源程序文件,程序文件在保存时默认采用了操作系统默认支持的GBK编码格式形成了一个.java文件,也即,java程序在被编译前,JAVA源程序文件是采用操作系统默认支持的。

2、我们用JDK的javac.exe文件编译我们的Java源程序,由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的JAVA源程序的编码格式,则javac.exe首先获得我们操作系统默认采用的编码格式,也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(它保存的就是操作系统默认的编码格式,如WIN2k,它的值为GBK),然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。

3、然后,javac把转换后的unicode格式的文件进行编译成.class类文件,此时.class文件是UNICODE编码的(包括里面的中文字符串),它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件(使用utf8编码方式编码)。对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.encoding格式转化为UNICODE格式了。

3.1、这一步中,对于JSP源程序文件是不同的,对于JSP,这个过程是这样的:即WEB容器调用JSP编译器,JSP编译器先查看JSP文件中是否设置有文件编码格式,如果JSP文件中没有设置JSP文件的编码格式,则JSP编译器调用JDK先把JSP文件用JVM默认的字符编码格式(也即WEB容器所在的操作系统的默认的file.encoding)转化为临时的Servlet类,然后再把它编译成UNICODE格式的class类,并保存在临时文件夹中。如:在中文win2k上,WEB容器就把JSP文件从GBK编码格式转化为UNICODE格式,然后编译成临时保存的Servlet类,以响应用户的请求。

4、运行第二步编译出来的类,分为三种情况: A、 直接在console上运行的类 B、 EJB类和不可以直接运行的支持类(如JavaBean类) C、 JSP代码和Servlet类。

4.1、直接在console上运行的类这种情况,运行该类首先需要JVM支持,即操作系统中必须安装有JRE。运行过程是这样的:首先java启动JVM,此时JVM读出操作系统中保存的class文件并把内容读入内存中,此时内存中为UNICODE格式的class类,然后JVM运行它,如果此时此类需要接收用户输入,则类会默认用file.encoding编码格式对用户输入的串进行编码并转化为unicode保存入内存(用户可以设置输入流的编码格式)。程序运行后,产生的字符串(UNICODE编码的)再回交给JVM,最后JRE把此字符串再转化为file.encoding格式(用户可以设置输出流的编码格式)传递给操作系统显示接口并输出到界面上。以上每一步的转化都需要正确的编码格式转化,才能最终不出现乱码现象。

4.2、EJB类和不可以直接运行的支持类(如JavaBean类) 由于EJB类和不可以直接运行的支持类,它们一般不与用户直接交互输入和输出,它们常常与其它的类进行交互输入和输出,所以它们在第二步被编译后,就形成了内容是UNICODE编码的类保存在操作系统中了,以后只要它与其它的类之间的交互在参数传递过程中没有丢失,则它就会正确的运行。

4.3、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编码发送到客户的浏览器上。

附录:

jsp 编译过程(以tomcat为例)

1、Tomcat 先将整个JSP页面的代码读取出来,写到一个新的JAVA文件中。在读取JSP文件时,tomcat会先去读取JSP文件的pageEncoding属性,然后按照pageEncoding指定的编码来读取JSP文件。如果pageEncoding没有指定,tomcat会使用contentType指定的字符集编码,如果contentType也没有指定,就使用默认的ISO-8859-1编码。

2、Tomcat读取完JSP文件后,会用UTF-8编码将这些内容写道一个新的Java文件中,然后编译。所以会在Tomcat的work文件类看到.jsp文件对应一个UTF编码副本文件。

3、当JSP文件显示的时候,会使用contentType中指定的MIME类型和charset。如果charset没有指定,就使用pageEncoding中指定的编码,如果pageEncoding也没有指定,就使用默认的ISO-8859-1编码。

时间: 2024-08-03 15:43:40

字符与编码(Java编码转换详细过程)的相关文章

Java编码与乱码问题

一.为什么要编码? 由于人类的语言太多,因而表示这些语言的符号太多,无法用计算机的一个基本的存储单元----byte来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解. byte一个字节即8个bit,所以能表示的字符范围是0~255个,这满足不了人类的需要,要解决这个矛盾必须需要一个新的数据结构char,从char到byte必须经过编码. 二.常用编码介绍 ASCII码 总共128个,用一个字节的低7位表示,0~31是控制字符,如换行.回车.删除等,32~126是打印字符,可以通过键盘

Java 编码与字符

一.字符集介绍 ANSI:American National Standards Institute.中文:美国国家标准学会 不同国家的和地区为此制定了不同标准,由此产生了 GB2312.GBK.Big5.Shift_JIS 等各自的编码标准.这些使用 1 至 4 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码.在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码:在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码. 不同 ANSI 编

Python常见字符编码间的转换

学习Python,字符编码间的转换是绕不过去的一只拦路虎,不把编码彻底搞明白,总有一天它会猝不及防坑你一把. Python2.x和Python3.x在字符编码的设置上也有很大区别(Python3未来将是主流,所以Python3为主),今天我们就来一起学习下. 上一篇文章里我已经简述了Python的常见编码了,这里就不再赘述了,还不清楚的小伙伴可以先去看下:     http://www.cnblogs.com/schut/p/8406897.html 一.Unicode 和 UTF-8的纠葛 U

java笔记--ASCII编码认知和转换

ASCII是基于拉丁字母的一套电脑编码系统,主要用于显示英语字符是当今最通用的单字节编码.包括128个字符. ASCII编码和字符的转换 代码: package com.xhj.data; import java.util.Scanner; /** * ASCII编码转换 * * @author XIEHEJUN * */public class ASCIIExchange { /** * ASCII编码转换成字符 * * @param number * @return */ public st

[Swift]字符串根据索引获取指定字符,依据ASCII编码实现字符和整数的快速转换

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言. 它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646. 请注意,ASCII是American Standard Code for Information Interchange缩写,而不是ASCⅡ(罗马数字2),有很多人在这个地方产生误解. 在Swift中实现:字符串根据索

字符,字节和编码

摘要:本文介绍了字符与编码的发展过程,相关概念的正确理解.举例说明了一些实际应用中,编码的实现方法.然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱码的办法.本文的内容涵盖了“中文问题”,“乱码问题”. 掌握编码问题的关键是正确地理解相关概念,编码所涉及的技术其实是很简单的.因此,阅读本文时需要慢读多想,多思考. 引言 “字符与编码”是一个被经常讨论的话题.即使这样,时常出现的乱码仍然困扰着大家.虽然我们有很多的办法可以用来消除乱码,但我们并不一定理解这些

java编码问题

工作中经常遇到java编码问题,由于缺乏研究,总是无法给出确切的答案,这个周末在网上查了一些资料,在此做些汇总. 问题一:在java中读取文件时应该采用什么编码? Java读取文件的方式总体可以分为两类:按字节读取和按字符读取.按字节读取就是采用InputStream.read()方法来读取字节,然后保存到一个byte[]数组中,最后经常用new String(byte[]);把字节数组转换成String.在最后一步隐藏了一个编码的细节,new String(byte[]);会使用操作系统默认的

Java编码问题汇总

转自 http://www.blogjava.net/zhangchao/archive/2011/05/26/351051.html Thanks Java编码问题汇总 工作中经常遇到java编码问题,由于缺乏研究,总是无法给出确切的答案,这个周末在网上查了一些资料,在此做些汇总. 问题一:在java中读取文件时应该采用什么编码? Java读取文件的方式总体可以分为两类:按字节读取和按字符读取.按字节读取就是采用InputStream.read()方法来读取字节,然后保存到一个byte[]数组

Java编码

转自:http://www.blogjava.net/zhangchao/archive/2011/05/26/351051.html Thanks Java编码问题汇总 工作中经常遇到java编码问题,由于缺乏研究,总是无法给出确切的答案,这个周末在网上查了一些资料,在此做些汇总. 问题一:在java中读取文件时应该采用什么编码? Java读取文件的方式总体可以分为两类:按字节读取和按字符读取.按字节读取就是采用InputStream.read()方法来读取字节,然后保存到一个byte[]数组