短文速读,这将是一个系列文章。本身写了不少文章,也看了不少文章。发现不少都是收藏不看系列。固然有时间的时候,的确会把收藏的文章找出来好好的学习一番。可是大多数文章仿佛石沉大海,失去了应有的价值。java
因此萌生了这个系列的想法,系列文章的特色:以一些平常开发中不起眼的基础知识点为内核,围绕此包裹通俗易懂的文字。尽可能用少思考的模式去讲述一个知识。让咱们可以真正在碎片化的时间里学到东西!面试
爱因斯坦:“若是你不能简单地解释同样东西,说明你没真正理解它。”编程
[短文速读-2] 重载/重写,动/静态分派?(从新修订)多线程
[短文速读-3] 内部匿名类使用外部变量为何要加finalpost
[短文速读 -5] 多线程编程引子:进程、线程、线程安全优化
小A:刚踏入Java编程之路...spa
MDove:一个快吃不上饭的Android开发...线程
小A:MDove,最近我有一个不成熟的小疑问,不知道当讲不当讲。
MDove:不成熟那就别问了...
小A:额错了,额真滴错了。额从一开始就不该该学Java...
MDove:问、问、问...
小A:a=a+b和a+=b。这俩者有什么区别呀?没看出来有什么区别啊!
MDove:你所说的没区别,是这样吧?
int a = 1;
int b = 2;
a = a + b;
a += b;
复制代码
MDove:那你有没有换过别的写法呢?好比把b的类型变一下:
float b = 2F;
复制代码
MDove:怎么样,看出来效果了吧。没看出来??OK,那我就贴上效果:
MDove:这样就能看明白了吧?b提高了类型以后。会发现a = a + b
是没办法编译经过的,须要强制类型转换才能够。可是咱们的a + = b
却能够,这是为何呢?其实很简单。让咱们反编译一下这个class文件,就能够很清晰的给出答案:
public void fun() {
int a = 1;
float b = 2F;
a += b;
}
// 反编译class的内容
public void fun() {
byte var1 = 1;
float var2 = 2.0F;
int var10000 = (int)((float)var1 + var2);
}
复制代码
MDove:因此它们两者的区别就很清楚了吧?在这种a比b类型范围要小的状况下。a = a + b;
须要强制类型转换,也就是咱们常写的:a = (int) (a+b);
而咱们的a += b;
被咱们的编译器在编译期作了一些小手脚。也就是编译器帮咱们进行了强制类型转化。
小A:原来是这样,那强制类型转换会带来什么问题呢?
MDove:解答这个问题,让咱们先来看一张图:
MDove:强制类型转化,通常会带来精度丢失的问题。这里float的范围太大,咱们就用byte和short来演示,强制类型带来的问题:
public void fun() {
byte a = 1;
short b = 127;
a=(byte) (a+b);
System.out.println(a);
}
复制代码
MDove:System打出的内容,应该知道是什么吧?没错是-128。强制类型带来的问题一目了然了吧。
小A:怎么会是-128呢?
MDove:OK,接下来,我来解释一下,为何会是-128这么一个奇怪的数字。首先,咱们都知道基本类型在堆中所占的字节以下表。
小A:不对呀?我记得基本类型是存放在栈中的呀?
MDove:这种说法并不错,但不全面。存放在堆中仍是在栈中,是取决于这个变量声明的位置。若是是局部变量,则会存放在栈帧中。可是若是是成员变量(全局变量),那么就会存放在堆中。此外存放在栈中,基本类型所占的字节是固定:若是是32位计算机那么就是4字节;64位即是8字节。
有一个须要留意的点,new对象并不是所有在堆中。虚拟机会对方法作逃逸分析优化。若是局部变量new的对象,没有发生引用逃逸(在方法体内,未将引用暴露给外面)。那么虚拟机会直接将其建立在栈中,以此来减小堆中压力。
类型 | 所占字节 |
---|---|
byte | 1字节 |
short | 2字节 |
int | 4字节 |
long | 8字节 |
char | 2字节 |
float | 4字节 |
double | 8字节 |
MDove:解释完所占字节的问题,我们继续。由上边可知byte占1字节,那么也就是8位,若是每一位都为1(11111111),那么理论上就是它所能表示的最大内容。
小A:那应该是255呀!
MDove:实际否则,由于正负的缘由,计算机中使用补码的形式表示二进制,高1位表示符号位(0为正,1为负)。所以对于8位来讲,最大只能是01111111,也就是127。(0表示它为正)
MDove:而咱们刚才的那个计算byte a = 1; short b = 127; a=(byte) (a+b);
不考虑类型转换,那么a+b妥妥的等于128。而且对于所占2字节的short来讲那就是00000000 10000000
。可是咱们强制类型转化成了byte,这时作了一件事情,那就是高1字节的内容所有砍掉,也就是只剩下了10000000
。
MDove:按咱们刚才所说,高1位的内容表示正负。1为负。
小A:!!!若是1为负,那System.out应该是0才对啊。
MDove:一看你二进制就没有好好学。对于含有补码形式的10000000
,咱们要用补码的方式去计算。计算套路以下:高1位为1,那么这是数就是负数。想要知道是负几,咱们须要将10000000
按位取反,也就是01111111
。还没完,此时还要再加1,也就是10000000
。如今获得的这个数是几,那么就是负几,10000000
是十进制的128,所以补码形式的10000000
也就是:-128。
MDove:这样解释是否是就知道强制类型转换带来的问题,以及为何强制类型转化后的byte变成了-128了吧。
小A:好难学...我想回家种地...
小A妈:崽,别学编程啦,赶忙回家收玉米了。