最近在看JDK的源码,在看源码的时候看到了0xff这么个东东,从这里引出了类型转换。因此在此记录下。
在写原理之前先看几个例子。byte b=-1;int a=b;然后打印a得出的结果是-1.int b=-1;byte a=(byte)b;打印a得出来的是-1。int a=255;byte b=(byte)255;打印b得出的结果也是-1;而把这个强制转出来的-1再转回int,得出的确不是255了,有点奇怪了。这是为什么那?好了,废话不过说,下面就开始讨论为什么了。在讲这个之前先来几个概念。二进制中的原码,反码,补码,补位,真值。再有就是byte类型和int类型分别占了多少位。这里需要说一下,二进制的高位是符号位,1表示负数,0表示正数。注:java是用补码存储数据的。
byte类型占一个字节,一个字节由8位二进制组成,所以说byte类型占了8位。int类型占4个字节,所以说int类型占了8位。
真值:这个就看字面意思,int a=-1;a的真值就是-1.
原码:int类型的-1的二进制表示,由于-1是负数,又是int类型的,所以他需要32个二进制来表示,二进制的最高位是符号位,所以为1,1的二进制为1,所以-1的二进制表示为 1000 0000 0000 0000 0000 0000 0000 0001;
反码:正数的反码就是原码,负数的反码是在原码的基础上,符号位不变,其余位取反。所以int类型的-1的反码是
1111 1111 1111 1111 1111 1111 1111 1111。
补码:正数的补码就是原码,负数的补码是在反码的基础上加1。所以,int类型的-1的补码是 1111 1111 1111 1111 1111 1111 1111 1111。
补位:补位是二进制中在扩充位数的时候,位数不够需要在左边补齐,补齐的方式为如果是正数的补位,左边全部补0,负数左边全部补1(也就是说补位的时候补足的是符号位)。
进入正题:
int a=-1;byte b=(byte)a;b的结果是-1。为什么int类型给byte类型赋值的时候为什么需要做强制类型转换,因为int类型是32位的,而byte类型只有8位,8位无法存储32位,所以需要把32位强制转为8位。这个结果是怎么得出来的呢?从二进制的角度开始分析,int类型的-1的补码是 1111 1111 1111 1111 1111 1111 1111 1111。他在强制转为8位byte的时候需要把高24位丢弃,只保留8位,也就是 1111 1111 ,这8位是补码的形式,转化为原码,8位的最高位是1.所以是负数。根据原码,反码和补码的计算方法可以得出他的反码是1111 1110 ,原码是 1000 0001 ,所以他的真值是-1。
byte a =-1,int b=a,b的结果是-1。为什么byte类型给int类型赋值的时候不需要做强制类型转换,因为是从低位向高位转,会自动补位。byte类型的-1的原码是1000 0001 ,他的补码就是1111 1111 。由于byte类型需要从8位转为32位的int类型,位数不够,根据扩充原则需要在二进制原码的左边扩充符号位。注意,byte类型的-1的原码的补位后的结果不是1111 1111 1111 1111 1111 1111 1000 0001 ,而是1000 0000 0000 0000 0000 0000 0000 0001 。原因是在补位的时候是先将真值取绝对值,计算出他的原码,将原码扩充完毕之后,最高位改为符号。因此,byte类型的-1的绝对值是1,他的原码是0000 0001 ,补全32位需要在左边补24个0,补完之后由于是负数的补位,所以将最高位的符号位改为1,表示负数,所以byte类型的-1扩充为int类型后他的原码是1000 0000 0000 0000 0000 0000 0000 0001 。(其实根据补码补位也是可以的,byte 类型-1 的补码是1111 1111 ,他补位之后,因为最高位是负数,所以左边全部补充1 ,为1111 1111 1111 1111 1111 1111 1111 1111 ,这是补码,最高位符号位不变,他的反码是1111 1111 1111 1111 1111 1111 1111 1110,原码就是 1000 0000 0000 0000 0000 0000 0000 0001 )所以,他的真值就是-1了。
再看最后一个例子,int a=255;byte b=(byte)a;b的值为什么是-1那?int类型的255的原码是0000 0000 0000 0000 0000 0000 1111 1111,反码是0000 0000 0000 0000 0000 0000 1111 1111,补码是0000 0000 0000 0000 0000 0000 1111 1111。32位转8位需要丢掉高24位,剩下1111 1111八位。剩下的八位的最高位是符号位,将他转为原码就是1000 0001,真值就是-1了。
大家在自己算一下(byte)234的结果是什么,然后在IDE里在运行下看和自己手写算出来的一样吗。
语文水平不太好,写的可能有点啰嗦,希望你能理解下,写这篇文章就是想和大家分享下在学习当中遇到的问题,怎么解决的,学习java不是学习下框架什么的就可以了,只有了解底层的原理,在看别人写的代码才能真正理解。才能真正学会java,而不是感到迷茫。在此要感谢我亲爱的媳妇,前面那些都是她帮我打字的,这么晚了还要让她陪我熬夜,好感动!