字节(Byte):一个字节占8位(bit),在计算机和网络中是通过二进制字节传递信息的;
字符(character):字符是人所能读写的最小单位,例如汉字“我”、字母“A”、符合“+”等,计算机所能支持的字符组成的集合,就叫做字符集。
编码(encode):在计算机和网络中无法直接传递字符,所以需要将字符解析为字节,个解析操作就叫做编码(encode),而相应的,将编码的字节还原成字符的操作就叫做解码(decode)。编码和解码都需要按照一定的规则,这种把字符集中的字符编码为特定的二进制数的规则就是字符编码(Character encoding)。
编码的原因
由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元——字节 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解。计算机中存储信息的最小单元是一个字节即8个位(bit),所以能表示的字符范围是0~255个。人类要表示的符号太多,无法用一个字节来完全表示,这就需要编码来解决这个问题。
ASCII码
在计算机发展的早期,字符集和字符编码一般使用相同的命名,例如最早的字符集ASCII(American Standard Code for Information Interchange),它既代表了计算机所支持显示的所有字符(字符集),又代表了这个字符集的字符编码。
ASCII字符集是一个二维表,支持128个字符。128个码位,用7位二进制数表示,由于计算机1个字节是8位二进制数,所以最高位为0,即00000000-01111111 或0x00-0x7F。
慢慢地,只支持128个码位的ASCII不能满足我们的需求了,就在原来ASCII的基础上,扩展为256个字符,成为EASCII(Extended ASCII)。EASCII有256个码位,用8位二进制数表示,即00000000-11111111或0x00-0xFF。
ISO-8859标准
当计算机传到了欧洲,EASCII也开始不能满足需求了,但是改改还能凑合。于是国际标准化组织在ASCII的基础上进行了扩展,形成了ISO-8859标准,跟EASCII类似,兼容ASCII,在高128个码位上有所区别。但是由于欧洲的语言环境十分复杂,所以根据各地区的语言又形成了很多子标准,如ISO-8859-1、ISO-8859-2、ISO-8859-3、……、ISO-8859-16。
所以ISO-8859并不是一个标准,而是一系列标准,它们子标准都以同样的码位对应不同字符集。
GBK
全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。
Unicode字符编码
后来计算机传入亚洲,由于亚洲语种和文字都十分丰富,256个码位就显得十分鸡肋了。于是继续扩大二维表,单字节改双字节,16位二进制数,65536个码位。在不同国家和地区又出现了很多编码,大陆的GB2312、港台的BIG5、日本的Shift JIS等等。
为了解决传统的字符编码方案的局限,就引入了统一码(Unicode)和通用字符集(Universal Character Set, UCS)来替代原先基于语言的系统。通用字符集的目的是为了能够涵盖世界上所有的字符。Unicode是计算机科学领域里的一项业界标准,包括字符集、编码方案等。
Unicode的编码方式:Unicode使用16位的编码空间也就是每个字符占用2个字节。这样理论上一共最多可以表示2的16次方(即65536)个字符。
Unicode的实现方式:Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式也称为Unicode转换格式(Unicode Transformation Format,简称为UTF),目前主流的实现方式有UTF-16和UTF-8。
UTF-8
UTF-8是一种变长编码,它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他Unicode字符混合的情况,将按一定算法转换。
UTF-8每个字符使用1-3个字节编码,并利用首位为0或1进行识别。
1、如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
2、如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
3、如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节
UTF-16
UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。
Java中的字符编码
在Java中,char类型用UTF-16BE编码描述一个代码单元。在Java SE 1.4中引入的java.nio包用Charset类统一了对字符集的转换。此类定义了用于创建解码器和编码器以及获取与 charset 关联的各种名称的方法。此类的实例是不可变的。
下面用一个小例子来展示一下Java中字节与字符之间的转换:
package com.test;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "Hello World,你好 世界";
System.out.println(s);
byte[] byte1 = s.getBytes();//默认编码
System.out.println("默认编码:" + Charset.defaultCharset());
for(byte b : byte1) {
//把字节以16进制显示
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
try {
byte[] byte2 = s.getBytes("UTF-8");
System.out.println("\nUTF-8编码:");
for(byte b : byte2) {
//把字节以16进制显示
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
byte[] byte3 = s.getBytes("UTF-16");
System.out.println("\nUTF-16编码:");
for(byte b : byte3) {
//把字节以16进制显示,fe ff表示是以UTF-16编码
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}