一.为什么要编码?
1.在计算机中存储信息的最小单元是1字节,即8个bit,所以能表示的字符范围是0~255个.
2.人类要表示的符号太多,无法用1个字节来完全表示.
这就是矛盾,要解决这个矛盾,就出现了一种新的数据结构char,而从char到byte必须编码.
二.几种编码格式
1.ASCII码
学计算机的不知道ASCII,我擦,那你Low爆了.总共有128个,用1个字节的低7位表示,0~31是控制字符如换行,回车,删除等,32~126是打印字符,可通过键盘输入并且能够显示出来.
2.ISO-8859-1
很显然,128个字符是不够用的,于是ISO组织制定了一系列标准来扩展ASCII编码,它们兄弟比较多,ISO-8859-1到ISO-8859-15,老大还是老大,其中ISO-8859-1人家就比较牛,掌握了大多数西欧语言字符,应用最广泛.但是ISO-8859-1仍然是单字节编码,总共能表示256个字符.
3.GB2312
知道全称吗?好吧我也不知道.全称<信息技术中文编码字符集>,它是双字节编码,总编码范围是A1~F7,其中A1~A9是符号区,总共包含682个符号;B0~F7是汉子区,包含6763个汉子.
4.GBK
搞数据库的一定接触过GBK,全称<汉字内码扩展规范>,为扩展GB2312而出生,并加入更多汉字.编码范围8140~FEFE(去掉XX7F),总共有23940个码位,能表示21003个汉字,和GB2312兼容,所以GB2312编码,可以用GBK解码,不会出现乱码.
5.GB18030
全称也是<信息技术中文编码字符集>,是咱们国家的强制标准,它可能是单字节,双字节或者四字节编码,与GB2312兼容,虽说是国家标准,实际系统应用并不广泛.
6.UTF-16
UTF-16定义了Unicode字符在计算机中的存取方法,用两个字节表示Unicode的转化格式,采用定长的表示方法.两个字节是16个bit,所以叫UTF-16.它表示字符非常方便,每两个字节表示一个字符,这就大大简化了字符串的操作.这也是Java以UTF-16作为内存的字符存储格式的很重要的原因.
7.UTF-8
UTF-16虽然简单好用,但是用两个字节,存储空间放大了1倍,并且采用顺序编码,不能对单个字符的编码值进行校验.而UTF-8采用变长技术(好像char与varchar),每个编码区域有不同的字码长度,不同类型的字符可以由1~6个字节组成.单字节范围内的字符采用1个字节表示,对汉字则采用3个字节表示.
三.Java中的编码场景.
1.在I/O操作中需要编码
编码一般涉及到从字节到字符,或从字符到字节,这种转换场景主要是I/O(网络IO,磁盘IO)
Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到字符的转换,而具体字节到字符的解码实现它由 StreamDecoder 去实现,在 StreamDecoder 解码过程中必须由用户指定 Charset 编码格式。值得注意的是如果你没有指定 Charset,将使用本地环境中的默认字符集,例如在中文环境中将使用 GBK 编码.
写也是类似滴,字符的父类是 Writer,字节的父类是 OutputStream,通过 OutputStreamWriter 转换字符到字节.看图:
应用程序中涉及到 I/O 操作时只要注意指定统一的编解码 Charset 字符集,一般不会出现乱码问题,有些应用程序如果不注意指定字符编码,中文环境中取操作系统默认编码,如果编解码都在中文环境中,通常也没问题,但是还是强烈的不建议使用操作系统的默认编码,因为这样,你的应用程序的编码格式就和运行环境绑定起来了,在跨环境下很可能出现乱码问题.
2.在内存操作中需要编码
String类提供了从字符到字节的方法.
String str = "我是中文字符";
byte[] b = str.getBytes("UTF-8");
String ns= new String(s,"UTF-8");
只要设置编码格式统一,则一般情况下就不会出现乱码.