1. 程式人生 > 其它 >Java漫談9

Java漫談9

上次聊String的時候聊到了String為什麼可以在不new的情況下建立,說實話,這個問題我也沒有答案,直到看到了這篇帖子,才敢說知道了為什麼。

《Java String 兩種不同的賦值方案比較》

http://blog.163.com/woshihezhonghua@126/blog/static/1271436362012101214031911/

簡單來說,就是因為java的編譯器會自動給你加上。由此,我想到兩點:

第一是,java中的那些基本資料型別,會不會也是由編譯器自動加上new這個關鍵字的。搜了一下必應,沒搜到什麼有效的答案。

第二是,String是引用資料型別,那既然是引用資料型別,為什麼不像其它的引用資料型別一樣,直接用new這個關鍵字來建立物件,而非要用弄出一個類似於基本資料型別的建立物件的方式。按照存在即合理的邏輯,那我們就試著從這二者建立流程的不同這個角度去看看能不能得出結論。

先說一下一個概念,棧記憶體和堆記憶體。你可以把它們看做在記憶體中儲存運算資料的兩個倉庫,一個儲存的是資料的變數名,相當於資料的別名,或者是資料的標籤。另一個是儲存資料本身,比如字元陣列“Hello World”。另外還有一個常量池的概念,它是不同於堆疊的另一個儲存區域,可以可以把它當做是一個常用工具存放倉庫。

我們先來看看用new這個關鍵字,它的生成過程是什麼樣的:

String str1 = new String("hello");

首先,系統會先在常量池中尋找有沒有“hello”,如果沒有的話,就先在常量池中建立“hello”物件,然後再在堆記憶體中建立“hello”物件(也就是把“hello”放入堆記憶體),然後再把它的地址值傳給棧記憶體中的str1。如果常量池中有“hello”物件了,那麼在常量池中不會再建立,但在堆記憶體中會再建立的。如果常量池中的“hello”長時間沒有被引用,java的垃圾回收器就會自動將它回收,釋放“hello”物件所佔用的空間。對於堆記憶體中的“hello”物件也是如此。

其次再來看看直接賦值的方式,流程是怎麼樣的:

String str2 = "hello";

系統會先在常量池中尋找有沒有“hello”物件,如果有的話就直接使用,沒有的話就在常量池中新建一個,也叫入池。而堆疊當中則不需要開闢新空間。

如此一來,如果下次還有String的物件也用直接賦值的方式定義為“hello”,既不需要再次在常量池中建立,又不需要在堆疊中建立,直接指向這個堆疊中的“hello”物件即可。

再進一步,也就是說用直接賦值的方式定義兩個String型別的物件,用雙等號“==”判斷的話,結果為true。

這裡補充說一下,在java中,雙等號是用來判斷相等的,在String中它判斷的是物件的地址是否相等,若要判斷String的值是否相等,要用equals方法。

以此再進一步,要是用new的方式和直接賦值的方式分別建立的話,也就是用str1與str2比較,結果為false。

但如果我就是想要用讓str1與str2相等,該怎麼做呢。因為str1對物件的引用是用的是物件在堆記憶體中的地址,如果能把這個引用的地址變為“hello”物件在常量池中的物件,這樣雙等號判斷的時候就會為true了。而java中也提供了這樣的方法 —— intern(),也叫“入池方法”,具體用法如下:

String str1 = new String("hello").intern();

所以總的來說,用直接賦值的方法效率會比較高。

最後,我想說說我看懂了這種設計思想之後的感受。在計算機中,仍然是十分看中效率的。尤其在看中效率的過程中,可能會衍化出一些我們看似差不多,效果也差不多的相似方法或屬性。這些東西一開始我只是會用,但說不上原因,在逐漸的模仿之中逐漸地形成了習慣用法,而新入門的人又會順著這個方式一輪一輪,反覆迴圈。如果在用熟了,形成習慣了之後,我們能去進一步地瞭解一下原理,也許就能使我們對程式碼的具體使用場景理解加深,然後再用到程式設計中,做到合適的程式碼放到合適的地方,最終能在程式設計效率和程式執行效率上得到一些提升。

今天我與你聊了String的直接賦值的建立方式,希望對你使用String有幫助,我們下回見。

清單

  1. 總的來說,用直接賦值的方式效率比較高。
  2. 用new的方式建立String物件後,可以用intern()方法將其放入常量池中。
  3. 在String中,雙等號是判斷物件的地址是否相等,用equals才是判斷物件的值是否相等。