1110xxxx(E0-EF) 10yyyyyy 10zzzzzz,我们从低位开始补起,不够的用0补齐。
1110
0100 10
111000 10
101101 ,换成16进制为E4 B8 AD。
好了我们用java代码来验证下,是否正确。
public static void main(String[] args) {
String ha = "中";
byte b[] = null;
try {
b = ha.getBytes("utf-8");
} catch (Exception e) {
System.exit(-1);
}
for (int i = 0; i < b.length; i++) {
System.out.print(Integer.toHexString(b[i]).substring(6) + " ");
}
}
输出果然是:e4 b8 ad。
utf8 wiki中有下描述:
- 对于UTF-8编码中的任意字节B,如果B的第一位为0,则B为ASCII码,并且B独立的表示一个字符;
- 如果B的第一位为1,第二位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的一个字节,并且不为字符的第一个字节编码;
- 如果B的前两位为1,第三位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由两个字节表示;
- 如果B的前三位为1,第四位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由三个字节表示;
- 如果B的前四位为1,第五位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由四个字节表示;
因此,对UTF-8编码中的任意字节,根据第一位,可判断是否为ASCII字符;根据前二位,可判断该字节是否为一个字符编码的第一个字节; 根据前四位(如果前两位均为1),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;根据前五位(如果前四位为1),可判断编码 是否有错误或数据传输过程中是否有错误。
反过来,我们还是拿刚才的”中“为例,1110
0100 10
111000 10
101101 ,第一个字节开始为110,则读第二个字节为10,第三个字节为10,则认为是utf8字符。
于是就有了一个那个经典的“联通"干不过”移动“的经典段子。
我们在xp下,随便建立一个文件,输入"联通",保存,这时你在打开是,发现”联通"2个字符不见了。奇怪吗??????
我们知道默认保存的编码是ANSI,实际也是类GBK的编码。
对应16进制为c1 aa cd a8, 转化成二进制为11000001 10101010 11001101 10101000 ,我们来看,110xxxxx,10xxxxxx 正好符合utf8的形式。
这时候文件编写器以为你的文件是utf8的文件,然后默认已utf8的形式给你打开展示。于是就出现乱码了。如果你在”联通“后面随便加几个字符。就不出出现灵异事件了。
那么我们继续讨论 GBK和Unicode是什么关系呢?
实际上GBK我们可以看做是字符集,他也有自己一一对应的码表。google一下,很容易查到。这里有个Unicode和GBk对应的表
Unicode-GBk。
在java中,
"我爱你莎莎".getBytes("gbk");
进行转化,其实就是类似查一个Unicode和GBk对应表进行转化的。大家看一下Charset这个抽象类的那些子类就明白了。
通过上面的描述GBk和UTF8关系也就很明朗了,完全可以通过Unicode进行中转。
同事在询问编码的问题时,一开始对类似如下代码,相互转变不太理解。
byte b1[] = null;
b1 = "我爱你莎莎".getBytes("gbk");
System.out.println(new String(b1,"gbk"));
byte b2[] = null;
b2 = "我爱你莎莎".getBytes("utf8");
System.out.println(new String(b2,"utf8"));
System.out.println(new String (new String (b2,"gbk").getBytes("gbk"),"utf8"));
其实我们可以把getBytes("gbk"),这个函数当做将unicode用gkb加密的过程,而new String(”xxx“,"编码”)看成是解密的一个过程。
大家思考一下最后面的那个输出可以得到正确的结果吗?为什么?
下面我们来讨论 ,通过http协议下的url传输后,编码转化问题。
首先说明的是本人本地默认编码是gbk。
我们只用Servlet,不使用任何框架比如spring(因为使用框架时,框架也有一套自己自己的机制)如下代码
public class HttpEncode extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str = req.getQueryString();
System.out.println(req.getCharacterEncoding());
String encode = null;
try {
encode = req.getParameter("encode");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(str);
System.out.println(encode);
}
}
我们分别用jetty(版本6.1)和resin(版本3.1.8)下容器,测试如下请求 127.0.0.1/test?encode=%B9%FE 其中%B9%FE为GBk的编码的汉字”哈“
jetty容器下输出为
resin下为:
null
encode=%B9%FE
null
换做127.0.0.1/test?encode=%E5%93%88 ,utf8编码的”哈“
jetty和resin下都输出如下
null
encode=%E5%93%88
哈
为什么会是这样?
我们拿jetty分析,在jetty的源码中,
public String getParameter(String name)
{
if (!_paramsExtracted)
extractParameters();
return (String) _parameters.getValue(name, 0);
}
对应的
extractParameters(); 部分代码
if (_queryEncoding==null)
_uri.decodeQueryTo(_baseParameters);
然后
public void decodeQueryTo(MultiMap parameters)
{
if (_query==_fragment)
return;
_utf8b.reset();
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters,_utf8b);
}
也就是如果
_queryEncoding为null时,默认是用utf8进行解码的。而resin也不例外。
jetty中
_queryEncoding的值可以通过org.mortbay.jetty.Request.queryEncoding 这个属性给赋值而resin采用的是req.getCharacterEncoding()中的值为标准。
要想在jetty下 127.0.0.1/test?encode=%B9%FE,获取到正确的字符,代码如下
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str = req.getQueryString();
System.out.println(req.getCharacterEncoding());
req.setAttribute("org.mortbay.jetty.Request.queryEncoding", "gbk");
String encode = null;
try {
encode = req.getParameter("encode");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(str);
System.out.println(encode);
}
resin下只需要
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str = req.getQueryString();
req.setCharacterEncoding("gbk");
System.out.println(req.getCharacterEncoding());
String encode = null;
try {
encode = req.getParameter("encode");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(str);
System.out.println(encode);
}
通过上面想说明的是,不同的容器,默认编码的策略是不一致的。只要我们了解编码的基础知识。通过一些封装就很容易掌控这个局面。
相关推荐
Java编码标准是软件开发中的一项重要规范,它旨在提高代码质量、可读性以及团队间的协作效率。这份PDF文档很可能是Oracle公司或者一些知名的Java社区制定的编程规范,旨在为Java开发者提供一套统一的编码指南。以下...
阿里巴巴java编码规范 ,Java 并发编程培训(阿里巴巴) 《阿里巴巴Java开发手册》,首次公开阿里官方Java代码规范标准。这套Java统一规范标准将有助于提高行业编码规范化水平,帮助行业人员提高开发质量和效率、大大...
华为JAVA编码规范.pdf 华为JAVA编码规范.pdf是华为公司编写的JAVA编程语言编码规范,旨在提供一个统一的编程风格和代码组织方式,以提高代码的可读性、维护性和可重用性。该规范涵盖了编程语言的基本结构、命名规则...
腾讯 Java 编码规范 腾讯 Java 编码规范是腾讯集团管理标准的一部分,旨在确保公司项目代码的易维护性和编码安全性。该规范涵盖了 Java 编码风格、文件组织、代码风格、注释、命名、声明、异常、习惯等方面。 一、...
Java 编码规范 Java 编码规范是指在 Java 语言中编写代码时需要遵守的一些约定和规则,以确保代码的可读性、可维护性和可扩展性。本文将对 Java 编码规范的主要内容进行详细讲解。 命名风格是 Java 编码规范的重要...
"java编码规范考试题答案" 一、Java编码规范考试题答案 本文档涵盖了Java编码规范的各种方面,包括集合类、线程、对称密码算法、异常处理、命名规范、随机数生成、压缩文件解压、安全编程规范、操作系统登录用户名...
《阿里巴巴 Java 编码指南》是业界广泛采用的编码规范,旨在提高代码质量和开发效率,尤其对于使用 IntelliJ IDEA 的开发者来说,此指南的兼容性更新至 2023.3+ 版本,确保了最新的开发环境支持。这份指南在 2024 年...
Java编码规范是软件开发中非常重要的一个环节,它旨在提高代码质量、可读性、可维护性和团队协作效率。这份文档,"Java编码规范.doc",由东软集团有限公司的商用软件事业部编写,包含了国内大型Java项目和国际知名...
【标题】:“Java编码总结1”主要涉及到Java编程语言中的编码问题,这在软件开发中是至关重要的。编码问题往往会导致程序出现难以预料的错误,尤其是处理多国语言或者特殊字符时。Java作为广泛使用的跨平台语言,其...
**百度Java编码规范** 在软件开发中,遵循一定的编码规范是非常重要的,它能提高代码的可读性,便于团队协作,降低维护成本。百度作为一家技术驱动的公司,也提出了其内部使用的Java编码规范,旨在确保代码的一致性...
JAVA 编码规范试题 JAVA 编码规范试题是一套涵盖了 JAVA 编程规范的试题,旨在帮助开发者掌握 JAVA 编程的基本规范和best practice。该试题涵盖了 JAVA 编程规范的多个方面,包括变量命名、代码格式、异常处理、...
本文将深入探讨“js解码”和“java编码”这两个主题,并结合标签“源码”和“工具”,讨论如何在实际项目中应用它们。 首先,我们来看JavaScript中的解码。JavaScript是一种在客户端和服务器端都能运行的脚本语言,...
Java 编码规范是开发团队遵循的一套标准,旨在提高代码质量、可读性和可维护性。这份规范涵盖了多个方面,包括文件命名、命名规范、Java 文件样式、代码编写格式以及编程技巧和性能优化等。 1. **前言** - 简介:...
Java编码规范(Java Coding Standard) oiNSFT-BS-OT0105 V3.0 2005-5-11 东软集团有限公司 商用软件事业部 版权所有 中国 沈阳浑南高新技术产业开发区 东软软件园
JAVA编码规范培训
"java编码规范(华为)" Java编码规范是华为公司为Java语言编程提供的规范性文档,旨在提高编程的规范化和专业化。本规范涵盖了Java语言编程的各个方面,包括排版、注释、命名、编码和JTEST规则和建议。 1. 范围 ...