1. char

“java 中有个基本类型 char, 它占用固定的 2 byte 空间来表示字符, 又因为 java 设计之初就采用了 Unicode 编码,所以 char 能表示所有字符包括中文.”

但 2 字节最多只能标识 65536 个字符, 它是怎么能囊括那么多字符的呢? 仅所有汉字就不止 6 万.

java 中的 char 确实使用 2 byte 空间, 它实际使用的是 UCS-2 也就是 plane 0, 只能表述 65536 个字符, 对于超出其范围的其它 plane 内容, 请看下图:

char / String - 图1

一旦你使用了大于 UCS-2 的字符, 那么编译器会直接报错.

其实也就是说 char 使用的是 UTF-16 格式. 有个建议是尽量别用 char 类型, 因为它会导致一些隐蔽的错误. 比如, 当你在用 String 时你定义了一个 , 你想当然的认为一个 char 就能盛放String 中的一个字符 (毕竟 char 是字符, 而 String 就是描述的 char 数组), 但是你会发现其实这个 Stringlength() 是 2 而不是 1, 因为它超出了 UCS-2, String 用两个char 的位置 (4 字节) 来表示了这个 char, 而 String 本该用一个 char 的位置来表示它才对.

2. String

首先, String 能够支持的字符与你写代码时选择的编码方式有关, 当你选择 UTF 编码时, 你可以随便使用 Unicode 字符, 用没脚 当变量名都随你. 使用 GBk 时, 没脚虫 不被支持 (GBK 收录的少一些或者这是日本字)

其次, String 在 Java 中是被定义为 char 数组来组织的, 所以你定义的 String 最终要被转换成char 来存放, 但是, 不要认为超出 char 的 65536 就不能存了, 如果超出了它会用 2 个 char 来存放.

在这里有两种方向来说 1 个 String 占用的空间:

2.1. 在 Java 中实际使用的空间

这与使用的编码有关:

UTF-8 : 2 或 4 byte, 其实就是 1 个 char 或者 2 个 char;

GBk : 2 byte, 就是 1 个 char.

2.2 如果对其编码,所需要的空间(String.getBytes())

UTF-8 : 1~4 byte, ASCII 用 1 byte, 汉字大部分用 3 byte, 其它字符参照上边 UTF2.2 的算法, 超出 UCS-2 的部分比如那个 就会是 4 byte.

GBk : ASCII 使用 1 byte, 其它中文 2 byte.

3. 额外的部分—-从 java 到 class 文件

无论 .java 文件你用 GBK 或者 UTF-8 来编码, 编译器在将其编译为 .class 文件后, 如果其中有字符串, 会使用 UTF-8 来编码存储字节, 占用 1~4 byte. 详细来说, 就是在 .class 文件的常量池部分, 这种字符串数据使用的数据结构是 CONSTANT_Utf8_info, 代表 UTF-8 编码的字符串.

4. References

[1] Java中char和String 的深入理解 - 字符编码1