跳转至

计算机存储数字和字符的原理?

一、数字的存储

1. 整数:补码(Two's Complement)

计算机用补码存储有符号整数,目的是让加减法统一电路(减法变加法)。

真值 原码 反码 补码
+1 0000 0001 0000 0001 0000 0001
-1 1000 0001 1111 1110 1111 1111
-128 1000 0000

规则: - 正数:原码 = 反码 = 补码。 - 负数:补码 = 反码 + 1,最高位是符号位(0 正 1 负)。 - 8 位补码范围:-128 ~ 127,比原码多表示一个 -128。

2. 浮点数:IEEE 754

Java 的 float(32 位)和 double(64 位)遵循 IEEE 754:

float:  1 位符号 + 8 位指数 + 23 位尾数
double: 1 位符号 + 11 位指数 + 52 位尾数

例如 0.1 在 double 中不是精确值,所以 0.1 + 0.2 != 0.3。金融计算用 BigDecimal

二、字符的存储

1. ASCII

1 字节,最高位为 0,只能表示 128 个字符(英文字母、数字、控制符)。

2. ISO-8859-1(Latin-1)

1 字节,最高位置 1,扩展到 256,覆盖西欧语言。

3. GBK / GB2312

中文编码,1~2 字节。GB2312 收录 6763 个汉字;GBK 扩展到 21886 个。

4. Unicode 与 UTF-8 / UTF-16 / UTF-32

  • Unicode:为每个字符分配一个唯一码点(Code Point),如 中 = U+4E2D
  • 但 Unicode 只定义码点,不规定怎么存。UTF 是存储实现
  • UTF-8:变长 1~4 字节。ASCII 字符占 1 字节,中文通常 3 字节。互联网最常用。
  • UTF-16:Java 内部 char 用的编码,变长 2/4 字节(BMP 字符 2 字节,辅助平面 4 字节)。
  • UTF-32:定长 4 字节。

5. Java 中的 char 与 String

  • charUTF-16 码元,2 字节,只能表示 BMP 字符。
  • 像 emoji(如 😀 U+1F600)需要两个 char(代理对)。
  • String.length() 返回的是 char 数量,不是 Unicode 字符数;codePointCount() 才是字符数。
String s = "😀";
s.length();              // 2
s.codePointCount(0, s.length()); // 1

乱码根因

乱码 = 编码与解码用了不同的字符集。解决:明确指定 UTF-8,不要依赖平台默认编码(new String(bytes) 在不同系统结果不同)。