天天看點

[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)1.2 你好 String1.3 String字元串操作1.3  == 與 equals 不是親家1.4 也不難 泥瓦匠再出奇招1.5 equals碰到n長字元串呢?1.6 intern妙用總結

        懷着初次見你的心情,泥瓦匠和你一起打開jdk1.7文檔。我最近想寫一些關于jdk1.7的了解,都知道jdk8出來了,新特性我準備下階段有空學習。

        泥瓦匠想說,閱讀e文文檔有利于體會原汁原味。但畢竟國内大牛翻譯的很不錯了,咱們不加評判,喜歡哪種自己挑。能抓老鼠,能解決實際項目,适應業務環境的就是你學到了。請看下面的小例子:

清單1.1

      泥瓦匠,你不是在忽悠我嗎?這麼簡單的程式,你想說什麼。說實在确實是基礎,但基礎紮實才能有更高的突破。就想泥瓦匠默默為自己,為家人為未來打基礎。

可以見,string是不需要用new來建立一個新對象的類。它是不可變的(constant),其值(像"abc"建立後,不可改變)。自

然,string其實實作了基本類型char的序列的功能,是以中文名“字元串”。這裡大家有可能疑惑,泥瓦匠就找到jdk源碼證據給你們看:

[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)1.2 你好 String1.3 String字元串操作1.3  == 與 equals 不是親家1.4 也不難 泥瓦匠再出奇招1.5 equals碰到n長字元串呢?1.6 intern妙用總結

        這段代碼是來自jdk1.7源碼裡面的,char型value數組的形式組成了string類的内容。其操作就是針對value數組操作。這樣想是否豁然開朗,然後心裡自喜“so easy”。其實難點下面,大家慢慢看下去。

        依舊看代碼清單1.1,java提供了一個特殊的連接配接操作符(concatenation operator)+ 用于直接來拼接字元串。其中操作常用的方法羅列如下:

跟着泥瓦匠運作下清單1.1,你可以看到列印出來:

        很簡單的發現答案就是我們心目中想要的。這裡我不打算很詳細的解釋api,這樣會失去文章的趣味和讀者的興趣。我喜歡用例子來引導出,對于string在我項目和經驗中的總結。

下面就以我們substring()方法來解釋下源碼,可以看到其中實作的細節:

[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)1.2 你好 String1.3 String字元串操作1.3  == 與 equals 不是親家1.4 也不難 泥瓦匠再出奇招1.5 equals碰到n長字元串呢?1.6 intern妙用總結

邏輯大緻歸納如下:

        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:

[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)1.2 你好 String1.3 String字元串操作1.3  == 與 equals 不是親家1.4 也不難 泥瓦匠再出奇招1.5 equals碰到n長字元串呢?1.6 intern妙用總結

它其實就是實作了 == 比較記憶體的内容。

q:泥瓦匠,為什麼string要重寫object,這不導緻意義不一緻了嗎?

a:

非也非也,string是string,string用來處理的事物邏輯和業務和object完全不同。equals顧名思義等于,等于不表示完全相等。

而是一樣或者相似。正所謂業務看情況,比如泥瓦匠處理得金融資料一般小數點10幾位,那請問你還會在乎小數點10位後的的值嗎,當它們比較的時候,你不會

在乎,是以這就是相似。

        那麼我們就看一下string實作的equals方法:

[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)1.2 你好 String1.3 String字元串操作1.3  == 與 equals 不是親家1.4 也不難 泥瓦匠再出奇招1.5 equals碰到n長字元串呢?1.6 intern妙用總結

        簡單描述下,就是周遊兩個數組最好的條件下,就是要麼長度不同,要麼前面幾個不同。直接傳回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基礎元件重要的一部分。