二、堆、棧、堆棧
誰來告訴我,為什麼有很多地方(書、部落格等等)把棧叫做堆棧,把堆棧叫做棧?搞得我都頭暈目眩了——繞着門柱估計轉了 80 圈,不暈才怪!
我查了一下金山詞霸,結果如下:
我的天呐,更暈了,有沒有!怎麼才能不暈呢?我這裡有幾招武功秘籍,你們盡管拿去一睹為快:
1)以後再看到堆、棧、堆棧三個在一起打牌的時候,直接把“堆棧”踢出去;這仨人不适合在一起玩,因為堆和棧才是老相好;你“堆棧”來這插一腳算怎麼回事;這世界上隻存在“堆、棧”或者“堆棧”(标點符号很重要哦)。
2)堆是在程式運作時在記憶體中申請的空間(可了解為動态的過程);切記,不是在編譯時;是以,Java 中的對象就放在這裡,這樣做的好處就是:
當需要一個對象時,隻需要通過 new 關鍵字寫一行代碼即可,當執行這行代碼時,會自動在記憶體的“堆”區配置設定空間——這樣就很靈活。
另外,需要記住,堆遵循“先進後出”的規則(此處有雷)。就好像,一個和尚去挑了一擔水,然後把一擔水裝缸裡面,等到他口渴的時候他再用瓢舀出來喝。請放肆地打開你的腦洞腦補一下這個流程:缸底的水是先進去的,但後出來的。是以,我建議這位和尚在缸上貼個标簽——保存期限 90 天,過期飲用,後果自負!
還是記不住,看下圖:
(不好意思,這是鼎,不是缸,将就一下哈)
3)棧,又名堆棧(簡直了,完全不符合程式員的思維啊,我們程式員習慣說一就是一,說二就是二嘛),能夠和處理器(CPU,也就是腦子)直接關聯,是以通路速度更快;舉個十分不恰當的例子哈——眼睛相對嘴巴是離腦子近的一方,是以,你可以一目十行,但絕對做不到一開口就讀十行字,哪怕十個字也做不到。
既然通路速度快,要好好利用啊!Java 就把對象的引用放在棧裡。為什麼呢?因為引用的使用頻率高嗎?
不是的,因為 Java 在編譯程式時,必須明确的知道存儲在棧裡的東西的生命周期,否則就沒法釋放舊的記憶體來開辟新的記憶體空間存放引用——空間就那麼大,前浪要把後浪拍死在沙灘上啊。
現在清楚堆、棧和堆棧了吧?
三、基本資料類型
先來看《Java 程式設計思想》中的一段話:
在程式設計中經常用到一系列類型,他們需要特殊對待。之是以特殊對待,是因為 new 将對象存儲于“堆”中,故用 new 建立一個對象──特别小、簡單的變量,往往不是很有效。是以,不用new來建立這類變量,而是建立一個并非是引用的變量,這個變量直接存儲值,并置于棧中,是以更加高效。
在 Java 中,這些基本類型有:boolean、char、byte、short、int、long、float、double 和 void;還有與之對應的包裝器:Boolean、Character、Byte、Short、Integer、Long、Float、Double 和 Void;它們之間涉及到裝箱和拆箱,點選連結。
看兩行簡單的代碼:
int a = 3;
int b = 3;
這兩行代碼在編譯的時候是什麼樣子呢?
編譯器當然是先處理 int a = 3;,不然還能跳過嗎?編譯器在處理 int a = 3; 時在棧中建立了一個變量為 a 的記憶體空間,然後查找有沒有字面值為 3 的位址,沒找到,就開辟一個存放 3 這個字面值的位址,然後将 a 指向 3 的位址。
編譯器忙完了 int a = 3;,就來接着處理 int b = 3;;在建立完 b 的變量後,由于棧中已經有 3 這個字面值,就将 b 直接指向 3 的位址;就不需要再開辟新的空間了。
依據上面的概述,我們假設在定義完 a 與 b 的值後,再令 a=4,此時 b 是等于 3 呢,還是 4 呢?
思考一下,再看答案哈。
答案揭曉:當編譯器遇到 a = 4;時,它會重新搜尋棧中是否有 4 的字面值,如果沒有,重新開辟位址存放 4 的值;如果已經有了,則直接将 a 指向 4 這個位址;是以 a 值的改變不會影響到 b 的值哦。
最後,留個作業吧,下面這段代碼在運作時會輸出什麼呢?
public class Test1 {
public static void main(String args[]) {
int a = 1;
int b = 1;
a = 2;
System.out.println(a);
System.out.println(b);
TT t = new TT("T");
TT t1 = t;
t.setName("TT");
System.out.println(t.getName());
System.out.println(t1.getName());
}
}
class TT{
private String name;
public TT (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name1) {
this.name = name1;
}
}