疑问1:java char范围0-65535,如何存储那么多汉字

怀疑首先起于这里我用 char存储单个的汉字,可是忽然想到,如何char的范围仅有0-65535,如何表示全部的汉字(汉字博大精深,已远超65535个)html

是我打开eclipse试验charjava

char ch = (char) 65535;
System.out.println(ch);

编译器不报错,打印了空(什么都没有),估计此处无字符,能够理解。数组

接下来,我修改成65536eclipse

char ch = (char) 65536;
System.out.println(ch);

竟然编译不报错,我有点晕了,不是最大65535么,怎么大于也行?工具

接下来,我找到一个有汉字的84426编码

char ch = (char) 84426;
System.out.println(ch);

这里打印出了“䧊”,why?一头雾水,java官方说明文档也是指定其是2个byte,16位的无符号值,也即0-65535,why此处84426均可以,并且打印出了spa

后来我又增长ch的值,想其难道是4个字节,直到2^31-1=2147483647时,不报错,加1时2147483648,编译不经过了,提示以下:.net

char ch = (char) 2147483648;//The literal 2147483648 of type int is out of range
System.out.println(ch);

注意里面的提示The literal 2147483648 of type int is out of range,我才注意到后面的值实际上是int的范围,因此编译不报错,同理long类型的更大,见code

char ch = (char) 0xFFFFFFFFFFFFFFFFL;//0x表示16进制,后面的L标明为long类型

因此编译不报错,指的是未超事后面类型的范围,因此不报错。htm

那么既然这么大,char范围0-65535那么小,是否有转换规则,是的,见下面

也就是大于65535的int值赋予char时,其会自动mod 65536(此处只针对大于,小于的话就不对了,见下),得出65535范围内的一个unicode

int i = 18890 + 65536;
//大于65535即mod,此处加了好几个65535,其仍是表明18890
//int i = 18890 + 65536 + 65536 + 65536;
//int i = 18890 - 65536 - 65536;
char c = (char)i;
System.out.println(c);
//mod针对大于65535的还好使,可是其表明的是这个意思
System.out.println(i % 65536);
//Integer.valueOf()能获得其表明的unicode值的大小,十进制int表示
System.out.println(Integer.valueOf(c));
char d = '䧊';
int n = (int)d;
System.out.println(n);

由上可见,其实“䧊”字的unicode码是18890,而非84426,而且其范围超过0-65535的范围,若是强制转换(char c = (char)i;)java会根据规则自动转换到0-65535区间中的一个。

到这里估计也就明白了,是本身写错了,下面这种方式确定会提示编译错误的

char ch = 65536;// Type mismatch: cannot convert from int to char

也即char的范围的确是0-65535。其实char单引号的写法(

char ch = '䧊';

),只是为了方便记忆和书写,它仍是会转为数字码的形式,也即unicode码存储。

那到了这里

疑问还在,那就是65535的范围如何存储那么多的汉字?

答案是其存不了那么多,最多只能是65535,由于在此范围以外的都会转换到此范围里

并且我试了找到65535以外的汉字(用此工具查看UniToy)来试验,但是始终没法打出这些汉字,遂放弃了

大于65535的汉字,截取一部分

还有点疑问:看下面

public class Test {

	public static void main(String[] args) {
		String str= "中";
		char x ='中';
		byte[] bytes=null;
		byte[] bytes1=null;
		byte[] bytes2=null;
		try {
                    bytes = str.getBytes("gbk");  
                    bytes1 = str.getBytes("utf-8");  
                    bytes2 = charToByte(x);  
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		System.out.println("bytes 大小:"+bytes.length);
		System.out.println("bytes1大小:"+bytes1.length);
		System.out.println("char转换为byte数组大小:"+bytes2.length);
                System.out.println("byte数组的两个值,其实unicode值的两个字节拆分到数组里了:"+bytes2[0]+"-"+bytes2[1]);
	}
	
	// 如“中”的unicode值为Integer.valueOf(x)=20013
        // 二进制为0100 1110 0010 1101
	// 拆分出来即为b[0]=0100 1110 b[1]=0010 1101
	public static byte[] charToByte(char c) { 
        byte[] b = new byte[2]; 
        b[0] = (byte) ((c & 0xFF00) >> 8); 
        b[1] = (byte) (c & 0xFF); 
        return b; 
    }
}

输出:

gbk byte数组大小:2

utf8 byte数组大小:3

char转换为byte数组大小:2

byte数组的两个值,其实unicode值的两个字节拆分到数组里了:78-45


java是用unicode来表示字符,"中"这个中文字符的unicode就是2个字节。

String.getBytes(encoding)方法仅是获取指定编码的byte数组表示,而非java char存储时会占3个字节,只是utf8编码时该占几个字节

一般gbk/gb2312是2个字节,utf-8是3个字节。

若是不指定encoding则取系统默认的encoding。

-----------------------------------------------------------------------------------------------------------

UTF-8,GBK等这里没涉及,他们只是编解码规则,按必定规则编解码,再和其对应的字符图案对应起来。

其实简单来讲UTF-8就是unicode码如何转换为字符来显示的,其有必定的转换规则,具体见http://my.oschina.net/u/914655/blog/318738处第11项。

目前汉字范围及与unicode如何对应

GB2312有6763个汉字,GBK有21003个汉字,GB18030-2000有27533个汉字,GB18030-2005有70244个汉字。

Unicode 5.0中,若是不算兼容区,目前有70217个汉字。让咱们比较一下Unicode的70217汉字和GB18030-2005中的70244汉字:

GB18030-2005 Unicode 5.0 对应的Unicode编码
CJK统一汉字的20902汉字 CJK统一汉字的20902汉字 0x4E00-0x9FA5
CJK统一汉字扩充A的6582汉字 CJK统一汉字扩充A的6582汉字 0x3400-0x4DB5
CJK统一汉字扩充B的42711汉字 CJK统一汉字扩充B的42711汉字 0x20000-0x2A6D6
CJK部首补充区的14个部首 未计入 2E81, 2E84, 2E88, 2E8B, 2E8C, 2E97, 2EA7, 2EAA, 2EAE, 2EB3, 2EB6, 2EB7, 2EBB, 2ECA
CJK兼容汉字区的21个汉字 未计入 F92C, F979, F995, F9E7, F9F1, FA0C, FA0D, FA0E, FA0F, FA11, FA13, FA14, FA18, FA1F, FA20, FA21, FA23, FA24, FA27, FA28, FA29
8个部首 CJK统一汉字区新增了这8个字符 0x9FB4-0x9FBB
未计入 CJK统一汉字区新增的14个字符 0x9FA6-0x9FB3
相关文章
相关标签/搜索