字节、字符和编码

本文详细介绍了字符编码的原因,从ASCII码、ISO-8859标准到GBK和Unicode字符编码,以及UTF-8和UTF-16的实现。特别提到了Java中字符编码使用UTF-16BE,并通过示例展示了字节与字符之间的转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
字节(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();
	}
	
}

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值