String類——StringBuilder類的源碼及內存分析(java)


相同:底層均采用字符數組value來保存字符串

區別:String類的value數組有final 修飾,指向不可改,同時private 未提供修改value數組的方法。StringBuilder類的value數組沒有final修飾,可以改變指向,且可以擴容,擴容通過新建字符數組完成。

 

  首先分析String的源碼:

 

  可以看到String類有final修飾,所以String類不能被繼承。這保證對String對象方法的調用確實運行的是String類的方法,而不是經其子類重寫后的方法。往下看,是value數組,該字符數組被用於存儲String的字符串,即”abcd”String里存儲為value[]:’a’, ’b’, ‘c’, ‘d’ 的字符數組,final修飾,表示value指向的數組不變,但是數組里的值可變,但是有private修飾,且String類並沒有提供修改value數組內容的方法,所以String對象的值一旦賦值就不可變

  例如:下列字符數組cfinal修飾,表示c的指向不變,但修改c的內容是可行的。

 

 

  賦值前后的內存變化:

  賦值前:

 

  賦值后:

 

第一部分:構造函數

  接下來看看常用的String類的構造函數:

  首先空串 ””  “abcd” 都是字符串對象

 

  再看這兩個構造函數:

 

  對於以下代碼:

String str1 = new String();

String str2 = new String(“abcd”);

  在構造函數中分別對應:

this.value = “”.value;

this.value = “abcd”.value;

  是將 “” value值賦予str1value,將 “abcd” value所指對象賦給str2value

 

  再看另一個常用的構造函數:

 

  該函數使用數組復制函數,將參數數組c復制給str3的字符數組value

  再看看數組復制函數Arrays.copyOf():

 

  其中參數original是要被復制的字符數組,newLength是要復制的長度,也是新數組的長度。函數返回復制完的新數組。

char[] c = {‘a’, ‘b’, ‘c’, ‘d’};

String str3 = new String(c);

的內存分析如下:

 

第二部分 常用函數

  1. length()函數,返回的是字符數組value的長度

 

  2.判空isEmpty() 函數,利用字符數組長度是否為0

   

  3.重寫的 equals函數

 

首先判斷是否為同一個對象,若不是,再判斷是否是String對象,強制轉為String類型后,判斷兩個String對象的value數組是否長度相同,接下來對兩個value字符數組的內容從0開始向后比較。即equal()為真的情況是: 兩個對象相同;都是String對象且value字符數組內容相同。

 

  函數為真的兩種情況:

  情況一:指向同一對象

 

  情況二:均為String對象且value數組內容一致

 

  4.compareTo() 函數

 

即在均存在字符的情況下,返回第一個不相同字符之差,前lim個字符相同(即長字符串的前lim個恰好是短字符串)則返回兩個字符串長度之差。

  5.substring 函數

  substring(int)

 

該函數返回從給定參數位置起到字符串結束的新字符串。如果給定從0開始,則返回原本的String對象,否則返回一個新的String對象。

  substring(int, int):

如果要獲取的子串是從0到最后,則返回原本的String對象,否則返回一個新的String對象。

  6.字符替換 replace(char, char);

 

函數先判斷替換字符和被替換字符是否相同,若相同則返回原String對象,不同則先找到要替換的字符位置,接下來創建一個新的字符數組,將保存替換后的字符串,最后返回一個新的String對象。

  7.toString函數

 

因為已經是String對象,所以返回自身。

 

 

  接來下看StringBuilder類的源碼:

  StringBuilder類也是由final修飾,即也不能被繼承。同時該類繼承了抽象父類AbstractStringBuilder.

 

第一部分   構造函數

  StringBuilder strb = new StringBuilder();

  可以看到構造函數對父類構造函數傳的參數為16,分析父類對應的構造函數:

 

  父類創建了一個長度為16的字符數組,將value指向該新數組,那么value是什么呢?

 

value也是字符數組,和String類不同的是,該字符數組沒有final 修飾,即value的指向可以改變,同時權限為默認,即同類和同包可用,該類和StringBuilder在同一個包中。同時使用count變量記錄字符個數(不同於value數組長度,value長度是容量)。

  另一個構造函數:

  StringBuilder strb = new StringBuilder(20);

 

即通過父類構造函數,創建一個新的字符數組。該數組長度為參數值。

  傳入字符串的構造函數:

  StringBuilder strb = new StringBuilder(“abcd”);

 

初始StringBuildervalue數組容量設置為傳入字符串長度加上16,再通過append函數將str寫入,分析append函數:

 

先調用父類的append方法:

 

ensureCapacityInternal函數:參數是當前對象的value中字符長度與傳入字符串長度之和,也即是value的容量最小值。

 

如果需要的容量最小值大於目前value容量,調用擴容函數enpandCapacity函數。

enpandCapacity函數源碼:

 

  擴容的新容量為當前value的容量2倍加2,如果擴容后的容量還是比需要的最小容量小,則直接擴容為需要的最小容量,再將當前value內容復制給一個新的長度為newCapacity的字符數組,再將value指向這個擴容后的新數組。即擴容是通過開辟新數組完成的,返回的也是新創建的新數組

 

  接着,append函數執行完ensureCapacityInternal函數后,this對象的value數組已經指向一個擴容后的新數組,並且之前的value數組里的值也復制到新的value數組中,接下來執行getChars函數:

  getChars函數源碼:

 

  即該函數是將調用的string對象的value數組從srcBeginsrcEnd復制給目標數組dst,從dst數組的第dstBegin位置開始。

  append函數中執行完str.getChars函數后就將參數str的內容追加到StringBuilder對象的value數組后面,再更新count值,返回調用對象。

  內存可以描述為:

 

第二部分  常用函數

  1. 刪除函數

  deleteCharAt(int)

 

 看父類的對應函數

 

即刪除索引為index處的字符。通過調用數組復制函數來完成,將索引后面的內容依次復制到從索引開始的位置上,即通過覆蓋的原理完成,更新count

  2.插入函數insert(int, char)

 

父類對應函數:

 

即將字符c 插入到索引offset位置上,首先確保value數組容量足夠,然后通過數組復制,將索引位置開始全部向后移一位,再將索引位置賦值c,更新count

  3.toString函數

 

返回一個新創建的String對象,內容為value保存的字符。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM