------- android培训、java培训、期待与您交流! ----------
java专题系列之2-字符编码
在讨论编码之前,我们得知道什么是编码表?
我们写一篇日志,并将其存入本地硬盘,是将字符存入硬盘吗?不是,因为计算机只能识别二进制数据,也就是0101之类的二进制数据,这时候就需要通过查询一张表,然后对应字符的二进制数据
存入硬盘,这张表我们就将其称为编码表.常见的编码表有
ASCII 老美的码表,使用一个字节的七位表示
ISO8859-1 欧洲的码表,使用一个字节的全部八位表示
GB2312 汉字的码表,使用两个字节表示
GBK GB2312的扩展,支持更多的汉字,包括简体字和繁体字,GBK 和 GB2312向下兼容ASCII
UNICODE 两个字节表示一个字符,Unicode只与ASCII兼容(更准确地说,是与ISO8859-1兼容),与GB码不兼容(两个字节想表示全世界所有的文字明显不可能吗?老美脑子秀逗了吗)
UTF-8 UTF-8是一种8位的unicode字符集,编码长度是可变的
关于unicode和utf-8的关系,从网上copy下来的
最初的unicode编码是固定长度的,16位,也就是2两个字节代表一个字符,这样一共可以表示65536个字符。显然,这样要表示各种语言中所有的字符是远远不够的。
Unicode4.0规范考虑到了这种情况,定义了一组附加字符编码,附加字符编码采用2个16位来表示,这样最多可以定义1048576个附加字符,目前unicode4.0只定义了45960个附加字符。
Unicode只是一个编码规范,目前实际实现的unicode编码只要有三种:UTF-8,UCS-2和UTF-16,三种unicode字符集之间可以按照规范进行转换。
UTF-8是一种8位的unicode字符集,编码长度是可变的,并且是ASCII字符集的严格超集,也就是说ASCII中每个字符的编码在UTF-8中是完全一样的。
UTF-8字符集中,一个字符可能是1个字节,2个字节,3个字节或者4个字节长。一般来说,欧洲的字母字符长度为1到2个字节,
而亚洲的大部分字符则是3个字节,附加字符为4个字节长。
Unix平台中普遍支持UTF-8字符集,HTML和大多数浏览器也支持UTF-8,而window和java则支持UCS-2。
UTF-8的主要优点:
对于欧洲字母字符需要较少的存储空间。
容易从ASCII字符集向UTF-8迁移。
'\u0001' 到 '\u007F' 范围内的所有字符都是用单个字节表示的:
位值
字节 1 0 位 6-0
null 字符 '\u0000' 以及从 '\u0080' 到 '\u07FF' 的范围内的字符用两个字节表示:
位值
字节 1 1 1 0 位 10-6
字节 2 1 0 位 5-0
'\u0800' 到 '\uFFFF' 范围内的 char 值用三个字节表示:
位值
字节 1 1 1 1 0 位 15-12
字节 2 1 0 位 11-6
字节 3 1 0 位 5-0
实例1
import java.util.Arrays;
public class TestEncode1 {
public static void main(String[] args) throws Exception {
String s = "你好";
byte[] b1 = s.getBytes();
String s1 = Arrays.toString(b1);
System.out.println(s1);
byte[] b2 = s.getBytes("gbk");
String s2 = Arrays.toString(b2);
System.out.println(s2);
}
}
从打印的数字来看,java使用的就是GBK编码
实例2
import java.util.Arrays;
public class TestEncode2 {
public static void main(String[] args) throws Exception {
String s = "你好";
//String s = "a你好";
byte[] b1 = s.getBytes("gbk");
String s1 = Arrays.toString(b1);
System.out.println(s1);
byte[] b2 = s.getBytes("utf-8");
String s2 = Arrays.toString(b2);
System.out.println(s2);
}
}
打印的结果是
[-60, -29, -70, -61]
[-28, -67, -96, -27, -91, -67]
从打印的结果来看gbk码表是把一个汉字当成是两个字节数据来存储,而utf-8是把一个汉字当成3个字节表示
你如果把s换成a你好,打印的是
[97, -60, -29, -70, -61]
[97, -28, -67, -96, -27, -91, -67]
最前面的97就是a的Ascii码表示的值,由此可见gbk和utf-8都是兼容Ascii码的,并且说使用gbk码表不代表所有字符都是用两个字节的表示的,编码长度不是定长的
实例3
import java.util.Arrays;
public class TestEncode2 {
public static void main(String[] args) throws Exception {
String s = "你";
byte[] b1 = s.getBytes("gb2312");
System.out.println(Arrays.toString(b1));
String s1 = new String(b1, "utf-8");
System.out.println(s1);
byte[] b2 = s1.getBytes("utf-8");
System.out.println(Arrays.toString(b2));
String s2 = new String(b2, "gb2312");
System.out.println(s2);
}
}
打印的结果是
[-60, -29]
??
[-17, -65, -67, -17, -65, -67]
锟斤拷
这是一种特殊情况,使用unicode解码会根据二进制数据具体的值来判断到底是用一个字节表示一个字符还是两个字节表示一个字符或是三个字节表示一个字符,本例中显然是一个字节表示
一个字符,重新编码回去后的值与原先不一样,所以在利用gbk解码会与先前不一样,而将utf-8换成iso8859-1则不会出错(iso8859-1一个字节代表一个字符)