[短文速讀-1] a=a+b和a+=b的區別

前言

短文速讀,這將是一個系列文章。本身寫了不少文章,也看了不少文章。發現不少都是收藏不看系列。固然有時間的時候,的確會把收藏的文章找出來好好的學習一番。可是大多數文章彷彿石沉大海,失去了應有的價值。java

因此萌生了這個系列的想法,系列文章的特色:以一些平常開發中不起眼的基礎知識點爲內核,圍繞此包裹通俗易懂的文字。儘可能用少思考的模式去講述一個知識。讓咱們可以真正在碎片化的時間裏學到東西!面試

愛因斯坦:「若是你不能簡單地解釋同樣東西,說明你沒真正理解它。」編程

[短文速讀-1] a=a+b和a+=b的區別安全

[短文速讀-2] 重載/重寫,動/靜態分派?(從新修訂)多線程

[短文速讀-3] 內部匿名類使用外部變量爲何要加finalpost

[短文速度-4] new子類是否會實例化父類學習

[短文速讀 -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媽:崽,別學編程啦,趕忙回家收玉米了。

劇終

這裏是一幫應屆生共同維護的公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,以及咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油,一同努力~!~!

我的公衆號:IT面試填坑小分隊
相關文章
相關標籤/搜索