String是Java中一個比較基礎的類,每個開發人員都會常常接觸到。並且,String也是面試中常常會考的知識點。String有不少方法,有些方法比較經常使用,有些方法不太經常使用。今天要介紹的subString就是一個比較經常使用的方法,並且圍繞subString也有不少面試題。面試
substring(int beginIndex, int endIndex)
方法在不一樣版本的JDK中的實現是不一樣的。瞭解他們的區別能夠幫助你更好的使用他。爲簡單起見,後文中用substring()
表明substring(int beginIndex, int endIndex)
方法。數組
substring(int beginIndex, int endIndex)
方法截取字符串並返回其[beginIndex,endIndex-1]範圍內的內容。性能
String x = "abcdef"; x = x.substring(1,3); System.out.println(x);
輸出內容:this
bc
你可能知道,由於x是不可變的,當使用x.substring(1,3)
對x賦值的時候,它會指向一個全新的字符串:spa
然而,這個圖不是徹底正確的表示堆中發生的事情。由於在jdk6 和 jdk7中調用substring時發生的事情並不同。設計
String是經過字符數組實現的。在jdk 6 中,String類包含三個成員變量:char value[]
, int offset
,int count
。他們分別用來存儲真正的字符數組,數組的第一個位置索引以及字符串中包含的字符個數。code
當調用substring方法的時候,會建立一個新的string對象,可是這個string的值仍然指向堆中的同一個字符數組。這兩個對象中只有count和offset 的值是不一樣的。對象
下面是證實上說觀點的Java源碼中的關鍵代碼:blog
//JDK 6 String(int offset, int count, char value[]) { this.value = value; this.offset = offset; this.count = count; } public String substring(int beginIndex, int endIndex) { //check boundary return new String(offset + beginIndex, endIndex - beginIndex, value); }
若是你有一個很長很長的字符串,可是當你使用substring進行切割的時候你只須要很短的一段。這可能致使性能問題,由於你須要的只是一小段字符序列,可是你卻引用了整個字符串(由於這個很是長的字符數組一直在被引用,因此沒法被回收,就可能致使內存泄露)。在JDK 6中,通常用如下方式來解決該問題,原理其實就是生成一個新的字符串並引用他。索引
x = x.substring(x, y) + ""
關於JDK 6中subString的使用不當會致使內存系列已經被官方記錄在Java Bug Database中:
內存泄露:在計算機科學中,內存泄漏指因爲疏忽或錯誤形成程序未能釋放已經再也不使用的內存。 內存泄漏並不是指內存在物理上的消失,而是應用程序分配某段內存後,因爲設計錯誤,致使在釋放該段內存以前就失去了對該段內存的控制,從而形成了內存的浪費。
上面提到的問題,在jdk 7中獲得解決。在jdk 7 中,substring方法會在堆內存中建立一個新的數組。
Java源碼中關於這部分的主要代碼以下:
//JDK 7 public String(char value[], int offset, int count) { //check boundary this.value = Arrays.copyOfRange(value, offset, offset + count); } public String substring(int beginIndex, int endIndex) { //check boundary int subLen = endIndex - beginIndex; return new String(value, beginIndex, subLen); }
以上是JDK 7中的subString方法,其使用new String
建立了一個新字符串,避免對老字符串的引用。從而解決了內存泄露問題。
因此,若是你的生產環境中使用的JDK版本小於1.7,當你使用String的subString方法時必定要注意,避免內存泄露。