开发者社区> geekori> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Java编码问题解决方案大揭密

简介: 本文为原创,如需转载,请注明作者和出处,谢谢! 一、Java编码是怎么回事? 对于使用中文以及其他非拉丁语系语言的开发人员来说,经常会遇到字符集编码问题。
+关注继续查看
本文为原创如需转载请注明作者和出处谢谢

一、Java编码是怎么回事

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

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


class 中国
{
    
public String 雄起()
    {
         
return "中国雄起";
    }
}

中国 祖国 
= new 中国();
System.out.println(祖国.雄起());

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

class 수퍼맨
{
    
public void スーパーマン() {  }
}

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

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

二、Java编码转换

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

    先定义一个字符串变量

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

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

System.out.println(gbk);

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



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

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

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

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

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

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

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

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

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

String s = "
";

MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[0].ToString());

MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[1].ToString());

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

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

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

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

“中”的ucs2编码为2D4EGBK编码为D6D0

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

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

    当然感兴趣的读者也可以试试其他语言的编码如“人类”的韩语是“인간의”如下面的代码将输出“인간의”的cp949ucs2编码其中cp949是韩语的代码页。


String korean = "인간의"// 共三个韩文字符我们只测试第一个“인”

System.out.println(Integer.toHexString(
0xff & korean.getBytes("unicode")[2]));

System.out.println(Integer.toHexString(
0xff & korean.getBytes("unicode")[3]));

System.out.println(Integer.toHexString(
0xff & korean.getBytes("Cp949")[0]));

System.out.println(Integer.toHexString(
0xff & korean.getBytes("Cp949")[1]));

 

上面代码的输出结果如下

c7

78

c0

ce

    也就是说“”的ucs2编码为C778cp949的编码为C0CE要注意的是在cp949ucs2编码也有C0CE不要弄混了。读者可以访问下面的url来验证

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

Java支持的编码格式

三、属性文件

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

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

String name= ""u7528"u6237"u540d"u4e0d"u80fd"u4e3a"u7a7a" ;

System.out.println(name);

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


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

 

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


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

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

四、Web中的编码问题

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

 

<!--  main.jsp  -->

  
<%@ page language="java"  pageEncoding="utf-8"%>

  
<html>
      
<head>

      
</head>

      
<body>
          
<form action="servlet/MyPost" method="post">
              
<input type="text" name="user" />
              
<p/>
              
<input type="submit"  value="提交"/>
          
</form>

      
</body>
  
</html>


    下面是个Servlet

  package servlet;

  import java.io.IOException;
  import java.io.PrintWriter;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;

  
public class MyPost extends HttpServlet
  {

      
public void doPost(HttpServletRequest request, HttpServletResponse response)
              throws ServletException, IOException
      {
          String user 
= request.getParameter("user");
          System.
out.println(user);
      }
  }


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

    request.setCharacterEncoding("utf-8");

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

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


 

 



国内最棒的Google Android技术社区eoeandroid欢迎访问

《银河系列原创教程》发布

《Java Web开发速学宝典》出版欢迎定购

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里Java编码手册实战详解-OOP规约
阿里Java编码手册实战详解-OOP规约
43 0
阿里Java编码手册实战详解-命名规范篇
阿里Java编码手册实战详解-命名规范篇
199 0
阿里Java编码手册实战详解-集合处理篇
阿里Java编码手册实战详解-集合处理篇
40 0
Eclipse+Java+Swing实现学校教材管理系统
Eclipse+Java+Swing实现学校教材管理系统
42 0
Eclipse+Java+Swing实现学校教务管理系统(下)
Eclipse+Java+Swing实现学校教务管理系统
72 0
Eclipse+Java+Swing实现超市管理系统-TXT存储信息
Eclipse+Java+Swing实现超市管理系统-TXT存储信息
57 0
Java实现图片验证码
Java实现图片验证码
53 0
Java实现简易2编程1点比大小游戏。(玩家VS电脑)
Java实现简易21点比大小游戏。(玩家VS电脑)
34 0
+关注
geekori
欧瑞科技创始人&amp;CEO,东北大学计算机专业硕士,拥有超过20年软件开分经验。欧瑞学院金牌讲师、51CTO学院金牌讲师、CSDN学院特约讲师、畅销书作者,企业内训讲师。曾出版过超过30本IT畅销书,涉猎移动开发、跨平台开发、机器学习、区块链、大数据、编译器等领域。
419
文章
1
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载