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

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

是我打开eclipse试验char

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

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

接下来,我修改为65536

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都可以,而且打印出了

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

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类型的更大,见

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

所以编译不报错,指的是未超过后面类型的范围,所以不报错。

那么既然这么大,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的汉字,截取一部分

165905_2jrp_914655.png

还有点疑问:看下面

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
171021_xCtf_914655.gif8个部首CJK统一汉字区新增了这8个字符0x9FB4-0x9FBB
未计入CJK统一汉字区新增的14个字符0x9FA6-0x9FB3


转载于:https://my.oschina.net/u/914655/blog/318664

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值