Java中的字符编码

在平常开发中,常常会遇到关于编码的问题,让人总有种弄不清的感受,此次我就整理一下,以便本身复习和你们分享,文中若有错误请及时指正。网络

ASCII编码

先说说编码的由来,它的由来再简单不过了,为了让计算机存储字符。你们知道计算机底层的处理只有二进制,也就是0和1。在没有计算机的时候,人们使 用8个晶体管来表示状态和动做,怎么表示呢?也就是说,每一个晶体管能够亮或者灭,也就是0和1,根据8个晶体管不一样的亮灭组合来表示不一样的意思。那么根据 数学知识能够知道,一共有256种组合方式(2的8次方)。编码

这256种表示一开始并无所有被使用完,只使用了一部分(32个,表示各类状态),随着计算机的出现和发展,很快剩下的位置也开始被占用,用来表 示空格、标点符号、数字、大小写字符等,一共使用了127个位置,这127个位置所组成的字符对应表,就称为ANSII编码表(American Standard Code for Information Interchange,美国信息互换标准代码)。简单来讲,ANSII是最原始的计算机编码表,表示了西方人使用的几乎全部的经常使用字符。spa

扩展字符集

扩展字符集仍是ASCII编码表中的,也就是256-127剩下的哪些位置,这些位置存储了一些更加有意思的字符,好比横线、竖线交叉等等,也就是扩展后的ASCII码表.net

GB2312编码表

很明显,随着世界上愈来愈多的人使用计算机,而本来的ASCII编码表已经没有位置了,那么中国就推出了本身的编码表,将6000多个经常使用汉字编了 进去。不过对ASCII编码表作了一些修改:小于127的字符意义与ANSII编码表同样,把扩展字符集所有舍弃,两个大于127的字符连在一块儿时,就表 示一个汉字。这样就能够组合出7000多个汉字,而且还加入了数学符号、罗马希腊的字母、日文等等,这张码表,就是GB2312编码表。简单来 说,GB2312编码表就是ANSII编码的中文扩展码表。code

GBK编码

不过很快,这张GB2312编码表也不够用了,毕竟只有7000多个汉字,而后就继续扩展,加入了20000多个汉字和符号,就造成了GBK编码表,GBK包含GB2312的全部编码orm

GB18030

接着,少数民族的文字也加入了进来,就造成了GB18030编码表开发

DBCS(Double Byte Charecter Set 双字节字符集)

以上关于中文的这些编码表,被统称为DBCS,在DBCS系列标准里,最大的特色是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案 里,所以程序为了支持中文处理,必需要注意字串里的每个字节的值,若是这个值是大于127的,那么就认为一个双字节字符集里的字符出现了,占两个字节, 而小于127的,占一个字节。get

Unicode

相似中国,全世界的各个国家都开始编写本身语言的码表,这样就造成了一个混乱的编码时代,因而乎,就有人要解决这个问题,这个组织就是ISO (国际标谁化组织)。他们的办法很简单,废除全部现存编码,从新编纂了一套编码,这套编码包含全世界全部的字符,这就是Unicode编码表的由来。为了 兼容各类字符,规定,Unicode编码中不论中文英文仍是别的什么文,每一个字符占用两个字节。可是问题也来了,在制定Unicode编码的时候,没有考 虑到跟已有任何一种编码兼容,这使得同一个汉字可能在不一样码表表示的不同,也就是乱码问题的由来。没有一种简单的算术方法能够把文本内容从 UNICODE编码和另外一种编码进行转换,这种转换必须经过查表来进行。数学

如前所述,UNICODE 是用两个字节来表示为一个字符,他总共能够组合出65535不一样的字符,这大概已经能够覆盖世界上全部文化的符号。若是还不够也没有关系,ISO已经准备 了UCS-4方案,说简单了就是四个字节来表示一个字符,这样咱们就能够组合出21亿个不一样的字符出来。io

UTF-8

什么是UTF-8呢?简单来讲,UTF-8是一种Unicode编码表的存储方式和传输标准。它是为了解决网络传输Unicode编码而诞生的。来看一张UTF-8实现Unicode存储的对照表:
UTF-8对照表
从图中看出,UTF-8编码实现所占用的字节数是不肯定的,1到6位都有可能。其实4个字节就几乎能够表示全世界的字符了,因此5个字节和6个字节的那种表示方法被停用了。

并且ISO也为之后作了准备了,指定了UCS-4方案,说简单了就是四个字节来表示一个字符,这样咱们就能够组合出21亿个不一样的字符出来。

中文到底占几个字节?

这个问题常常被问到,我是这样理解的,这个答案要分状况。若是是DBCS那一套编码,那么中文占两个字节,若是是UTF-8编码,中文占3个字节或 4个字节,至于究竟是3个仍是4个,要看你给的中文在上面那张图的哪一个区间段中,不一样的区间段对应的UTF-8格式不同,致使告终果的不一致。

到这里就差很少了,至于著名的“联通”乱码问题我这里很少说了,开发平时也用不上,有兴趣的能够度娘。

说了这么多,可能有些混淆了,这里有个问题,Unicode规定每一个字符占两个字节,那么UTF-8编码中算几个呢,中文、英文都分别在不一样编码下占几个字节?

关于这个问题,仍是那句话,要分状况,下面用程序来验证,这是最清楚的方式了:

1 String testStr = "abc";
2 String testCh = "你";
3 System.out.println("GBK编码:英文长度" + testStr.getBytes("GBK").length);
4 System.out.println("GBK编码:中文长度" + testCh.getBytes("GBK").length);
5 System.out.println("UTF-8编码:英文长度" + testStr.getBytes("UTF-8").length);
6 System.out.println("UTF-8编码:中文长度" + testCh.getBytes("UTF-8").length);
7 System.out.println("Unicode编码:英文长度" + testStr.getBytes("Unicode").length);
8 System.out.println("Unicode编码:中文长度" + testCh.getBytes("Unicode").length);

如下为输入结果:
运行结果
这 个结果GBK与UTF-8的没有疑问,Unicode这个结果有点意外,为何"abc"三个字符会占8位呢?这个是由于若是你指定要用Unicode来 编码,Java其实使用的是UTF-16LE来处理,简单来讲,就是这是UTF-16编码的结果,那么为何是8位呢?由于在UTF-16中,不论是中英 日美仍是什么文,每一个字符都占两个字节,那么"abc"就是6个字节,而为了通讯,UTF-16须要在字符前面加标识,这个标识叫BOM头,这个不用管, 只要知道,要加2个字节,因此6 + 2 = 8,就是8个字节,而中文"你"占2个字节,再加上BOM头,就是4个字节。那么就记住,UTF-16中,每一个字符占两个字节,总的字符长度 = 字符个数 * 2 + 2,就能够了。好比中文"你好”,在UTF-16编码下占6个字节。

总结一下:

  • 一个英文字符在DBCS编码体系中,占一个字节,在UTF-8中占1个字节,在UTF-16中占2个字节,可是在UTF-16计算字节数时,要 注意,是总的字符数的两倍,再加上BOM头的两个字节。在Unicode表中,占两个字节。Java是基于Unicode编码的,因此其实Java中的字 符都是两个字节,可是因为编码实现不同,如UTF-8,因此要分清楚这几种状况。

  • 一个中文字符在DBCS编码体系总,占两个字节,在UTF-8中占3到4个字节(中文在Unicode表中对应的数字从3个字节的格式开始),在UTF-16中占2个字节,一样在UTF-16计算字节数时,要注意,是总的字符数的两倍,再加上BOM头的两个字节。

                分享到:

相关文章
相关标签/搜索