本人两年Java开发经验,开发期间干的大都是CRUD的活,温水煮青蛙。最近就想着投投简历,看下外面是个啥行情,抽空也背了些八股文。上周面了一家,虽然问的内容都很基础,就是面那种刚毕业的大学生才会问的问题,结果太紧张,脑子一片空白,背的一些题都忘光了,被面试官吊起来打。。。。。
痛定思痛,从现在开始记录每一个面试官问到的题(如果还记得的话),冲!
2.问题面试官:给你个int类型的255,把它赋值到byte类型的变量上,然后打印这个变量,结果是多少?
我:255吧
面试官:byte的范围是多少?
我:我想想(2分钟过去了)。。。。
面试官:好吧,我再换一个问题吧。。。。。。
其实面试前我还特地记了下各个基本类型占几个字节,然而上面问题都没答出来。
3.解答话不多说,直接上代码:
public class TestCase { public static void main(String[] args) { int a = 255; byte b; b = (byte)a; System.out.println(b); System.out.println(Integer.toBinaryString(a)); System.out.println(Byte.MIN_VALUE); System.out.println(Byte.MAX_VALUE); } }
输出:
-1 11111111 -128 127
可以看到结果是 【-1】,但是这个结果是怎么来的呢?
3.1 技术准备首先,回到一个比较基础的问题,java中byte的范围是多少?
从上面的打印结果中可以看到,byte类型的范围是[-128,127]。
那这个[-128~127]又是怎么来的呢?
这又涉及到java中的每种整数类型的占用的内存大小了。
java中byte类型的数占用1个字节。
一个字节=8位,一位就是一个0或1。
位又是啥概念?一位就是我们常说的1bit,1bit就是一个0或1,众所周知,计算机只认识0和1。
一位可以想象成一个小灯泡,灯泡亮了就是1,没亮就是0,一个字节就是8个小灯泡并排放在一起。
所以,一个byte类型的变量,大小为一个字节,就是用8位(8个小灯泡)来表示的。
那么这8位又是什么意思?怎么用8位来表示一个数?
首先要了解二进制的数怎么转化成十进制的数的,网上随便百度下都能找到,此处不再描述。
而java中,乃至计算机中实际上是如何用二进制来描述一个数的呢?
我们都是站在巨人的肩膀上的,怎么用8位表示一个数,几十年前的计算机先驱们都安排好了。答案是用了一个叫做【补码】的东西。补码又是啥??
不好解释,直接上链接:
原码,反码,补码的深入理解与原理_小小云麓的博客-CSDN博客_原码反码补码
3.2 开始计算恶补了上面的内容后,首先就可以弄明白为什么byte的范围是[-128,127]了,然后终于可以开始研究为什么int的255转成byte后就变成了-1。
java中int是4个字节,就是4组小灯泡,每组8个灯泡。
int类型的255用二进制来表示(上面的演示程序中也打印出来的了,只是因为高位都是0所以就只打印了后面8个1)如下所示(左面为高位):
00000000 00000000 00000000 11111111
而byte只有1个字节,只能用1排小灯泡,int有4排,装不下,咋办呢?
所以就抛弃了高位的3个字节,把低位的那一排用来表示byte,如下图:
11111111
好了,现在只要我们把这8个1,翻译成人能方便地转化成熟悉的十进制数就行了。
翻译过程就是一个根据【补码】求【原码】的过程,如下:
首先要知道这是一个【补码】,先看第一位(符号位),第一位是 1,表示这是一个负数。
然后,既然是个负数,先不管第一位的1
先反转(即0变1,1变0)后面7位,则后面7位反转后变成 7个0 :0000000
然后将反转后的二进制数+1,就变成了6个0加一个1:0000001
所以加上之前的第一位的1,求得的原码就是【10000001】
即【-1】。
3.3 再次验证好了,现在在随便找一个数,手工算一下,就找int类型的278吧
int类型的278的二进制补码表示:
public class TestCase { public static void main(String[] args) { int a = 278; byte b; b = (byte)a; // System.out.println(b); System.out.println(Integer.toBinaryString(a)); } } 输出: 100010110 即: 00000000 00000000 00000001 00010110
看后面8位:
00010110
首位是0,欸,是个正数,整数的【补码】和【原码】相同,那应该就是2 + 4 + 16 = 22
验证一下:
public class TestCase { public static void main(String[] args) { int a = 278; byte b; b = (byte)a; System.out.println(b); System.out.println(Integer.toBinaryString(a)); } } 输出: 22 100010110
果然,22,计算正确!
好,趁热打铁,再来一个,计算int类型的128,赋值给byte类型。
public class TestCase { public static void main(String[] args) { int a = 128; System.out.println(Integer.toBinaryString(a)); byte b; b = (byte)a; System.out.println(b); } } 输出: 10000000 -128
首先看下int的二进制表示:
00000000 00000000 00000000 10000000
转化成byte的二进制:
10000000
欸,先看首位,是个1,是个负数,
反转后面7个0,变成7个1,7个1在加1,就变成了一个1跟7个0:
1111111 + 0000001 = 10000000
在结合首位的1,得到的原码就是:
110000000
即-1 乘 2的7次方 = -128
好,再来一个负数的int,计算int类型的-130,赋值给byte类型。
public class TestCase { public static void main(String[] args) { int a = -130; System.out.println(Integer.toBinaryString(a)); byte b; b = (byte)a; System.out.println(b); } } 输出: 11111111111111111111111101111110 126
int的二进制:
11111111 11111111 11111111 01111110
byte的二进制:
01111110
首先,首位是个0,是个正数,也不用取反了,直接按位加就完了,2+4+8+16+32+64 = 126
所以就是126
4.简单求法讲道理,手工从二进制算十进制还好。从十进制手工算二进制,你是在刁难我胖虎!
其实,byte的范围之内部分,int与之都是对应的,一旦int的值超过了byte的范围,那么就从byte的另一个边界开始轮回就可以了:
128是第一个超过byte最大值的数,那么就从byte的最小值开始数,即int的128转化为byte后就是-128,
同理int的129转成byte就是-127,后面依次类推。
往下数也是同样的道理,int的-128化为byte后就是-128,而int的-129化为byte后就是127。
所以这种大范围向小范围的数字兼容的,其实是有规律的,就拿int和byte来说,后8位总是一个循环的:
比如int的0:
int :00000000 00000000 00000000 00000000 byte: 00000000
比如int的1:
int :00000000 00000000 00000000 00000001 byte: 00000001
...
比如int的127:
int :00000000 00000000 00000000 01111111 byte: 01111111
比如int的128:
int :00000000 00000000 00000000 10000000 byte: 10000000 // -128
比如int的255:
int :00000000 00000000 00000000 11111111 byte: 11111111 // -1
比如int的256:
int :00000000 00000000 00000001 00000000 byte: 00000000 // 0
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)