一、Java编码是怎么回事?
对于使用中文以及其他非拉丁语系语言的开发人员来说,经常会遇到字符集编码问题。对于Java语言来说,在其内部使用的是UCS2编码(2个字节的Unicode编码)。这种编码并不属于某个语系的语言编码,它实际上是一种编码格式的世界语。在这个世界上所有可以在计算机中使用的语言都有对应的UCS2编码。
正是因为Java采用了UCS2,因此,在Java中可以使用世界上任何国家的语言来为变量名、方法名、类起名,如下面代码如下:
10 |
System.out.println(祖国.雄起()); |
哈哈,是不是有点象“中文编程”。实际上,也可以使用其他的语言来编程,如下面用韩文和日文来定义个类:
2 |
public void スーパーマン() { }
|
实际上,由于Java内部使用的是UCS2编码格式,因为,Java并不关心所使用的是哪种语言,而只要这种语言在UCS2中有定义就可以。
在UCS2编码中为不同国家的语言进行了分页,这个分页也叫“代码页”或“编码页”。中文根据包含中文字符的多少,分了很多代码页,如cp935、cp936等,然而,这些都是在UCS2中的代码页名,而对于操作系统来说,如微软的windows,一开始的中文编码为GB2312,后来扩展成了GBK。其实GBK和cp936是完全等效的,用它们哪个都行。
二、Java编码转换
上面说了这么多,在这一部分我们做一些编码转换,看看会发生什么事情。
先定义一个字符串变量:
用下面的语言输出一定会输出中文:
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字节,结果是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 ]);
|
3 |
System.out.println(gbk.getBytes( "unicode" )[ 3 ]);
|
前两个字节是标识位,要从第3个字节开始。还有就是其他的语言使用的编码的字节顺序可能不同,如在C#中可以使用下面的代码获得“中国“的UCS2编码:
3 |
MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[ 0 ].ToString());
|
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 ]));
|
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
当然,感兴趣的读者也可以试试其他语言的编码,如“人类”的韩语是“???”,如下面的代码将输出“???”的cp949和ucs2编码,其中cp949是韩语的代码页。
3 |
System.out.println(Integer.toHexString( 0xff & korean.getBytes( "unicode" )[ 2 ]));
|
5 |
System.out.println(Integer.toHexString( 0xff & korean.getBytes( "unicode" )[ 3 ]));
|
7 |
System.out.println(Integer.toHexString( 0xff & korean.getBytes( "Cp949" )[ 0 ]));
|
9 |
System.out.println(Integer.toHexString( 0xff & korean.getBytes( "Cp949" )[ 1 ]));
|
上面代码的输出结果如下:
c7
78
c0
ce
也就是说“?”的ucs2编码为C778,cp949的编码为C0CE,要注意的是,在cp949中,ucs2编码也有C0CE,不要弄混了。读者可以访问下面的url来验证:
http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT
http://www.bt285.cn/content.php?id=1196863
Java支持的编码格式
三、属性文件
Java中的属性文件只支持iso-8859-1编码格式,因此,要想在属性文件中保存中文,就必须使用UCS2编码格式("uxxxx),因此,出现了很多将这种编码转换成可视编码和工具,如Eclipse中的一些属性文件编辑插件。
实际上,"uxxxx编码格式在java和C#中都可以使用,如下面的语句所示:
1 |
String name= "" u7528 "u6237" u540d "u4e0d" u80fd "u4e3a" u7a7a" ;
|
3 |
System.out.println(name); |
上面代码将输出“用户名不能为空”的信息。将"uxxxx格式显示成中文非常简单,那么如何将中文还原成"uxxxxx格式呢?下面的代码完成了这个工作:
01 |
String ss = "用户名不能为空" ;
|
02 |
byte [] uncode = ss.getBytes( "Unicode" );
|
05 |
for ( int i= 2 ; i < uncode.length; i++)
|
07 |
if (i % 2 == 0 ) result += "\\u" ;
|
08 |
String abc = Integer.toHexString(x & uncode[i]);
|
09 |
result += abc.format( "%2s" , abc).replaceAll( " " , "0" );
|
11 |
System.out.println(result); |
上面的代码将输出如下结果:
\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a
好了,现在可以利用这个技术来实现一个属性文件编辑器了。
四、Web中的编码问题
大家碰到最多的编码问题就是在Web应用中。先让我们看看下面的程序:
03 |
<%@ page language="java" pageEncoding="utf-8"%>
|
11 |
< form action = "servlet/MyPost" method = "post" >
|
12 |
< input type = "text" name = "user" />
|
14 |
< input type = "submit" value = "提交" />
|
下面是个Servlet:
03 |
import java.io.IOException;
|
04 |
import java.io.PrintWriter;
|
05 |
import javax.servlet.ServletException;
|
06 |
import javax.servlet.http.HttpServlet;
|
07 |
import javax.servlet.http.HttpServletRequest;
|
08 |
import javax.servlet.http.HttpServletResponse;
|
10 |
public class MyPost extends HttpServlet
|
13 |
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
14 |
throws ServletException, IOException
|
16 |
String user = request.getParameter( "user" );
|
17 |
System.out.println(user);
|
如果中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格式。如下图:
相关推荐
"java中文乱码问题处理方案" java 中文乱码问题处理方案是 java 开发者... java 系统的中文问题解决方案包括使用 String 的字节码转换、对 J2EE 容器进行编码设置、将 java/J2EE 系统的统一编码定义为 UTF-8 等方法。
在Java开发中,生成Word文档是一项常见的需求,例如在报告生成、数据导出或合同制作等场景。...实际应用中,根据项目特性和需求选择合适的库,并灵活运用其提供的功能,就能实现Java生成Word文档的“完美解决方案”。
### Java反序列化回显解决方案 #### 前言 在信息安全领域,特别是渗透测试与安全研究中,Java反序列化漏洞是一个常见的攻击点。利用此类漏洞,攻击者可以执行远程代码(RCE),对系统造成严重影响。然而,通常情况...
本文主要研究了Java中中文编码问题,探讨了Java SE序的运行原理,分析了Java单机程序、在服务器上运行JSP、Servlets或EJB等产生中文乱码的原因,并提出了相应的解决方案。 一、Java中文编码问题的来源 Java程序...
本文将深入探讨Java Web的编码机制,JSP运行原理,以及如何解决常见的乱码问题。 首先,我们需要了解Java中的字符编码规则。Java默认采用ISO8859-1编码,这是针对西欧语言的标准编码,无法正确处理中文字符。为了...
在本课程"Java_我的代码解决方案Andrei Neagoies在线udemy课程掌握编码面试数据结构算法.zip"中,Andrei Neagoies旨在帮助学员深入理解并掌握编程面试中常见的数据结构和算法,以便在实际面试中脱颖而出。...
2. **提高问题解决能力**:遇到编程难题时,可以参考源码找到解决方案。 3. **优化代码**:学习专业程序员的编程习惯和技巧,提升代码质量。 4. **扩展知识面**:了解Java库的内部实现,有助于设计和选择合适的数据...
在IT领域,中文乱码问题是一个常见的困扰,尤其是在Web应用中。本文主要探讨了如何解决中文乱码问题,特别是涉及到浏览器、Servlet容器以及HTTP请求方式(GET和POST)...理解这些原理有助于更好地诊断和解决乱码问题。
这个案例涵盖了从需求分析、模型设计、编码实现到最终测试的完整过程,对于理解Hibernate的工作原理和实际应用场景非常有帮助。 #### 结论 综上所述,《很不错的Hibernate解决方案》不仅详细介绍了Hibernate框架的...
《Java_罗伯特·塞奇威克和凯文·韦恩的算法书中所有练习的解决方案》是一个包含详细解答的资源包,适用于那些正在学习或已经学习过由著名计算机科学家罗伯特·塞奇威克(Robert Sedgewick)和凯文·韦恩(Kevin ...
【标题】:“JAVA的视频会议服务器源码” 这个标题揭示了我们关注的...通过分析和学习这个Java视频会议服务器的源码,开发者可以深入理解这些技术的实际应用,提升自己的技能,并可能为自己的项目提供灵感或解决方案。
## 解决方案 阿里巴巴官方在发现该漏洞后,及时发布了修复版本,包括1.2.51和1.2.58。升级到这些新版本可以有效防止该漏洞的利用。推荐立即更新至最新稳定版,以确保系统的安全性。 除了升级版本,还有一些临时的...
总的来说,Base64编码在Java中是一个常见的需求,无论是官方API还是第三方库,都有成熟的解决方案。在实际开发中,建议优先使用Java标准库的`java.util.Base64`,因为它具有更好的兼容性和稳定性。对于需要兼容老...
Java设计模式是软件工程中的一种最佳实践,它提供了一套标准的解决方案,用于解决在编写可维护、可扩展和高效代码时经常遇到的问题。这些模式是经验丰富的开发人员在面对相似问题时经过反复验证和提炼得出的结果。在...
### POST和GET方法乱码解决方案 #### 前言 在Web开发中,中文乱码问题经常出现。这种现象主要是由于客户端(浏览器)与服务器之间的编码格式不一致导致的。通常情况下,浏览器发送数据时使用预设的编码格式,如UTF-...
本篇文章将深入探讨这个问题,并提出一种另类的解决方案——利用JNI(Java Native Interface)进行加密和解密操作来规避乱码问题。 首先,我们需要理解为什么会出现中文乱码。这通常与字符编码有关,Java和JSP默认...
以下是对这个问题的详细解析和解决方案: 1. **字符集概念**: - **ASCII**:7位字符集,包含128个字符,主要为英文字符。 - **ISO-8859-1**:扩展ASCII,增加了一些西欧语言的字符。 - **双字节字符集**:如GB...
3. **编程实现**:使用Java语言实现各个模块的功能,进行编码和调试。 4. **创新设计**:在满足基本要求的基础上,鼓励学生进行创新,例如使用虚函数、文件流、重载流插入运算符等高级特性。 5. **论文编写**:...
总的来说,百度aip-java-sdk-4.1.0为Java开发者提供了便利的OCR解决方案,无论是简单的通用文字识别,还是特定场景如身份证、银行卡等的识别,都能轻松应对。借助这个SDK,开发者可以构建出高效、精准的图像文字识别...
总的来说,解决JSP中文乱码问题的关键在于理解字符编码的工作原理,并在代码的各个层面保持一致。从源文件保存、编译、运行到与外部数据交互,都需要关注字符编码的设定,确保数据在转换过程中不丢失或变形。通过...