JDK6和JDK7中String的substring()…

在JDK6與JDK7這兩個版本中,substring(int beginIndex, int endIndex)方法是不同的. 瞭解兩個版本間的區別可以讓你更好地使用它們. 爲簡單起見,本文中以 substring() 表示 substring(int beginIndex, int endIndex).

1. substring()功能簡介
String對象的substring(int beginIndex, int endIndex)方法返回此對象的一個子串,從beginIndex 開始,一直到 endIndex-1 結束,共 (endIndex - beginIndex)個字符。
新手提示: 
    1.1 String 的索引和數組一樣,都是從0開始.
    1.2 注意,方法名字是substring(),全小寫.
    1.3 有個重載方法是substring(int beginIndex),從beginIndex索引處開始,取得子字符串.

 

[java] view plaincopy
  1. String x = "abcdef";  
  2. int begin=1;  
  3. int end=3;  
  4. x = x.substring(begin, end);  
  5. System.out.println(x);  


執行結果(包含索引爲 begin,直到 end-1 的字符):

 

[plain] view plaincopy
  1. bc  


2. 當substring()被調用時,發生了什麼?
你應該知道,因爲 x 是不可變的,當 指定 x 等於 x.substring(begin, end)時,實際上 x 指向了一個全新的字符串,如下圖所示:

圖1



然而,這幅圖並不是完全正確的,堆內存中所真正發生的事也不是這麼簡單.那麼,在JDK6和JDK7之間 substring()的調用到底有些什麼區別呢?

3. JDK 6中的substring()方法
String實際上是一個字符數組.在 JDK6中, String對象主要包含3個屬性域: 

[java] view plaincopy
  1. private final char value[];  
  2. private final int offset;  
  3. private final int count;  


他們用於存儲實際的字符數組,數組的第一個索引,以及String的字符個數.
當調用 substring() 方法時,創建了一個新的String對象,但是string的value[] 屬性域仍然指向堆內存中的原來的那個數組。區別就是 兩個對象的 count 和 offset 這兩個值不同了。 如下圖所示:

圖2

要解釋這個問題,下面是最關鍵部分的代碼:

[java] view plaincopy
  1. // JDK6,包級私有構造,共享 value數組提升速度  
  2. String(int offset, int count, char value[]) {  
  3.     this.value = value;  
  4.     this.offset = offset;  
  5.     this.count = count;  
  6. }  
  7.   
  8.   
  9. public String substring(int beginIndex, int endIndex) {  
  10.     // ... 檢查邊界的代碼  
  11.     // 如果範圍和自己一模一樣,則返回自身,否則用value字符數組構造一個新的對象  
  12.     return ((beginIndex == 0) && (endIndex == count)) ? this :  
  13.         new String(offset + beginIndex, endIndex - beginIndex, value);  
  14. }  


4. JDK 6中substring()引起的問題
如果有一個"非常"長的字符串,但每次使用substring()時只想要很小的一部分,那麼將會引起另一個性能問題: 雖然你只需要很小的一部分,但是持有了整個value[]的引用,從而導致大量內存被佔用。
要解決這個問題,在JDK6中可以讓其指向一個真正的子字符串,示例代碼:

[java] view plaincopy
  1. x = x.substring(begin, end) + "";  


5. JDK 7中的substring()方法
在JDK 7 中這個問題得到改進, substring()方法真實地在堆內存中創建了另一個字符數組.

圖3


[java] view plaincopy
  1. // JDK 7, 權限變爲 public   
  2. public String(char value[], int offset, int count) {  
  3.     // ... 檢查邊界..  
  4.     // value 數組拷貝  
  5.     this.value = Arrays.copyOfRange(value, offset, offset+count);  
  6. }  
  7.   
  8.   
  9. public String substring(int beginIndex, int endIndex) {  
  10.     // ... 檢查邊界..  
  11.     int subLen = endIndex - beginIndex;  
  12.     // 如果和自身一樣,那就返回自身,否則返回構造的新對象  
  13.     return ((beginIndex == 0) && (endIndex == value.length)) ? this  
  14.                 : new String(value, beginIndex, subLen);  
  15. }  


參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章