1.unicode是用16位二进制来表示字符的一种编码方式。java中就是采用unicode进行编码,因此,在java中,每个字符都是16位二进
制表示,即2个字节(byte)。
2.字符以及字符串与unicode之间的互相转换
1)对于字符类型(char)而言,可以与数字类型直接进行相互转化,而转化后的数字类型即为字符类型所对应的unicode;可以发
现,unicode都是正数,而char也是无符号类型,即char类型字符所对应的数字全都为正数,一个负数转化为char时也将被视作
正数来对待;如:
char ch = '王';
System.out.println((int)ch);//'王'字符所对应的unicode,结果:29579
char cn1 = (char)0x0001;
System.out.println(cn1);//能够正常输出unicode编号为1的字符
char cn2 = (char)0x8001;
System.out.println(cn2);//输出乱码'?',因为char类型并不会因为0x8001首位数字为1就认为是一个负数,
//同样也不会因为java的负数使用补码形式保存而对其进行原码转化,而是直接把符号位按照常数位来计算,
//因此这里转换后的数字范围不在unicode表中,因此给出乱码;
2)在进行不同精度的数字类型转换的时候,特别要注意,在java中,由低精度向高精度转换的时候,会进行符号位扩展,即在高
位补上符号位;这里需要知道一些基础预知识(a.在java中,负数是用二进制补码形式表示;b.在数字类型中,类型以及其对应
的精度为:byte-8,short-16,int-32,而char为16位;c.如果没有特别声明,一般给出的数如16进制0x开头的,都是int类
型;);下面首先来看一个由精度转换过程中符号扩展所引起的现象:
char nch = (char)(-1);//由-1转化为字符类型...A
System.out.println(nch);//输出为'?',即无法识别该字符...B
short snum = (short)(-1);//...C
System.out.println(snum);//输出为-1...D
byte bnum = (byte)(-1);//...E
System.out.println(bnum);//输出为-1...F
System.out.println((byte)nch);//输出为-1...G
System.out.println((short)nch);//输出为-1...H
System.out.println((int)nch);//输出为65535...I
System.out.println((int)((short)(-1)));//输出为-1...J
下面我们一步步分析产生以上现象的原因;
在A中,将一个unicode为-1的字符赋给nch,这里-1是一个int类型,即32位,并且是负数,因此在计算机中的表示应该为
0xFFFFFFFF,而在A步骤实际上是对该数由高精度转低精度,强行截取低16位,即0xFFFF;在C,E其实也是强行的截取低位,
由高精度向低精度转换的时候,无论是否为有符号数之间的转换,都为强行截取低位;而在D,F中,正好截
取的低位也为-1,因此输出为-1。在G中,同样是高精度转低精度,因此与C,E一样,直接截取后恰好为-1,因此输出-1;在H
中,精度不变,但是short为有符号数,因此最高位视为符号位,因此输出-1;在I中,是典型的低精度转高精度,这时,就会出现
所谓的符号扩展,由于nch为0xFFFF,并且char类型为无符号数,因此扩展为32位的int类型时,直接往高位补上0,由于补位后
最高位为0,因此整个数最后输出为65535;而在J中,16为的-1虽然同样为0xFFFF,但是short为有符号数,因此,转换为int时
候,高位补上符号位,因此最后补位后最高位为1,视作负数,补码形式,因此最后输出-1;因此,我们也做个结论,由低精度向
高精度转换的时候,如果低精度的数为有符号数,则在高位补上符号位;若低精度的数为无符号数,则在高位补上0;事实上,可
以测试得,如果,一个byte精度转换为char类型,也是补上符号位的,这也更严谨的证明了以上结论。
至此,关于高低精度转换的一些规则,应该已经明了。
3)对于字符串而言,如果想得到字符串中的每个字符的unicode,可以通过把字符串转化为字符数组,然后取每个字符的unicode
即可。而不要用getBytes方法去取得字节拼接方式,因为java是通过unicode,16位来存储字符,如果单独拆开字节,其实并没
有任何意义,而且字节的拆拼也容易发生符号扩展错误。
4)如果真的要取字节来自己处理,则通过&运算去取低位,然后用>>来进行移位。
3.关于编码
unicode在英文字符部分,与ascll码无区别,只不过ascll码用的是7位二进制,最高位永远为0;而unicode用16位。unicode还扩展了世界语言部分,中文字符也包括在内;另一种中文编码GBK编码,也是采用双字节编码,但是具体编码方式与unicode不同,因此,可以发现,如果用String类中的getBytes()方法去取得一个字符的两个字节,与把这个字符在char类型中自己用&运算去取得的两个字节比较,发现不一样,因为getBytes()方法默认是GBK编码,而后者方法取得的是unicode编码值;如果在调用getBytes()方法的时候选用UTF-16编码的话,就和后者一致了,因为UTF-16编码就是unicode编码的一种双字节编码。