Java编码问题完全解决方案

本文深入探讨了Java中的编码问题,包括Java内部使用的UCS2编码原理、常见编码转换方法、属性文件中的编码处理以及Web应用中常见的编码问题解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 本文介绍了Java编码是怎么回事,以及一些中文编码的常见问题及解决方 案。对于Java语言来说,在其内部使用的是UCS2编码(2个字节的Unicode编码)。这种编码并不属于某个语系的语言编码,它实际上是一种编码格 式的世界语。

一、Java编码是怎么回事?

对于使用中文以及其他非拉丁语系语言的开发人员来说,经常会遇到字符集编码问题。对于Java语言来说,在其内部使用的是UCS2编码(2个字节的 Unicode编码)。这种编码并不属于某个语系的语言编码,它实际上是一种编码格式的世界语。在这个世界上所有可以在计算机中使用的语言都有对应的 UCS2编码。

正是因为Java采用了UCS2,因此,在Java中可以使用世界上任何国家的语言来为变量名、方法名、类起名,如下面代码如下:

 
  1. class  中国  
  2. {  
  3.      public  String 雄起()  
  4.     {  
  5.           return   "中国雄起" ;  
  6.     }  
  7. }  
  8.  
  9. 中国 祖国 =  new  中国();  
  10. System.out.println(祖国.雄起());  

哈哈,是不是有点象“中文编程”。实际上,也可以使用其他的语言来编程,如下面用韩文和日文来定义个类:

 
  1. class  수퍼맨  
  2. {  
  3.      public   void  スーパーマン() {  }  

实际上,由于Java内部使用的是UCS2编码格式,因为,Java并不关心所使用的是哪种语言,而只要这种语言在UCS2中有定义就可以。

在UCS2编码中为不同国家的语言进行了分页,这个分页也叫“代码页”或“编码页”。中文根据包含中文字符的多少,分了很多代码页,如cp935、 cp936等,然而,这些都是在UCS2中的代码页名,而对于操作系统来说,如微软的windows,一开始的中文编码为GB2312,后来扩展成了 GBK。其实GBK和cp936是完全等效的,用它们哪个都行。

二、Java编码转换

上面说了这么多,在这一部分我们做一些编码转换,看看会发生什么事情。

先定义一个字符串变量:

 
  1. String gbk =  "中国" // “中国”在Java内部是以UCS2格式保存的  

用下面的语言输出一定会输出中文:

 
  1. System.out.println(gbk); 

实现上,当我们从IDE输入“中国”时,用的是java源代码文件保存的格式,一般是GBK,有时也可是utf-8,而在Java编译程序时,会不 由分说地将所有的编码格式转换成utf-8编码,读者可以用UltraEdit或其他的二进制编辑器打开上面的“中国.class”,看看所生成的二进制 是否有utf-8的编码(utf-8和ucs2之间的转换非常容易,因为utf-8和ucs2之间是用公式进行转换的,而不是到代码页去查,这就相当于将 二进制转成16进制一样,4个字节一组)。如“中国”的utf-8编码按着GBK解析就是“涓  浗”。如下图所示。

utf-8编码按着GBK解析  

如果使用下面的语言可以获得“中国”的utf-8字节,结果是6(一个汉字由3个字节组成)

 
  1. System.out.println(gbk.getBytes("utf-8").length); 

下面的代码将输出“涓  浗”。

 
  1. System.out.println(new String(gbk.getBytes("utf-8"), "gbk"));     

由于将“中国“的utf-8编码格式按着gbk解析,所以会出现乱码。

如果要返回中文的UCS2编码,可以使用下面的代码:

 
  1. System.out.println(gbk.getBytes("unicode")[2]);  
  2.  
  3. System.out.println(gbk.getBytes("unicode")[3]);  

前两个字节是标识位,要从第3个字节开始。还有就是其他的语言使用的编码的字节顺序可能不同,如在C#中可以使用下面的代码获得“中国“的UCS2 编码:

 
  1. String s =  "中" ;  
  2.  
  3. MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[ 0 ].ToString());  
  4.  
  5. MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[ 1 ].ToString());  

使用上面的java代码获得的“中“的16进制UCS2编码为4E2D,而使用C#获得的相应的ucs2编码为2D4E,这只是C#和Java编码 内部使用的问题,并没有什么关系。但在C#和Java互操作时要注意这一点。

如果使用下面的java编码将获得16进制的“中”的GBK编码:

 
  1. System.out.println(Integer.toHexString(0xff & xyz.getBytes("gbk")[0]));  
  2.  
  3. System.out.println(Integer.toHexString(0xff & xyz.getBytes("gbk")[1]));  

“中”的ucs2编码为2D4E,GBK编码为D6D0

读者可访问如下的url自行查验:

http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT

三、Java编码相关的属性文件

Java中的属性文件只支持iso-8859-1编码格式,因此,要想在属性文件中保存中文,就必须使用UCS2编码格式("uxxxx),因此, 出现了很多将这种编码转换成可视编码和工具,如Eclipse中的一些属性文件编辑插件。

实际上,"uxxxx编码格式在java和C#中都可以使用,如下面的语句所示:

 
  1. String name=  "" u7528 "u6237" u540d "u4e0d" u80fd "u4e3a" u7a7a" ;  
  2.  
  3. System.out.println(name);  

上面代码将输出“用户名不能为空”的信息。将"uxxxx格式显示成中文非常简单,那么如何将中文还原成"uxxxxx格式呢?下面的代码完成了这 个工作:

 
  1. String ss =  "用户名不能为空" ;  
  2. byte [] uncode = ss.getBytes( "Unicode" );  
  3. int  x =  0xff ;  
  4. String result = "" ;  
  5. for ( int  i=  2 ; i <  uncode.length; i++)  
  6. {  
  7.      if (i %  2  ==  0 ) result +=  "//u" ;  
  8.     String abc = Integer.toHexString(x & uncode[i]);              
  9.     result += abc.format( "%2s" , abc).replaceAll( " " "0" );                 
  10. }  
  11. System.out.println(result); 

上面的代码将输出如下结果:

/u7528/u6237/u540d/u4e0d/u80fd/u4e3a/u7a7a

好了,现在可以利用这个技术来实现一个属性文件编辑器了。

四、Web中的Java编码问题

大家碰到最多的编码问题就是在Web应用中。先让我们看看下面的程序:

 
  1. <  !--  main.jsp  -- >  
  2.  
  3.    <  %@ page  language = "java"    pageEncoding = "utf-8" % >  
  4.  
  5.    <   html >  
  6.        <   head >  
  7.  
  8.        <  /head >  
  9.  
  10.        <   body >  
  11.            <   form   action = "servlet/MyPost"   method = "post" >  
  12.                <   input   type = "text"   name = "user"   />  
  13.                <   p />  
  14.                <   input   type = "submit"    value = "提交" />  
  15.            <  /form >  
  16.  
  17.        <  /body >  
  18.    <  /html >  

下面是个Servlet:

 
  1. package  servlet;  
  2.  
  3. import  java.io.IOException;  
  4. import  java.io.PrintWriter;  
  5. import  javax.servlet.ServletException;  
  6. import  javax.servlet.http.HttpServlet;  
  7. import  javax.servlet.http.HttpServletRequest;  
  8. import  javax.servlet.http.HttpServletResponse;  
  9.  
  10. public   class  MyPost  extends  HttpServlet  
  11. {  
  12.  
  13.      public   void  doPost(HttpServletRequest request, HttpServletResponse response)  
  14.              throws  ServletException, IOException  
  15.     {  
  16.         String user = request.getParameter( "user" );  
  17.         System.out.println(user);  
  18.     }  
  19. }  

如果中main.jsp中输入中文后,向MyPost提交,在控制台中会输出“中国”,一看就是乱码。如果将IE的当前编码设成其他的,如 由utf-8改为gbk,仍然会出现乱码,只是乱得不一样而已。这是因为客户端提交数据时是根据浏览器当前的编码格式来提交的,如浏览器当前为gbk编 码,就以gbk编码格式来提交。 这本身是不会出现乱码的,问题就出在Web服务器接收数据的时候,HttpServletRequest在将客户端传来的数据转成ucs2码上出了问题。 在默认情况下,是按着iso-8859-1编码格式来转的,而这种编码格式并不支持中文,所以也就无法正常显示中文了,解决这个问题的方法是用和客户端浏 览器当前编码格式一致的编码来转换,如果是utf-8,则在doPost方法中应该用以下的语句来处理:

 
  1. request.setCharacterEncoding( "utf-8" ); 

为了对每一个Servlet都起作用,可以将上面的语句加到filter里。

另外,我们一般使用象MyEclipse一样的IDE来编写jsp文件,这样的工具会根据pageEncoding属性将jsp文件保存成相应的编 码格式,但如果要使用象记事本一样的简单的编辑器来编写jsp文件,如果pageEncoding是utf-8,而在默认时,记事本会将文件保存成 iso-8859-1(ascii)格式,但在myeclipse里,如果文件中有中文,它是不允许我们保存成不支持中文的编码格式的,但记事本并不认识 jsp,因此,这时在ie中就无法正确显示出中文了。除非用记事本将其保存在utf-8格式。如下图:

用记事本将其保存在utf-8格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值