1. 棧(stack)與堆(heap)都是Java用來在Ram中存放數據的地方。與C++不同,Java自動管理棧和堆,程序員不能直接地設置棧或堆。

2.

棧的優勢是,存取速度比堆要快,僅次於直接位於CPU中的寄存器。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。另外,棧數據可以共

享,詳見第3點。堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由於要

在運行時動態分配內存,存取速度較慢。

3. Java中的數據類型有兩種。

一種是基本類型(primitive types), 共有8種,即int, short, long, byte, float,

double, boolean, char(注意,並沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b

= 255L;的形式來定義的,稱為自動變數。值得注意的是,自動變數存的是字面值,不是類的實例,即不是類的引用,這裡並沒有類的存在。如int a

= 3;

這裡的a是一個指向int類型的引用,指向3這個字面值。這些字面值的數據,由於大小可知,生存期可知(這些字面值固定定義在某個程序塊裡面,程序塊退出

後,欄位值就消失了),出於追求速度的原因,就存在於棧中。

另外,棧有一個很重要的特殊性,就是存在棧中的數據可以共享。假設我們同時定義

int a = 3;

int b = 3;

編譯器先處理int a =

3;首先它會在棧中創建一個變數為a的引用,然後查找有沒有字面值為3的地址,沒找到,就開闢一個存放3這個字面值的地址,然後將a指向3的地址。接著處

理int b = 3;在創建完b的引用變數後,由於在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現了a與b同時均指向3的情況。

特別注意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變數修改了這個對象的內部狀態,那麼另一個

對象引用變數也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與

b的值後,再令a=4;那麼,b不會等於4,還是等於3。在編譯器內部,遇到a=4;時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開闢地址存

放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。

另一種是包裝類數據,如Integer, String, Double等將相應的基本數據類型包裝起來的類。這些類數據全部存在於堆中,Java用new()語句來顯示地告訴編譯器,在運行時才根據需要動態創建,因此比較靈活,但缺點是要佔用更多的時間。

4. String是一個特殊的包裝類數據。即可以用String str = new

String("abc");的形式來創建,也可以用String str = "abc";的形式來創建(作為對比,在JDK

5.0之前,你從未見過Integer i = 3;的表達式,因為類與字面值是不能通用的,除了String。而在JDK

5.0中,這種表達式是可以的!因為編譯器在後台進行Integer i = new

Integer(3)的轉換)。前者是規範的類的創建過程,即在Java中,一切都是對象,而對象是類的實例,全部通過new()的形式來創建。Java

中的有些類,如DateFormat類,可以通過該類的getInstance()方法來返回一個新創建的類,似乎違反了此原則。其實不然。該類運用了單

例模式來返回類的實例,只不過這個實例是在該類內部通過new()來創建的,而getInstance()向外部隱藏了此細節。那為什麼在String

str = "abc";中,並沒有通過new()來創建實例,是不是違反了上述原則?其實沒有。

5. 關於String str = "abc"的內部工作。Java內部將此語句轉化為以下幾個步驟:

(1)先定義一個名為str的對String類的對象引用變數:String str;

(2)在棧中查找有沒有存放值為"abc"的地址,如果沒有,則開闢一個存放字面值為"abc"的地址,接著創建一個新的String類的對象o,並將o

的字元串值指向這個地址,而且在棧中這個地址旁邊記下這個引用的對象o。如果已經有了值為"abc"的地址,則查找對象o,並返回o的地址。

(3)將str指向對象o的地址。

值得注意的是,一般String類中字元串值都是直接存值的。但像String str = "abc";這種場合下,其字元串值卻是保存了一個指向存在棧中數據的引用!

為了更好地說明這個問題,我們可以通過以下的幾個代碼進行驗證。

String str1 = "abc";

String str2 = "abc";

System.out.println(str1==str2);  //true

注意,我們這裡並不用str1.equals(str2);的方式,因為這將比較兩個字元串的值是否相等。==號,根據JDK的說明,只有在兩個引用都指向了同一個對象時才返回真值。而我們在這裡要看的是,str1與str2是否都指向了同一個對象。

結果說明,JVM創建了兩個引用str1和str2,但只創建了一個對象,而且兩個引用都指向了這個對象。

我們再來更進一步,將以上代碼改成:

String str1 = "abc";

String str2 = "abc";

str1 = "bcd";

System.out.println(str1 + "," + str2);  //bcd, abc

System.out.println(str1==str2);  //false

這就是說,賦值的變化導致了類對象引用的變化,str1指向了另外一個新對象!而str2仍舊指向原來的對象。上例中,當我們將str1的值改為"bcd"時,JVM發現在棧中沒有存放該值的地址,便開闢了這個地址,並創建了一個新的對象,其字元串的值指向這個地址。

事實上,String類被設計成為不可改變(immutable)的類。如果你要改變其值,可以,但JVM在運行時根據新值悄悄創建了一個新對象,然後將

這個對象的地址返回給原來類的引用。這個創建過程雖說是完全自動進行的,但它畢竟佔用了更多的時間。在對時間要求比較敏感的環境中,會帶有一定的不良影

響。

再修改原來代碼:

String str1 = "abc";

String str2 = "abc";

str1 = "bcd";

String str3 = str1;

System.out.println(str3);  //bcd

String str4 = "bcd";

System.out.println(str1 == str4);  //true

str3

這個對象的引用直接指向str1所指向的對象(注意,str3並沒有創建新對象)。當str1改完其值後,再創建一個String的引用str4,並指向

因str1修改值而創建的新的對象。可以發現,這回str4也沒有創建新的對象,從而再次實現棧中數據的共享。

我們再接著看以下的代碼。

String str1 = new String("abc");

String str2 = "abc";

System.out.println(str1==str2);  //false

創建了兩個引用。創建了兩個對象。兩個引用分別指向不同的兩個對象。

String str1 = "abc";

String str2 = new String("abc");

System.out.println(str1==str2);  //false

創建了兩個引用。創建了兩個對象。兩個引用分別指向不同的兩個對象。

以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中創建,而且其字元串是單獨存值的,即使與棧中的數據相同,也不會與棧中的數據共享。

6. 數據類型包裝類的值不可修改。不僅僅是String類的值不可修改,所有的數據類型包裝類都不能更改其內部的值。

7. 結論與建議:

(1)我們在使用諸如String str =

"abc";的格式定義類時,總是想當然地認為,我們創建了String類的對象str。擔心陷阱!對象可能並沒有被創建!唯一可以肯定的是,指向

String類的引用被創建了。至於這個引用到底是否指向了一個新的對象,必須根據上下文來考慮,除非你通過new()方法來顯要地創建一個新的對象。因

此,更為準確的說法是,我們創建了一個指向String類的對象的引用變數str,這個對象引用變數指向了某個值為"abc"的String類。清醒地認

識到這一點對排除程序中難以發現的bug是很有幫助的。

(2)使用String str =

"abc";的方式,可以在一定程度上提高程序的運行速度,因為JVM會自動根據棧中數據的實際情況來決定是否有必要創建新對象。而對於String

str = new

String("abc");的代碼,則一概在堆中創建新對象,而不管其字元串值是否相等,是否有必要創建新對象,從而加重了程序的負擔。這個思想應該是

享元模式的思想,但JDK的內部在這裡實現是否應用了這個模式,不得而知。

(3)當比較包裝類裡面的數值是否相等時,用equals()方法;當測試兩個包裝類的引用是否指向同一個對象時,用==。

(4)由於String類的immutable性質,當String變數需要經常變換其值時,應該考慮使用StringBuffer類,以提高程序效率。

Java 棧_Java棧與堆 | 學步園相关推荐

  1. java筆試題,Java筆試題附答案 | 學步園

    一.單項選擇題 1.Java是從()語言改進重新設計. A.Ada B.C++ C.Pasacal D.BASIC 答案:B 2.下列語句哪一個正確() A. Java程序經編譯後會產生machine ...

  2. java mdb文件_Java生成mdb文件[MS Access文件] | 學步園

    1. 在ClassPath下存一個空的blank.mdb. (也就是在你的項目中包含一個空白的.mdb文件) 2. 將項目中的blank.mdb另存到新的路徑. (可能是用戶選擇要導出mdb文件的保存 ...

  3. 八字易经算法之用JAVA实现完整排盘系统_八字易經演算法之用JAVA實現完整排盤系統 | 學步園...

    去年一天,一個朋友去看望病人回來就驚奇的告訴我,他發現和他朋友一起住院(肝膽科)的病人無一例外都是屬相為虎的病人,不是大一輪就是小一輪的.這是為什麼呢? 這不是什麼偶然,也不是什麼巧合.也許通過八字能 ...

  4. java bigdecimal.valueof_java 中的大數據類型(BigInteger和BigDecimal) | 學步園

    一.為什麼為用到BigInteger和BigDecimal這種數據類型呢? 我們非常清楚,java裡面整型int與浮點型float,double它們存放數據的範圍是有邊界的.那麼如果需要更大的數據時, ...

  5. java assertthat_assertThat用法 | 學步園

    ㈠ 一般匹配符 1.allOf 匹配符表明如果接下來的所有條件必須都成立測試才通過,相當於"與"(&&) assertThat( testedNumber, all ...

  6. mysql jdbc 5.1.6_mysql5.0+Mysqljdbc5.1.6.jar的整合 | 學步園

    今天早上開始就開始用Eclipse開發使用mysql的java Project和Tomcat Project,研究了一個上午,終於搞定. 其中java Project就是簡單的Main函數實現,Tom ...

  7. mysql存儲過程_Mysql存儲過程 | 學步園

    一.創建存儲過程 在創建存儲過程之前,首先要了解delimiter 分界符,默認sql 語句分界符是 ; 分號,但為了寫較長的存儲過程,需要將默認分割符修改掉,建議修改為 //,如此之後,sql 語句 ...

  8. matlab engevalstring,Matlab 執行engEvalString命令介紹 | 學步園

    MATLAB與VC混合編程指導書 在調用 Matlab 引擎之前,首先應在相關文件中加入一行: #include "enging.h" ,該文件包含了引擎 API 函數的說明和所需 ...

  9. python pyqt eric_python+PyQT+Eric安裝配置 | 學步園

    一.大綱內容: 1.預備PC環境: 2.預備安裝程序: 2.1.下載Python3.2 2.2.下載PyQt4 2.3.下載Eric5 3.安裝配置步驟: 3.1.安裝Pyhon3.2 3.2.安裝P ...

最新文章

  1. iOS-应用之间调用
  2. Java CPU占用率高分析
  3. Spring事务管理器分类
  4. linux命令we,Linux学习篇之基础命令
  5. 写二叉树程序时为什么总是报运行时错误_二叉树:一入递归深似海,从此offer是路人...
  6. 疑似荣耀V30 Pro 5G网络测试截图曝光:前置开孔双摄加持
  7. SQL Server 2000企业管理器中MMC无法创建管理单元的解决方法
  8. java读取txt文件_Java读取TXT文件的方法
  9. 中国海水产品加工行业发展现状及趋势分析,山东省产量最高「图」
  10. C语言fflush方法
  11. [图像几何变换]——图像的仿射变换、透射变换及图像金字塔
  12. 2022年度“强国杯”选拔赛 WriteUp
  13. 《Microduino实战》——2.7 总结
  14. iPhone 6/6Plus UI界面设计和适配尺寸规范
  15. MySQL主从复制与lvs+keepalived单点写入读负载均衡高可用实验
  16. 你知道二维码是什么码吗?目前流行的无线射频识别用的又是什么编码呢?它俩如何转换呢?
  17. [BUUCTF-pwn] qwb2018_opm
  18. 华为机试:连续出牌数量
  19. macbook上好用的解压软件_苹果电脑有什么好用的解压软件?推荐 Mac OSX 下最方便实用的六款解压缩软件...
  20. 学生信息管理页面HTML+CSS+JavaScript基础开发

热门文章

  1. 动动“意念”,音乐直流大脑,马斯克脑机接口真能实现?
  2. ARM裸机的知识点总结---------10、解决X210开发板软开关按键问题( 引脚功能复用)
  3. linuxCentOS如何汉化系统
  4. 10.2-vmstat命令
  5. 心情不好就狂吃?好心情心理:这是病,得治!
  6. Long转换为int
  7. easycode使用指南
  8. 编程小石头点餐小程序_点餐小程序,点餐系统,管理后台批量导入excel菜品数据...
  9. python-pyperclip模块
  10. 手机中丢失了数据怎么办