欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java字符串拼接在编译时优化测试

程序员文章站 2022-05-11 15:21:27
...

为了验证编译器对于String相关代码的字节码优化,我简单的做了个测试:

jdk版本:1.7.0_51

 java 用例代码:

package com.rsp.shiro;

/**
 * Created by cd_huang on 2017/4/1.
 */
public class StringTest {
	public static String StaticString(){
		return "BBB";
	}
	public static String getString1(){
		return "AAA"+"BBB";
	}
	public static String getString2(){
		return new StringBuilder().append("AAA").append("BBB").toString();
	}
	public static String getString3(){
		return "AAA"+StaticString();
	}
	public static String getString4(){
		return new StringBuilder().append("AAA").append(StaticString()).toString();
	}
}

 命令行输入:C:\Users\hcd>javac c:\StringTest.java
生成StringTest.class文件。

命令行输入:C:\Users\hcd>javap -v c:\StringTest.class
生成java编译后的字节码指令。

Classfile /c:/StringTest.class
  Last modified 2017-4-1; size 721 bytes
  MD5 checksum 60b413955d7484157009f74a40848d59
  Compiled from "StringTest.java"
public class com.rsp.shiro.StringTest
  SourceFile: "StringTest.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #11.#24        //  java/lang/Object."<init>":()V
   #2 = String             #25            //  BBB
   #3 = String             #26            //  AAABBB
   #4 = Class              #27            //  java/lang/StringBuilder
   #5 = Methodref          #4.#24         //  java/lang/StringBuilder."<init>":(
)V
   #6 = String             #28            //  AAA
   #7 = Methodref          #4.#29         //  java/lang/StringBuilder.append:(Lj
ava/lang/String;)Ljava/lang/StringBuilder;
   #8 = Methodref          #4.#30         //  java/lang/StringBuilder.toString:(
)Ljava/lang/String;
   #9 = Methodref          #10.#31        //  com/rsp/shiro/StringTest.StaticStr
ing:()Ljava/lang/String;
  #10 = Class              #32            //  com/rsp/shiro/StringTest
  #11 = Class              #33            //  java/lang/Object
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               StaticString
  #17 = Utf8               ()Ljava/lang/String;
  #18 = Utf8               getString1
  #19 = Utf8               getString2
  #20 = Utf8               getString3
  #21 = Utf8               getString4
  #22 = Utf8               SourceFile
  #23 = Utf8               StringTest.java
  #24 = NameAndType        #12:#13        //  "<init>":()V
  #25 = Utf8               BBB
  #26 = Utf8               AAABBB
  #27 = Utf8               java/lang/StringBuilder
  #28 = Utf8               AAA
  #29 = NameAndType        #34:#35        //  append:(Ljava/lang/String;)Ljava/l
ang/StringBuilder;
  #30 = NameAndType        #36:#17        //  toString:()Ljava/lang/String;
  #31 = NameAndType        #16:#17        //  StaticString:()Ljava/lang/String;
  #32 = Utf8               com/rsp/shiro/StringTest
  #33 = Utf8               java/lang/Object
  #34 = Utf8               append
  #35 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #36 = Utf8               toString
{
  public com.rsp.shiro.StringTest();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>
":()V
         4: return
      LineNumberTable:
        line 6: 0

  public static java.lang.String StaticString();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #2                  // String BBB
         2: areturn
      LineNumberTable:
        line 8: 0

  public static java.lang.String getString1();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #3                  // String AAABBB
         2: areturn
      LineNumberTable:
        line 11: 0

  public static java.lang.String getString2();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #4                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #5                  // Method java/lang/StringBuilder.
"<init>":()V
         7: ldc           #6                  // String AAA
         9: invokevirtual #7                  // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        12: ldc           #2                  // String BBB
        14: invokevirtual #7                  // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        17: invokevirtual #8                  // Method java/lang/StringBuilder.
toString:()Ljava/lang/String;
        20: areturn
      LineNumberTable:
        line 14: 0

  public static java.lang.String getString3();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #4                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #5                  // Method java/lang/StringBuilder.
"<init>":()V
         7: ldc           #6                  // String AAA
         9: invokevirtual #7                  // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        12: invokestatic  #9                  // Method StaticString:()Ljava/lan
g/String;
        15: invokevirtual #7                  // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        18: invokevirtual #8                  // Method java/lang/StringBuilder.
toString:()Ljava/lang/String;
        21: areturn
      LineNumberTable:
        line 17: 0

  public static java.lang.String getString4();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #4                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #5                  // Method java/lang/StringBuilder.
"<init>":()V
         7: ldc           #6                  // String AAA
         9: invokevirtual #7                  // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        12: invokestatic  #9                  // Method StaticString:()Ljava/lan
g/String;
        15: invokevirtual #7                  // Method java/lang/StringBuilder.
append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        18: invokevirtual #8                  // Method java/lang/StringBuilder.
toString:()Ljava/lang/String;
        21: areturn
      LineNumberTable:
        line 20: 0
}

C:\Users\hcd>

 
可以看出来getString3() 方法和getString4()方法的字节码指令一摸一样,也就是编译器帮我们做了优化。
由于String对象时不可变对象,因此在对字符串进行拼接时,String对象总是会生成新的对象,所以其性能相对较差。
StringBuilder:一个非线程安全的字符串缓冲类,jdk1.5后出现。
所以,编译器在字符串对象拼接时,自动帮我们用StringBuilder实现了字符串拼接。