java字符串拼接在编译时优化测试
程序员文章站
2022-05-11 15:21:33
...
为了验证编译器对于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实现了字符串拼接。