Java采用Unicode进行编码,char类型在内存中占2个字节-16位,其值的范围在0-65535之间。20 世纪 80 年代开始启动设计 Unicode 编码时,人们认为两个字节(16 位)的代码宽度足以对世界上各种语言的所有字符进行编码,并有足够空间留给未来的扩展。所以在设计 Java 时决定采用 16 位的 Unicode 字符集。目前Unicode编码范围在0-1114111之间,显然一个char类型已经不能够存65535以外的字符了,Java怎么扩展的我放后面讲,这里先讲正常情况。


给一个char赋值的几种方式,已“严”字为例子,​​严​​​的 Unicode 是:十六进制【​​4E25​​】二进制【01001110,00100101】十进制【20005】。我们可以已下面三种方式赋值。

char c1 = '严';
char c2='\u4E25';
char c3 = 20005;
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);

将char转换为字符串。

String str = new String(new char[]{c1});

将字符串转换为字节数组,我们用UTF-8编码解码方式。UTF-8编码方式原理请参考

​UTF-8编码原理​

System.out.println(Arrays.toString(str.getBytes("UTF-8")));

打印: [-28, -72, -91]

转换为二进制

String.format("%8s", Integer.toBinaryString(byte & 0xFF)).replace(' ', '0');

打印:11100100,10111000,10100101。这个值就是UTF-8以后二进制值。


下面来讲解JAVA的char类型如何表示65535以后的的字符。它采用的办法是(代理区模式)。

在0-65535之间,保留了一部分数字范围(D800–DBFF)和(DC00–DFFF)。

(D800–DBFF)叫高代理区和(DC00–DFFF)叫低代理区,各1024,这两个区组成一个二维的表格,共有1024×1024=2^10×2^10=2^4×2^16=16×65536,用它们来表示Unicode中65535以后的字符。

java char类型的存值范围_java


下面以一个例子来说明:

已符号笑脸为例: 在Unicode码表中 十进制 128515,十六进制为1F603。java char类型的存值范围_3d_02


通过查询代理区域对照表(D800–DBFF)和(DC00–DFFF), 1F603对应的高端区为D83D,低端区为DE03。通过java代码测试,因为char类型2个字节,所以如果显示4个字节的字符需要用2个char表示。

char[] chars = new char[]{'\uD83D','\uDE03'};
System.out.println(new String(chars));
System.out.println(Arrays.toString(new String(chars).getBytes("utf-8")));
//=[-16, -97, -104, -125]

成功打印出笑脸表情符号

java char类型的存值范围_3d_03

再看把它写成utf-8的二进制形式 = [-16, -97, -104, -125]。

转换为二进制[11110000,10011111,10011000,10000011]。

根据UTF-8编码规则转换出实际表示编码的二进制值,11111011000000011=128515=1F603。

java char类型的存值范围_ico_04