1、引言java
平常复习总结,发现过久不看基础,不少概念的东西仍是给忘了,本文将教你如何快速区分“字符”与“字符集”。windows
2、基础知识数组
各类文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。 也就是说,它是一个信息单位,一个数字是一个字符,一个文字是一个字符,一个标点符号也是一个字符。tomcat
字节是一个8bit的存储单元,取值范围是0x00~0xFF。 根据字符编码的不一样,一个字符能够是单个字节的,也能够是多个字节的。jvm
字符的集合就叫字符集。不一样集合支持的字符范围天然也不同,譬如ASCII只支持英文,GB18030支持中文等等。编码
在字符集中,有一个码表的存在,每个字符在各自的字符集中对应着一个惟一的码。可是同一个字符在不一样字符集中的码是不同的,譬如字符“中”在Unicode和GB18030中就分别对应着不一样的码(20013
与54992
)。spa
简单来讲,字符集就是一个按规则排列的字符的集合,能够理解为现实生活中的各类“字典”。例如:牛津字典,剑桥商务字典等等。同一个“单词”在不一样的字典中的位置是不一样的,同理也不是全部的字典都支持各类语言的,例如ASCLL字符集里面就没有中文。code
定义字符集中的字符如何编码为特定的二进制数,以便在计算机中存储(就是将字符在字符集中的对应位置化为二进制)。字符集和字符编码通常一一对应(也有例外)blog
字符集与字符编码的一个例外就是Unicode字符集,它有多种编码实现(UTF-8,UTF-16,UTF-32等)内存
3、举例理解
其实经过上面的标蓝的句子相信你们已经有了区分的理解。下面再举出一些例子,来加深你们的理解:
ASCII码是一个字符集,同时它的实现也只有一种,所以它也能够指代这个字符集对应的字符编码。
GB18030是一个字符集,主要是中国人为了解决中文而发明制定的,因为它的实现也只有一种,因此它也能够指代这个字符集对应的字符编码。
Unicode是一个字符集(java默认),为了解决不一样字符集码表不一致而推出的,统一了全部字符对应的码,所以在这个规范下,全部字符对应的码都是一致的(统一码),可是统一码只规定了字符与码表的一一对应关系,却没有规定该如何实现,所以这个字符集有多种实现方式(UTF-8,UTF-18,UTF-32),所以这些实现就是对应的字符编码。 也就是说,Unicode统一约定了字符与码表直接一一对应的关系,而UTF-8是Unicode字符集的一种字符编码实现方式,它规定了字符该如何编码成二进制,存储在计算机中。
附:经常使用编码表
ISO8859-1 | GBK/GBK2312 | UTF-8 | UTF-16 | UTF-32 | |
英文字符 | 1字节 | 2字节 | 大部分3,少部分4 | 2字节 | 4字节 |
中文字符 | 1字节 | 1字节 | 1字节 | 2字节 | 4字节 |
如表所示,ISO8859-一、utf-1六、utf-32都是定长字符编码,其中utf-16(Unicode)更是jvm默认的内码编码。
内码 vs 外码
java在内部都是unicode编码,不存在什么GBK/UTF-8只有在输入输出的时候,才会发生与外部的编码转化问题。
简单来讲,内码:char或String在内存里使用的编码方式。
外码:除了内码均可以认为是“外码”。(包括class文件的编码)
java内码:unicode(utf-16)
jvm默认外码:windows——gbk
Linux——utf-8
外码操做:
[String].getBytes() 就是将内码转换成外码存储在byte数组里,方法有两种形式:
getBytes(String charsetName): 使用指定的字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
getBytes(): 使用平台的默认字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
new String(byte[] bytes, String charset): 将字符序列bytes使用“charset”的字符编码(外码),解码成字符串(内码)。
编码和解码的“字符编码”必需要一致才能解码成想要的字符串(英文例外)。
可是为何在tomcat 下,使用 new String(s.getBytes("iso-8859-1") ,"GBK") 却能够用呢? 答案是:
tomcat 默认使用iso-8859-1编码, 也就是说,若是本来字符串 str 是GBK的,tomcat传输过程当中,将GBK转成iso-8859-1编码的字符数组了,至关于:
String s = "中国";
byte[] str_bytes = s.getBytes("GBK"); // 底层操做1:jvm,此时编码格式为gbk; String s = new String(str_bytes, "iso-8859-1"); // 底层操做2:tomcat; String str_new =new String(s.getBytes( "iso-8859-1"), "gbk"); // 获得正确字符串
默认状况下,使用iso-8859-1读取中文确定是有问题的,那么咱们须要将iso-8859-1 再转成GBK, 而iso-8859-1 是单字节编码的,即他认为一个字节是一个字符, 那么这种转换不会对原来的字节数组作任何改变,由于字节数组原本就是由单个字节组成的,若是以前用GBK编码,那么转成iso-8859-1后编码内容彻底没变, 则 s.getBytes("iso-8859-1") 实际上仍是原来GBK的编码内容则 new String(s.getBytes("iso-8859-1") ,"GBK") 就能够正确解码了。 因此说这是一种特殊状况。