簡體   English   中英

編譯器是否針對常量字符串優化Stringbuffer / StringBuilder.append()?

[英]Does the compiler optimize Stringbuffer/StringBuilder.append() for constant strings?

我讀了Jon Skeet關於用+連接字符串的答案 我想知道編譯器是否還使用StringBuffer / StringBuilder識別附加的constand字符串。

這個構建URL的代碼有一個好的意圖:

StringBuffer sb = new StringBuffer(constant1);
sb.append(nonconstant);
sb.append("?");
sb.append(constant2);
sb.append("=");
sb.append(constant3);
sb.append("&");
sb.append(constant4);
sb.append("=");
sb.append(constant5);

但是,如果編譯器沒有為常量優化Stringbuffer.append(),我會說以下代碼會更有效:

StringBuffer sb = new StringBuffer(constant1);
sb.append(non-constant);
sb.append("?" + constant2 + "=" + constant3 + "&" + constant4 + "=" + constant5);

因為編譯器會在編譯時優化+字符串連接。

為什么不嘗試一下呢? 在java 1.7中,以下類的主要方法:

public class Concat1
{
    private static final String constant2 = "c2";
    private static final String constant3 = "c3";

    public void main(String[] args) 
    {
        StringBuilder sb = new StringBuilder();
        sb.append(args[0]);
        sb.append("?");
        sb.append(constant2);
        sb.append("=");
        sb.append(constant3);
        System.out.println(sb.toString());
    }
}

(為了清晰起見,我更改了常量的數量)產生以下字節代碼:

public class Concat1 {
  public Concat1();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return        

  public void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #3                  // Method java/lang/StringBuilder."":()V
       7: astore_2      
       8: aload_2       
       9: aload_1       
      10: iconst_0      
      11: aaload        
      12: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: pop           
      16: aload_2       
      17: ldc           #5                  // String ?
      19: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: pop           
      23: aload_2       
      24: ldc           #6                  // String c2
      26: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: pop           
      30: aload_2       
      31: ldc           #7                  // String =
      33: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      36: pop           
      37: aload_2       
      38: ldc           #8                  // String c3
      40: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: pop           
      44: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      47: aload_2       
      48: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      51: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      54: return        
}

而以下課程:

public class Concat2
{
    private static final String constant2 = "c2";
    private static final String constant3 = "c3";

    public void main(String[] args) 
    {
        StringBuilder sb = new StringBuilder();
        sb.append(args[0]);
        sb.append("?" + constant2 + "=" + constant3);
        System.out.println(sb.toString());
    }
}

編譯為:

public class Concat2 {
  public Concat2();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return        

  public void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #3                  // Method java/lang/StringBuilder."":()V
       7: astore_2      
       8: aload_2       
       9: aload_1       
      10: iconst_0      
      11: aaload        
      12: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: pop           
      16: aload_2       
      17: ldc           #5                  // String ?c2=c3
      19: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: pop           
      23: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      26: aload_2       
      27: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      33: return        
}

顯然,你是對的。 在第二個類中, StringBuilder的append方法只被調用兩次,而在第一個例子中,它被調用每個常量字符串。

編譯器是否針對常量字符串優化Stringbuffer / StringBuilder.append()?

沒有。

但是,我認為您提出的優化的前提是不正確的。 我建議您使用兩個版本的代碼並編譯它們。 然后使用javap查看編譯代碼在每種情況下的樣子。

(FWIW,我希望你的“優化”不會改進生成的代碼。它很可能會創建第二個StringBuilder來連接中間字符串,並將其轉換為String。你最終會有大致相同數量的append操作,另外還創建了一個額外的臨時StringBuilder和一個額外的臨時String。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM