java中char类型占2个字节,String内部采用char[]表示
unicode字符集包含多个平面,通常第0平面就已经满足使用,第0平面可表示的字符从0x0000到0xFFFF。
在String表示的字符都在第0平面时,每个char对应一个字符,且String的私有成员value存储的是第0平面的unicode码点。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
汉字“虫”unicode码点为0x866b,位于第0平面
utf-8编码后占3个字节
import java.util.*;
import java.nio.charset.Charset;
import java.lang.reflect.*;
public class App
{
public static void main( String[] args ) throws Exception
{
String str = "虫";
System.out.println(str.length()); // 1
char[] value = str.toCharArray();
System.out.println(Integer.toHexString(value[0])); // 866b
System.out.println(Charset.defaultCharset()); // utf-8
byte[] bs = str.getBytes(); // 采用utf-8对unicode码点进行编码
System.out.println(bs.length); // utf-8编码后为3个字节
System.out.println(Arrays.toString(bs));
}
}
因此String内部存储的是unicode码点。
一个char只能表示unicode第0平面的字符,当要表示的字符位于非第0平面时,需要用2个char表示。utf16采用2个字节或4个字节表示,采用2个字节时,对应第0平面。
uft16的设计应该使得字符的识别非常容易,比如读到任意一个码点(2个字节),都要知道这个码点是对应第0平面,表示一个字符,还是对应非0平面,表示4个字节中的前2个字节还是后2个字节。
unicode范围从0x000000-0x10FFFF,第0平面范围从0x0000-0xFFFF,非0平面范围从0x10000-0x10FFFF,共计0x10FFFF-0xFFFF=0x100000个,即
(
2
4
)
5
(2^4)^5
(24)5,需要20bit表示
utf16对于非0平面的码点,在前后2个字节中各取10bit。前后2个字节剩余的6bit用于区分2个字节的码点还是4个字节的前2个字节或后2个字节。
2
6
2^6
26范围为0-63,utf16用54表示前16bit,55表示后16bit,其他的为单16bit。
54开头的范围为1101 10xx xxxx xxxx,区间就是D800~DBFF
55开头的范围为1101 11xx xxxx xxxx,区间就是DC00~DFFF
而unicode字符集也是将这2个区间分配给utf16,不允许分配字符。