字符串鏈接你用+仍是用StringBuilder

前言

據我所知字符串確實已經成爲 Java 開發人員最經常使用的類了,並且是大量使用。咱們都知道,String 實際上是封裝了字符,因此倆字符串鏈接就是將字符串對象裏面的字符連起來。不少人習慣使用+來鏈接字符串,也有人會用 StringBuilder 的append方法。java

"+"編譯後

看看若是咱們在程序中直接使用+來鏈接字符串的狀況,用下面一個簡單的例子來講明,進行兩個字符串鏈接操做,即s3 = s1 + s2bash

public class TestString {
	public static void main(String[] args) {
		String s1 = "www";
		String s2 = "ccc";
		String s3 = s1 + s2;
	}
}
複製代碼

接着javap -c TestString.class看一下編譯後的狀況,能夠看到編譯器實際上是對+進行了轉換的,轉成了 StringBuilder 對象來操做了,首先使用 s1 建立 StringBuilder 對象,而後用 append方法鏈接 s2,最後調用toString方法完成。併發

public class com.seaboat.string.TestString {
  public com.seaboat.string.TestString();
    Code:
       0: aload_0
       1: invokespecial #8 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String www
       2: astore_1
       3: ldc           #18 // String ccc
       5: astore_2
       6: new           #20 // class java/lang/StringBuilder
       9: dup
      10: aload_1
      11: invokestatic  #22 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      14: invokespecial #28 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      17: aload_2
      18: invokevirtual #31 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      24: astore_3
      25: return
}
複製代碼

"+"與"append"等價嗎

前面能夠看到+在編譯器做用下都會轉成 StringBuilder 的append方法執行,因此若是拋開運行效率來講,它們其實本質是同樣的。app

本質同樣是否就能說明它們時等價的呢?或者說可否爲了方便直接用+來鏈接字符串,剩下的事就交給編譯器了?繼續看個例子,在這個例子中有個 for 循環進行字符串鏈接操做。機器學習

public class TestString2 {
	public static void main(String[] args) {
		String s = "www";
		for (int i = 0; i < 10; i++)
			s += i;
	}
}
複製代碼

編譯後的狀況以下,不熟悉指令不要緊,咱們只看重要的部分,if_icmplt 8,這個就是 for 循環的條件判斷,小於10則不斷跳到8的位置,8後面其實就是建立 StringBuilder 對象,並以本地變量s的值初始化該對象,接着再將本地變量i append到 StringBuilder 對象中,最後調用toString方法將所得值存到本地變量s。分佈式

這樣來看循環中每次都要建立 StringBuilder 對象,並且要調用toString方法,這樣的執行效率顯然比較低,並且增長了 GC 的壓力。學習

public class com.seaboat.string.TestString2 {
  public com.seaboat.string.TestString2();
    Code:
       0: aload_0
       1: invokespecial #8 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String www
       2: astore_1
       3: iconst_0
       4: istore_2
       5: goto          30
       8: new           #18 // class java/lang/StringBuilder
      11: dup
      12: aload_1
      13: invokestatic  #20 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      16: invokespecial #26 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      19: iload_2
      20: invokevirtual #29 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      23: invokevirtual #33 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      26: astore_1
      27: iinc          2, 1
      30: iload_2
      31: bipush        10
      33: if_icmplt     8
      36: return
}
複製代碼

友好寫法

把事情都丟給編譯器是不友好的,爲了能讓程序執行更加高效,最好是咱們本身來控制 StringBuilder 的實例,好比下面,只建立一個 StringBuilder 實例,後面用append方法鏈接字符串。ui

public class TestString3 {
	public static void main(String[] args) {
		StringBuilder sb = new StringBuilder("www");
		for (int i = 0; i < 10; i++)
			sb.append(i);
	}
}
複製代碼

編譯後的狀況以下,首先建立一個 StringBuilder 對象,使用字符串"www"來實例化該對象,接着循環調用append方法將本地變量i添加到 StringBuilder 對象中。spa

public class com.seaboat.string.TestString3 {
  public com.seaboat.string.TestString3();
    Code:
       0: aload_0
       1: invokespecial #8 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #16 // class java/lang/StringBuilder
       3: dup
       4: ldc           #18 // String www
       6: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
       9: astore_1
      10: iconst_0
      11: istore_2
      12: goto          24
      15: aload_1
      16: iload_2
      17: invokevirtual #23 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      20: pop
      21: iinc          2, 1
      24: iload_2
      25: bipush        10
      27: if_icmplt     15
      30: return
}
複製代碼

-------------推薦閱讀------------.net

個人2017文章彙總——機器學習篇

個人2017文章彙總——Java及中間件

個人2017文章彙總——深度學習篇

個人2017文章彙總——JDK源碼篇

個人2017文章彙總——天然語言處理篇

個人2017文章彙總——Java併發篇


跟我交流,向我提問:

這裏寫圖片描述

公衆號的菜單已分爲「讀書總結」、「分佈式」、「機器學習」、「深度學習」、「NLP」、「Java深度」、「Java併發核心」、「JDK源碼」、「Tomcat內核」等,可能有一款適合你的胃口。

爲何寫《Tomcat內核設計剖析》

歡迎關注:

這裏寫圖片描述
相關文章
相關標籤/搜索