懷着初次見你的心情,泥瓦匠和你一起打開jdk1.7文檔。我最近想寫一些關于jdk1.7的了解,都知道jdk8出來了,新特性我準備下階段有空學習。
泥瓦匠想說,閱讀e文文檔有利于體會原汁原味。但畢竟國内大牛翻譯的很不錯了,咱們不加評判,喜歡哪種自己挑。能抓老鼠,能解決實際項目,适應業務環境的就是你學到了。請看下面的小例子:
清單1.1
泥瓦匠,你不是在忽悠我嗎?這麼簡單的程式,你想說什麼。說實在确實是基礎,但基礎紮實才能有更高的突破。就想泥瓦匠默默為自己,為家人為未來打基礎。
可以見,string是不需要用new來建立一個新對象的類。它是不可變的(constant),其值(像"abc"建立後,不可改變)。自
然,string其實實作了基本類型char的序列的功能,是以中文名“字元串”。這裡大家有可能疑惑,泥瓦匠就找到jdk源碼證據給你們看:

這段代碼是來自jdk1.7源碼裡面的,char型value數組的形式組成了string類的内容。其操作就是針對value數組操作。這樣想是否豁然開朗,然後心裡自喜“so easy”。其實難點下面,大家慢慢看下去。
依舊看代碼清單1.1,java提供了一個特殊的連接配接操作符(concatenation operator)+ 用于直接來拼接字元串。其中操作常用的方法羅列如下:
跟着泥瓦匠運作下清單1.1,你可以看到列印出來:
很簡單的發現答案就是我們心目中想要的。這裡我不打算很詳細的解釋api,這樣會失去文章的趣味和讀者的興趣。我喜歡用例子來引導出,對于string在我項目和經驗中的總結。
下面就以我們substring()方法來解釋下源碼,可以看到其中實作的細節:
邏輯大緻歸納如下:
1. 首先判斷傳入值得可靠性,判斷傳入的開始和結束,還有子字元串的長度。這是在每個系統開發需要在細節中關心的。關心細節,才能幹大事。
2. 然後判斷是不是原string,是的話,直接傳回this,如果不是就new一個子串。這個構造函數實作也不難,如果有興趣可以看看,其實也就是實作char數組的拷貝。
就string基礎部分泥瓦匠就介紹這裡,在這裡我們可以得出的結論是:設計源于生活,源于簡單。像一個方法和一個類結構的設計,單一簡單。是以我們學習以後設計方法要簡單,耦合度不能太高。
有人看到這個會大吃一驚,然後質問說“老師說,string 和 == 沒關系,你是不是瞎扯淡”。哈哈,我隻能說,隻不過修行在實際。舉個小栗子吧。
看下面清單1.2
看到這裡,你是否覺得這麼簡單,心裡想着肯定是“false,泥瓦匠真逗。”運作下,結果卻是
結論: 關于 == ,我們要知道 == 用于比對記憶體單元的内容。java中對比的就是兩個記憶體單元的内容(其實就是一串數字)。至于八個基本類型直接比較值。例如清單1.2,比較的是兩個引用,兩個引用對比的是引用的對象的邏輯值(也就是兩個對象對應記憶體單元的内容)。
泥瓦匠的記憶宮殿:就是相當于 泥瓦匠和我的親姐姐比較我們兩個的爸爸,畢竟的爸爸都是那一個,當然是true。
"a" + "b"的生命是怎麼樣的呢?網絡牛人有些反編譯會發現其實是類似下面的過程:
究竟jvm是怎麼把"a" +
"b"和"ab"知道他們是一樣的呢。我們回顧下,因為string是不可變類,也就是靜态java語言的特點。這涉及到jvm的優化方案。但jvm很死
闆,它不會很人工智能的像人腦,它會的隻是它能處理的,是以好好了解jvm有助于開發更好的額程式。比如定義一個ab字元串常量夠了,它不會在再 子串 a
b。這就是它的優化方案。
泥瓦匠的記憶宮殿:這就是偷懶思想,今天我要見我爸爸,明天姐姐要見爸爸。合并下呗,後天一起去見爸爸。
就此我們可以得出結論:編譯器給我帶來它對程式的優化,為了提升程式的效率和記憶體資源等,是以我們可以明白,如何掌握其特性寫出更好的代碼。
補充個例子,看看你們真的掌握沒?
這涉及了jvm的優化,答案是:
如果猜到了,證明你真懂了。泥瓦匠還是耐心的講解下:
第一個false:b是包括了一個常量和一個引用的值,是以。
第二個false: 你也可以猜到外部方法的常量在本方法隻是一個引用。是以。
結論如下:我們現在如果不知道jvm怎麼在編譯時期優化,我們就慢慢了解它們。
這個例子不好寫,泥瓦匠就帶你們看看源碼等。equals并不陌生,相信大家的系統裡面有很多設計到這個方法。
其實equals是實作了object的equals方法,而在object的equals:
它其實就是實作了 == 比較記憶體的内容。
q:泥瓦匠,為什麼string要重寫object,這不導緻意義不一緻了嗎?
a:
非也非也,string是string,string用來處理的事物邏輯和業務和object完全不同。equals顧名思義等于,等于不表示完全相等。
而是一樣或者相似。正所謂業務看情況,比如泥瓦匠處理得金融資料一般小數點10幾位,那請問你還會在乎小數點10位後的的值嗎,當它們比較的時候,你不會
在乎,是以這就是相似。
那麼我們就看一下string實作的equals方法:
簡單描述下,就是周遊兩個數組最好的條件下,就是要麼長度不同,要麼前面幾個不同。直接傳回false。
q:如果碰到大字元串這就悲劇了。是以一些大字元串怎麼處理呢。
a:其實實際中,大字元串也難見。但說處理的話,大字元串比對可以考慮分割比對或是啥的這裡就不展開了。
q:equals重寫 和 hashcode 有關系嗎?
a:這裡我們要先說明hashcode方法提供對象的hashcode值,傳回與預設的
system.identityhashcode()一緻。其廣泛用于集合架構。到後面我也會講到。hashcode的源于計算機的比較源于數字,而不是
對象。是以一個hashcode值辨別一個對象,産生了對象相關的很多算法。但是預設的hashcode犯法會發起對本地的調用開銷很大。
intern大家就有點陌生了。咱們首先得普及下常量池的概念,常量池(constant pool)指的是在編譯期被确定,并被儲存在已編譯的.class檔案中的一些資料。它包括了關于類、方法、接口等中的常量,也包括字元串常量。然後看看下面的例子:
當調用 intern()方法時,jvm 會在這個常量池中通過 equals()方法查找是否存在等值的 string,如果存在,則直接傳回常量池中這個 string 對象的位址;沒有找到,則會建立等值的字元串,傳回其位址。
思考提升:這有什麼用呢?
答曰:可以用于一些常量的存儲比較,枚舉(枚舉底層就是字元串,哈哈)。當想常量比常量,多數的情況下,考慮效率則選擇 intern()而不是equals。
string是java基礎元件重要的一部分。