由上一遍文章可知,Java 中的 char 本质上是 UTF-16 编码。而 UTF-16 实际上也是一个变长编码(2 字节或 4字节)。2 字节字符,可以存放到char类型变量,而且UTF-16格式码值和Unicode字符表序号“长得一样” ;如果一个偏僻的字符在 UTF-16 编码下占 4 字节,显然它是不能存放到 char 中的。换言之, char 中只能放 UTF-16 编码下只占 2 字节的那些字符。4字节字符就只能用两个char合起来的char数组表达了。
char 和 int 互转化剖析
int 数值大小在2^16内:char 和 int 直接互转化。int数值(四字节)会被截断高位两个字节的空间,可是数值大小不变,因为没有影响低位两个字节的值。
剖析:0xD307 小于 2^16,因此属于Unicode字符中的两字节字符。Unicode字符中的两字节字符 的索引序号(即代码点) 和 Utf-16字符编码值“长得一样”。一个char字符,想要获取其代码点,则直接强制转化为int即可。
不过为何出现下面的情况,我也是不清楚:如果说两字节字符的Utf-16字符编码值 和 Unicode代码点一致的话,为何bytes数组会是4个?还会出现负数?
int 数值大于2^16:int(四字节,代码点)不能直接转化char(两字节)。因为强制转化会自动截断空间,只取int数值的低位的两个字节;其次,int-->char过程中,其实存在转化高低代理位的算法(见java.lang.Character#highSurrogate和java.lang.Character#lowSurrogate)。因此,当 得到的char数组中的char也不是 原来int的高/低16位。要想得到char数组对应的Unicode字符表序号(即代码点),则需要通过String.codePointAt(int);
1)我们尝试将四字节int强转化成char:你会发现char变量对应的数值是0xD307。高位0x1已经被自动截掉丢失。所以这样强制转化是错误的。
2)四字节字符,我们是要利用Character.toChars(int)来转化的: