Different String, StringBuffer and StringBuilder from the Bytecode Perspective

Oracle official note:

javap
 Decomposition one or more class files.

Brief description of use
javap [options] classfile...

options
 Command-line options, see Options later in detail

classfile
 One or more Class files (separated by multiple spaces) can use file paths or files under classPath or enter URL s

Description
 The javap command decomposes and uninstalls one or more class files. The output depends on the options used. When no options are used, the javap command print scheme is protected and public fields and methods. The javap command prints the output to the console.

Options
-help
--help
-?
print the help information

-version
 Printed version information

-l
 Print in-line variables and local variables

-public
 Display public access modifiers

-protected
 Display protected, public access modifiers
-private
-p
 Display all content

-Joption
 Pass the specified options to the JVM. For example:

javap -J-version
javap -J-Djava.security.manager -J-Djava.security.policy=MyPolicy MyClassName
For more information about JVM options, see the java command documentation.

-s
 Print internal class signature

-sysinfo
 Class processing that displays system information (path, size, date, MD5 hash).
-constants
 Display static constants

-c
 Print disassembly code for methods in each class, such as Java bytecode instruction composition.


-verbose
 Print stack size, number of local variables, and method parameters.
Prints stack size, number of locals and arguments for methods.

-classpath path
 Specifies the path lookup class used by the javap command. Overrides the default or when it is set to CLASSPATH environment variables.
Specifies the path the javap command uses to look up classes. Overrides the default or the CLASSPATH environment variable when it is set.

-bootclasspath path
 The specified path loads the boot class. By default, boot class classes to implement the core Java platform in jre / lib / rt. Jar and several other jar files.
Specifies the path from which to load bootstrap classes. By default, the bootstrap classes are the classes that implement the core Java platform located in jre/lib/rt.jar and several other JAR files.

-extdir dirs
 Add some extension paths to get the class libraries
Overrides the location at which installed extensions are searched for. The default location for extensions is the value of java.ext.dirs.

Let's look at the differences between String, String Buffer and String Builder

Test class

public class Test {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            //When we mosaic characters, we don't mosaic characters too many times, even if it's more than 100 times.
            contactStringWithLoop(100);
        }
        System.out.println(System.currentTimeMillis() - start);
        //916 milliseconds

        start = System.currentTimeMillis();

        for (int i = 0; i < 100000; i++) {
            //When we mosaic characters, we don't mosaic characters too many times, even if it's more than 100 times.
            contactStringWithStringBuilder(100);
        }

        System.out.println(System.currentTimeMillis() - start);
        //244 milliseconds

        start = System.currentTimeMillis();

        for (int i = 0; i < 100000; i++) {
            //When we mosaic characters, we don't mosaic characters too many times, even if it's more than 100 times.
            contactStringWithStringBuffer(100);
        }
        System.out.println(System.currentTimeMillis() - start);
        //620 milliseconds
    }

    /**
     * Direct concatenation of strings
     *
     * @return
     */
    public static String contactString() {
        String string = "direct" + "Pair of strings" + "Conduct" + "Multiple splicing"
                + "Look at the final compilation" + "Bytecode" + "It will be a magic horse." + "A look" + "Of";
        return string;
    }

    /**
     * In fact, it is the same as the above method, but a number of variables are introduced into the stitching.
     *
     * @param str
     * @return
     */
    public static String contactStringWithParam(String str, String str2, String str3) {
        String string = "direct" + str3 + "Conduct" + "Multiple splicing"
                + "Look at the final compilation" + str + "It will be a magic horse." + str2 + "Of";
        return string;
    }

    /**
     * Stitching strings through loops
     *
     * @param loopCount Number of cycles
     * @return
     */
    public static String contactStringWithLoop(int loopCount) {
        String string = "";
        for (int i = 0; i < loopCount; i++) {
            string += i;
        }
        return string;
    }

    /**
     * Using StringBuffer loop to concatenate strings
     *
     * @param loopCount
     * @return
     */
    public static String contactStringWithStringBuffer(int loopCount) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < loopCount; i++) {
            sb.append(i);
        }
        return sb.toString();
    }

    /**
     * Using StringBuilder loop to concatenate strings
     *
     * @param loopCount
     * @return
     */
    public static String contactStringWithStringBuilder(int loopCount) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < loopCount; i++) {
            sb.append(i);
        }
        return sb.toString();
    }
}  

Using javap-c Test to get bytecode information

Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1      
       4: iconst_0      
       5: istore_3      
       6: iload_3       
       7: ldc           #3                  // int 100000
       9: if_icmpge     24
      12: bipush        100
      14: invokestatic  #4                  // Method contactStringWithLoop:(I)Ljava/lang/String;
      17: pop           
      18: iinc          3, 1
      21: goto          6
      24: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      27: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      30: lload_1       
      31: lsub          
      32: invokevirtual #6                  // Method java/io/PrintStream.println:(J)V
      35: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      38: lstore_1      
      39: iconst_0      
      40: istore_3      
      41: iload_3       
      42: ldc           #3                  // int 100000
      44: if_icmpge     59
      47: bipush        100
      49: invokestatic  #7                  // Method contactStringWithStringBuilder:(I)Ljava/lang/String;
      52: pop           
      53: iinc          3, 1
      56: goto          41
      59: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      62: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      65: lload_1       
      66: lsub          
      67: invokevirtual #6                  // Method java/io/PrintStream.println:(J)V
      70: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      73: lstore_1      
      74: iconst_0      
      75: istore_3      
      76: iload_3       
      77: ldc           #3                  // int 100000
      79: if_icmpge     94
      82: bipush        100
      84: invokestatic  #8                  // Method contactStringWithStringBuffer:(I)Ljava/lang/String;
      87: pop           
      88: iinc          3, 1
      91: goto          76
      94: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      97: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
     100: lload_1       
     101: lsub          
     102: invokevirtual #6                  // Method java/io/PrintStream.println:(J)V
     105: return        

  public static java.lang.String contactString();
    Code:
       0: ldc           #9// String splices strings several times directly to see what the final compiled bytecode looks like
       2: astore_0      
       3: aload_0       
       4: areturn       

  public static java.lang.String contactStringWithParam(java.lang.String, java.lang.String, java.lang.String);
    Code:
       0: new           #10                 // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
       7: ldc           #12// String Direct
       9: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      12: aload_2       
      13: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: ldc           #14 // String
      18: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: ldc           #15//String multiple splicing
      23: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: ldc           #16// String to see the final compilation
      28: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      31: aload_0       
      32: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      35: ldc           #17 // String will be a magic horse
      37: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      40: aload_1       
      41: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      44: ldc           #18// String
      46: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      49: invokevirtual #19                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      52: astore_3      
      53: aload_3       
      54: areturn       

  public static java.lang.String contactStringWithLoop(int);
    Code:
       0: ldc           #20                 // String 
       2: astore_1      
       3: iconst_0      
       4: istore_2      
       5: iload_2       
       6: iload_0       
       7: if_icmpge     35
      10: new           #10                 // class java/lang/StringBuilder
      13: dup           
      14: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
      17: aload_1       
      18: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: iload_2       
      22: invokevirtual #21                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      25: invokevirtual #19                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      28: astore_1      
      29: iinc          2, 1
      32: goto          5
      35: aload_1       
      36: areturn       

  public static java.lang.String contactStringWithStringBuffer(int);
    Code:
       0: new           #22                 // class java/lang/StringBuffer
       3: dup           
       4: invokespecial #23                 // Method java/lang/StringBuffer."<init>":()V
       7: astore_1      
       8: iconst_0      
       9: istore_2      
      10: iload_2       
      11: iload_0       
      12: if_icmpge     27
      15: aload_1       
      16: iload_2       
      17: invokevirtual #24                 // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
      20: pop           
      21: iinc          2, 1
      24: goto          10
      27: aload_1       
      28: invokevirtual #25                 // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
      31: areturn       

  public static java.lang.String contactStringWithStringBuilder(int);
    Code:
       0: new           #10                 // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
       7: astore_1      
       8: iconst_0      
       9: istore_2      
      10: iload_2       
      11: iload_0       
      12: if_icmpge     27
      15: aload_1       
      16: iload_2       
      17: invokevirtual #21                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      20: pop           
      21: iinc          2, 1
      24: goto          10
      27: aload_1       
      28: invokevirtual #19                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: areturn       
}

Let's break down the bytecode:

contactString method [in 64 rows of javac results]
  public static java.lang.String contactString();
    Code:
       0: ldc           #9// String splices strings several times directly to see what the final compiled bytecode looks like
       2: astore_0      
       3: aload_0       
       4: areturn       

From 0: LDC #9// String splicing strings several times directly to see that the compiled bytecode will look like a magic horse. It can be seen that the compiler directly converts the compiled results, instead of using + it directly uses the spliced strings (because there is no splicing of variables, the final results can be expected).
CONCLUSION: String splicing in java can be done directly by + method.

contactStringWithParam [in line 71 of the javac result]
  public static java.lang.String contactStringWithParam(java.lang.String, java.lang.String, java.lang.String);
    Code:
       0: new           #10                 // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
       7: ldc           #12// String Direct
       9: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      12: aload_2       
      13: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: ldc           #14 // String
      18: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: ldc           #15//String multiple splicing
      23: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: ldc           #16// String to see the final compilation
      28: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      31: aload_0       
      32: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      35: ldc           #17 // String will be a magic horse
      37: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      40: aload_1       
      41: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      44: ldc           #18// String
      46: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      49: invokevirtual #19                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      52: astore_3      
      53: aload_3       
      54: areturn       

0: New # 10 // class java / Lang / StringBuilder is a corresponding declaration of a StringBuilder, and then each stitching actually uses StringBuilder's append method.
Conclusion: There is no difference between String Builder and String +, but String + is more time-saving, labor-saving and relatively clear when it comes to this kind of string with no loop but variable stitching.

contactStringWithLoop [in line 99 of the javac result]
public static java.lang.String contactStringWithLoop(int);
    Code:
       0: ldc           #20                 // String 
       2: astore_1      
       3: iconst_0      
       4: istore_2      
       5: iload_2       
       6: iload_0       
       7: if_icmpge     35
      10: new           #10                 // class java/lang/StringBuilder
      13: dup           
      14: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
      17: aload_1       
      18: invokevirtual #13                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: iload_2       
      22: invokevirtual #21                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      25: invokevirtual #19                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      28: astore_1      
      29: iinc          2, 1
      32: goto          5
      35: aload_1       
      36: areturn       

First, the loop variable is initialized:

         0: iconst_0      
         1: istore_1

These two lines of code correspond to int i = 0 (iconst_0 is the number 0, istore_1 is the local variable 1, here is I in the source code).

       5: iload_2
       6: iload_0
       7: if_icmpge     35

These three lines mean if i is less than 10 and if i is less than 10, then continue to execute. Otherwise, jump to return number 35 and jump out of the for loop. So the actual meaning here is to create a new StringBuilder each time, and then return to StringBuilder's toString() at the end of the loop.

Contrast contactStringWithStringBuffer [in line 122 of javac results]
  public static java.lang.String contactStringWithStringBuffer(int);
    Code:
       0: new           #22                 // class java/lang/StringBuffer
       3: dup           
       4: invokespecial #23                 // Method java/lang/StringBuffer."<init>":()V
       7: astore_1      
       8: iconst_0      
       9: istore_2      
      10: iload_2       
      11: iload_0       
      12: if_icmpge     27
      15: aload_1       
      16: iload_2       
      17: invokevirtual #24                 // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
      20: pop           
      21: iinc          2, 1
      24: goto          10
      27: aload_1       
      28: invokevirtual #25                 // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
      31: areturn       

Above is the new String Builder, and then just append the String Builder.
CONCLUSION: String Builder should be used when using variables and concatenating strings circularly.

The test results of main method also show that the performance of String Builder is much better than String Buffer and String Buffer when they are used for 10000 times of character stitching. [Is StringBuffer thread-safe, so it loses some performance but is better than String, mainly because the cost of each new StringBuilder is relatively high]

I am an advertisement.

My live course will begin in July. I hope my friends will support me. Now there is a discount for registration.

https://segmentfault.com/l/15...

https://segmentfault.com/l/15...

Keywords: Java jvm less Oracle

Added by rbudj on Tue, 18 Jun 2019 23:07:50 +0300