1. 程式人生 > >字串String的+和+=及迴圈操作String的原理

字串String的+和+=及迴圈操作String的原理

String物件是不可變的:意思就是無論是對String的新增或修改,出現一個全新的String內容時,都意味著誕生了一個新的物件。但是如果內容不變的話,增加的只是物件的引用而已。

例如:

String a = "ljh";
String b = "ljh";
String c = "ljh";

System.out.println(a==b);
System.out.println(b==c);

結果都是true

但是這種不可變性會產生一些效能上的問題,所以JVM對String物件過載“+”“+=”進行了一些優化

操作符“+”可以用來連線String

String aaa = "ljh";
String 
bbb = "big"; String ccc = aaa+bbb+"aaaa";

在jdk8中,上述程式碼中在底層其實是編譯器擅自呼叫了StringBuilder類進行+的操作,主要原因是StringBuilder的append()更加高效,我們來看一下位元組碼。

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String ljh
       2: astore_1
       3: ldc           #3                  // String big
       5: astore_2
       6: new           #4                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
      13: aload_1
      14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: aload_2
      18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: ldc           #7                  // String aaaa
      23: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: astore_3
      30: return

可以看出一共有四個物件,分別是三個String 和一個StringBuilder

我們再來看一下+=

String a = "aaa";
a += "bbb";

位元組碼如下

    Code:
       0: ldc           #2                  // String aaa
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String bbb
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: return

可以看出先建立了一個“aaa”字串,然後當a遇到+=時,建立了一個StringBuilder物件,並append了aaa字串。之後建立了一個“bbb”物件,然後append了bbb字串,最後呼叫StringBuilder的toString方法。

接下來再看看迴圈中呼叫+=會是什麼樣子

String a = "aaa";
a += "bbb";
for(int i=0;i<5;i++){
    a+="ccc";
}
    Code:
       0: ldc           #2                  // String aaa
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String bbb
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: iconst_0
      24: istore_2
      25: iload_2
      26: iconst_5
      27: if_icmpge     56
      30: new           #3                  // class java/lang/StringBuilder
      33: dup
      34: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      37: aload_1
      38: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      41: ldc           #8                  // String ccc
      43: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      46: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      49: astore_1
      50: iinc          2, 1
      53: goto          25
      56: return

可以看出先建立String物件aaa,之後建立StringBuilder並初始化StringBuilder append aaa,然後建立bbb物件,並append(  bbb),然後我們發現在迴圈中依舊建立了一個新的StringBuilder,也就是沒經過一次迴圈都要建立一個新的StringBuilder物件。

這時我們做一個優化,提前建立StringBuilder物件

String a = "aaa";
a += "bbb";
StringBuilder sb = new StringBuilder(a);
for(int i=0;i<5;i++){
    sb.append("ccc");
}

    Code:
       0: ldc           #2                  // String aaa
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String bbb
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: new           #3                  // class java/lang/StringBuilder
      26: dup
      27: aload_1
      28: invokespecial #8                  // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      31: astore_2
      32: iconst_0
      33: istore_3
      34: iload_3
      35: iconst_5
      36: if_icmpge     52
      39: aload_2
      40: ldc           #9                  // String ccc
      42: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      45: pop
      46: iinc          3, 1
      49: goto          34
      52: return
可以看出迴圈體跳回34行,並不會不斷地建立新的StringBuilder,大大提高了效率和減小了垃圾數量!,所以我們要注意自己的寫法!避免無謂的消耗

相關推薦

字串String的++=迴圈操作String原理

String物件是不可變的:意思就是無論是對String的新增或修改,出現一個全新的String內容時,都意味著誕生了一個新的物件。但是如果內容不變的話,增加的只是物件的引用而已。例如:String a = "ljh"; String b = "ljh"; String c

氣泡排序字串(String)物件處理字串的方法

氣泡排序 第一種方法 var times=0; var arr=[12,3,6,9,77,37]; for(var i=0;i<arr.length-1;i++){ //控制比較的行數 for (var j=0;j<arr.length-i-1;j+

四:Java之字符串操作String、StringBufferStringBuilder

equal const wstring str asi 有時 string對象 階段 stringbu string是我們經經常使用到的一個類型,事實上有時候認為敲代碼就是在重復的操作字符串,這是C的特點,在java中。jdk非常好的封裝了關於字符串的操

String[]List<String>的區別相互轉換

Hello,everybody。好幾天不見啦,我一直在想著怎麼整場大戲,琢磨寫個好點的文章。(其實是因為玩了一個星期,emmmm,因為懶)。 1.兩者的區別 結構方面: List< String >:泛型,非定長,可變。 String[]:陣列,定長,不可

matlab 迴圈儲存變數為.mat 以及save函式報錯:錯誤使用 save 引數必須包含字串(Argument must contain a string.)的處理辦法

目的是儲存一組名稱連續的.mat資料做深度學習用。 直接上程式碼: for i = 1 : 1 : loop_num T(:, :, i) = data(:, :, i); name = ['your_path/test_', num2str(i), '.ma

java中String字串拼接“+”StringBuffer的效率對比

1、前言 (1)最近在做資料傳輸時,由於接收的資料量較大,在字串拼接時使用了以前感覺方便的“+”進行字串拼接,最後拼接到最後時間越來越多,導致效率變慢。 2、String拼接 首先來看一下兩個String用“+”號拼接需要的時間 String aa="E0 00 00 00 00

javasc中字串(String)物件處理字串的方法

字串的屬性 length 的介紹: 在JavaScript 中,對於字串來說,要掌握的屬性就只有一個,那就是 length 屬性.我們可以通過 length屬性來獲取字串的長度. 語法:字串名稱.length 說明:length 屬性很簡單,但是在字串操作中經常要用到,這個大家一定

字串格式的方法%s、formatpython3.6新特性f-string型別註解

一、%s msg = '我叫%s,今年%s,性別%s' %('帥哥',18,'男') print(msg) # 我叫帥哥,今年18,性別男 二、format # 三種方式: # 第一種:按順序接收引數 s1 = '我叫{},今年{},性別{}'.for

String字串 切割替換

public static void main(String[] args) { String str = "adb,de,fg"; /** * 在當前字串中,用後面的替換掉字串中所有出現的前面的,返回新的字串 */ String replace =

論 java中String new String還有物件中的String字串在記憶體中的儲存

一直以來,所有人都說,java中的String型別是不可變的,可是為什麼不可變確很少有人說的透徹,String和new String的區別,物件中的String和直接定義一個String是否有區別,一直都是一知半解。看了很多文件都是各種猜測,沒有具體程式碼來

BigDecimal轉String,int,double簡單操作運算、方法

BigDecimal b = new BigDecimal(12.10); //BigDecimal 轉換成 string資料型別 string c = b.toString(); //BigDeci

C++中字串string整數int的互相轉化方式

Talk is cheap, show me the code. 一、string轉int的方式 採用最原始的string, 然後按照十進位制的特點進行算術運算得到int,但是這種方式太麻

python的字串String)及其常見操作(方法、函式)

字串(string) -----------------------------------------------------------------------------------------------------------------------------------------

字串 StringStringBuffer的區別(從程式碼講解)

Java面試中經常問到字串,下面是根據百度面試整理出來的內容: 一、String和StringBuffer有什麼區別? String的長度是不可變的,StringBuffer的長度是可變的。 如果你對字串中的內容經常進行操作,特別是內容要修改時,那麼使用StringBuff

Java入門之API的使用String StringBuilder類的常見方法

API:學習JAVA幫助文件;使用步驟:1.開啟API文件;2.點選左上角顯示按鈕3.點選索引標籤,在輸入框內輸入你要學習的內容;學習一個新的類的步驟:1.看類的宣告:搞清楚這個類的一個修飾情況(繼承,實現)2.看類的說明:看這個類的功能描述;3.看類的構造方法摘要:瞭解建

Object類中的toString()方法equals()方法,String類中的equals()方法==常量符號,StringBuffer帶緩衝的字串

1、Object類中toString() 所有的類都預設的繼承了Object類 Object類中的toString方法返回的是類的名字和該物件雜湊碼組成的字串 System.out.printf(類物件名)實際輸出的是該物件的toString()方法所返回的字串 為了實際需求需要子類重寫父類

Redis支持的五種數據類型相應操作String(字符串),Hash(哈希),List(列表),Set(集合)zset(sorted set:有序集合)

list 支持 哈希 keys 當前 zset 存在 key-value second key 命令(key命令:用於管理 redis 的key)相應操作: key 命令 說明 del key [key...] dump key 序列化給定 key

C++中string檔案流類(ofstream,ifstream)的基本操作---按行讀取文件

先說明一個問題:java構建物件只能使用new的方法,而C++則不然。 下面程式碼實現讀取test.txt檔案中的內容並顯示,同時將某一個字串輸入到檔案test1.txt中。 函式getline(ifstream& param1, string& param

matlab:字串陣列string的區別

前言 在用sprintf()格式化輸出時,發現formatSpec可以是單引號建立的字串陣列,也可以是string(‘str’)建立的string。所以產生了疑惑,這兩者有什麼區別,各適用在什麼場合 官方文件 Character arrays and st

C#: 字串string位元組陣列byte[]的轉換

string轉byte[]: byte[] byteArray = System.Text.Encoding.Default.GetBytes ( str ); byte[]轉string: string str = System.Text.Encoding.Default.GetStri