字符集合(ASCII、Unicode):由一套用于特定用途的字符组成,例如支持西欧语言的字符集合,支持中文的字符集合。字符集合只定义了符号和他们的语意,其实跟计算机没有直接关系。现实生活中,不一样的语系有本身的字符集合,例如藏文有本身的字符集合,汉文有本身的字符集合。到计算机的世界中,也有各类字符集合,例如ASCII字符集合,GB2312字符集合,GBK字符集合。还有一个其余字符集合的超集--Unicode字符集定义了几乎绝大部分现存语言须要的字符,是一种通用的字符集,来支持多语言环境(能够同时处理多种语言混合的状况)。各个国家和地区在制定编码标准的时候,“字符集合”和“字符编码”通常都是同时制定的。因此像ASCII字符集合同样,它也同时表明了一种字符的编码。html
字符编码:是一套规则,定义了在计算机内存中如何表示字符,是字符集中的每一个字符与计算机内存中字节之间的转换关系,也能够认为是把字符数字化,规定每一个“字符”分别用一个字节仍是多个字节存储,用哪些字节来存储。例如ASCII编码[你没看错,它既是一种字符集合,也是一种字符编码],定义了英文字母和符号在计算机中的表示方式,是用一个字节来表示。Unicode字符集合,有好几种字符编码方式,例如变长度编码的UTF8,UTF16等。中文字符集也有不少字符编码,例如上文提到的GB2312编码,GBK编码等。java
char、unicode、string和UTF八、UTF16之间的关系描述:Java语言内部使用的就是16位的Unicode编码,从概念上讲java字符串就是Unicode字符序列,Unicode字符集合的码点(码点:指与一个编码表中的某个字符对应的代码值)能够分红17个代码级别,第一个代码级别称为基本的多语言级别,码点从U+0000到U+FFFF,即65536个码点,只有第一级别的码点能够用一个char值表示;其他的16个级别码点从U+10000到U+10FFFF,其中包含一些辅助字符,须要两个char值才能表示一个码点;Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,二进制与16进制等能够灵活转换,只是数值的表示方式变化而已,其值的大小不变。网络
UTF八、UTF16即为采用什么样的规则表示全部的码点,在UTF16的编码规则中,UTF16采用不一样长度的编码表示全部的Unicode码点,在基本的多语言级别,每一个字符用16位表示,一般被称为代码单元;而辅助字符采用一对连续的代码单元进行编码。U+D800~U+DFFF为空闲的2048个替代区域,U+D800~U+DBFF用于第一个代码单元,U+DC00~U+DFFF用于第二个代码单元,这样的设计能够迅速的知道一个代码单元是一个字符的编码仍是一个辅助字符的第一或第二部分。
性能
咱们知道计算机其实挺笨的,它只认识0101这样的字符串,固然了咱们看这样的01串时确定会比较头晕的,因此不少时候为了描述简单都用十进制,十六进制,八进制表示.实际上都是等价的,没啥太多不同.其余啥文字图片之类的其余东东计算机不认识.那为了在计算机上表示这些信息就必须转换成一些数字.你确定不能想怎么转换就怎么转,必须得有定些规则.因而刚开始的时候就有ASCII字符集(American Standard Code for Information Interchange, "美国信息交换标准码),它使用7 bits来表示一个字符,总共表示128个字符,咱们通常都是用字节(byte,即8个01串)来做为基本单位.那么怎么当用一个字节来表示字符时第一个bit老是0,剩下的七个字节就来表示实际内容.后来IBM公司在此基础上进行了扩展,用8bit来表示一个字符,总共能够表示256个字符.也就是当第一个bit是0时仍表示以前那些经常使用的字符.当为1时就表示其余补充的字符.编码
英文字母再加一些其余标点字符之类的也不会超过256个.一个字节表示主足够了.但其余一些文字不止这么多 ,像汉字就上万个.因而又出现了其余各类字符集.这样不一样的字符集交换数据时就有问题了.可能你用某个数字表示字符A,但另外的字符集又是用另一个数字表示A.这样交互起来就麻烦了.因而就出现了Unicode和ISO这样的组织来统一制定一个标准,任何一个字符只对应一个肯定的数字.ISO取的名字叫UCS(Universal Character Set),Unicode取的名字就叫unicode了.spa
总结起来为啥须要Unicode就是为了适应全球化的发展,便于不一样语言之间的兼容交互,而ASCII再也不能胜任此任务了.操作系统
1.容易产生后歧义的两字节设计
unicode的第一个版本是用两个字节(16bit)来表示全部字符code
.实际上这么说容易让人产生歧义,咱们总以为两个字节就表明保存在计算机中时是两个字节.因而任何字符若是用unicode表示的话保存下来都占两个字节.其实这种说法是错误的.orm
其实Unicode涉及到两个步骤,首先是定义一个规范,给全部的字符指定一个惟一对应的数字,这彻底是数学问题,能够跟计算机没半毛钱关系.第二步才是怎么把字符对应的数字保存在计算机中,这才涉及到实际在计算机中占多少字节空间.
因此咱们也能够这样理解,Unicode是用0至65535之间的数字来表示全部字符.其中0至127这128个数字表示的字符仍然跟ASCII彻底同样.65536是2的16次方.这是第一步.第二步就是怎么把0至65535这些数字转化成01串保存到计算机中.这确定就有不一样的保存方式了.因而出现了UTF(unicode transformation format),有UTF-8,UTF-16.
2.UTF-8 与UTF-16的区别
UTF-16比较好理解,就是任何字符对应的数字都用两个字节来保存.咱们一般对Unicode的误解就是把Unicode与UTF-16等同了.可是很显然若是都是英文字母这作有点浪费.明明用一个字节能表示一个字符为啥整两个啊.
因而又有个UTF-8,这里的8很是容易误导人,8不是指一个字节,难道一个字节表示一个字符?实际上不是.当用UTF-8时表示一个字符是可变的,有多是用一个字节表示一个字符,也多是两个,三个..反正是根据字符对应的数字大小来肯定.
因而UTF-8和UTF-16的优劣很容易就看出来了.若是所有英文或英文与其余文字混合,但英文占绝大部分,用UTF-8就比UTF-16节省了不少空间.而若是所有是中文这样相似的字符或者混合字符中中文占绝大多数.UTF-16就占优点了,能够节省不少空间.另外还有个容错问题,等会再讲
看的有点晕了吧,举个例子.假如中文字"汉"对应的unicode是6C49(这是用十六进制表示,用十进制表示是27721为啥不用十进制表示呢?很明显用十六进制表示要短点.其实都是等价的没啥不同.就跟你说60分钟和1小时同样.).你可能会问当用程序打开一个文件时咱们怎么知道那是用的UTF-8仍是UTF-16啊.天然会有点啥标志,在文件的开头几个字节就是标志.
EF BB BF 表示UTF-8
FE FF 表示UTF-16.
用UTF-16表示"汉"
假如用UTF-16表示的话就是01101100 01001001(共16 bit,两个字节).程序解析的时候知道是UTF-16就把两个字节当成一个单元来解析.这个很简单.
用UTF-8表示"汉"
用UTF-8就有复杂点.由于此时程序是把一个字节一个字节的来读取,而后再根据字节中开头的bit标志来识别是该把1个仍是两个或三个字节作为一个单元来处理.
0xxxxxxx,若是是这样的01串,也就是以0开头后面是啥就不用管了XX表明任意bit.就表示把一个字节作为一个单元.就跟ASCII彻底同样.
110xxxxx 10xxxxxx.若是是这样的格式,则把两个字节当一个单元
1110xxxx 10xxxxxx 10xxxxxx 若是是这种格式则是三个字节当一个单元.
这是约定的规则.你用UTF-8来表示时必须遵照这样的规则.咱们知道UTF-16不须要用啥字符来作标志,因此两字节也就是2的16次能表示65536个字符.
而UTF-8因为里面有额外的标志信息,全部一个字节只能表示2的7次方128个字符,两个字节只能表示2的11次方2048个字符.而三个字节能表示2的16次方,65536个字符.
因为"汉"的编码27721大于2048了全部两个字节还不够,只能用三个字节来表示.
全部要用1110xxxx 10xxxxxx 10xxxxxx这种格式.把27721对应的二进制从左到右填充XXX符号(实际上不必定从左到右,也能够从右到左,这是涉及到另一个问题.等会说.
刚说到填充方式能够不同,因而就出现了Big-Endian,Little-Endian的术语.Big-Endian就是从左到右,Little-Endian是从右到左.
由上面咱们能够看出UTF-8在局部的字节错误(丢失、增长、改变)不会致使连锁性的错误,由于 UTF-8 的字符边界很容易检测出来,因此容错性较高。
Unicode版本2
前面说的都是unicode的第一个版本.但65536显然不算太多的数字,用它来表示经常使用的字符是没一点问题.足够了,但若是加上不少特殊的就也不够了.因而从1996年开始又来了第二个版本.用四个字节表示全部字符.这样就出现了UTF-8,UTF16,UTF-32.原理和以前确定是彻底同样的,UTF-32就是把全部的字符都用32bit也就是4个字节来表示.而后UTF-8,UTF-16就视状况而定了.UTF-8能够选择1至8个字节中的任一个来表示.而UTF-16只能是选两字节或四字节..因为unicode版本2的原理彻底是同样的,就很少说了.
前面说了要知道具体是哪一种编码方式,须要判断文本开头的标志,下面是全部编码对应的开头标志
EF BB BF UTF-8
FE FF UTF-16/UCS-2, little endian
FF FE UTF-16/UCS-2, big endian
FF FE 00 00 UTF-32/UCS-4, little endian.
00 00 FE FF UTF-32/UCS-4, big-endian.
其中的UCS就是前面说的ISO制定的标准,和Unicode是彻底同样的,只不过名字不同.ucs-2对应utf-16,ucs-4对应UTF-32.UTF-8是没有对应的UCS