对于程序本身的优化,可以借鉴很多前辈们的经验,但是有些时候,
package com.evan.springboot.study;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/17 上午 11:15
*/
public class TestStringAndStringBuild {
public static void main(String[] args) {
}
public void m1(){
String s1="123";
String s2="456";
String s3=s1+s2;
System.out.println(s3);
}
public void m2(){
String s1="123";
String s2="456";
StringBuilder sb = new StringBuilder();
sb.append(s1);
sb.append(s2);
String S3 = sb.toString();
System.out.println(S3);
}
public void m3(){
String str="";
for (int i = 0; i < 5; i++) {
str=str+i;
}
System.out.println(str);
}
public void m4(){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
sb.append(i);
}
System.out.println(sb);
}
}
这里是不是很多人都会觉得m2效率更快?真像真的是这样的吗? m3和m4方法哪个更快呢?让我们带着这两个问题一起来研究一下吧?
我们先进入到TestStringAndStringBuild 的class类目录
在执行以下命令
javap -v TestStringAndStringBuild.class > Ts.txt
我们能看到在D:\IdeaProject\springboot\target\classes\com\evan\springboot\study生成了Ts.txt文件
打开Ts.txt文件
Classfile /D:/IdeaProject/springboot/target/classes/com/evan/springboot/study/TestStringAndStringBuild.class
Last modified 2020-4-17; size 1731 bytes
MD5 checksum df05b27a8ae3e481562d00a3bfce2dba
Compiled from "TestStringAndStringBuild.java"
public class com.evan.springboot.study.TestStringAndStringBuild
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #19.#52 // java/lang/Object."":()V
#2 = Class #53 // com/evan/springboot/study/TestStringAndStringBuild
#3 = Methodref #2.#52 // com/evan/springboot/study/TestStringAndStringBuild."":()V
#4 = Methodref #2.#54 // com/evan/springboot/study/TestStringAndStringBuild.m1:()V
#5 = Methodref #2.#55 // com/evan/springboot/study/TestStringAndStringBuild.m2:()V
#6 = Methodref #2.#56 // com/evan/springboot/study/TestStringAndStringBuild.m3:()V
#7 = Methodref #2.#57 // com/evan/springboot/study/TestStringAndStringBuild.m4:()V
#8 = String #58 // 123
#9 = String #59 // 456
#10 = Class #60 // java/lang/StringBuilder
#11 = Methodref #10.#52 // java/lang/StringBuilder."":()V
#12 = Methodref #10.#61 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#13 = Methodref #10.#62 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#14 = Fieldref #63.#64 // java/lang/System.out:Ljava/io/PrintStream;
#15 = Methodref #65.#66 // java/io/PrintStream.println:(Ljava/lang/String;)V
#16 = String #67 //
#17 = Methodref #10.#68 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#18 = Methodref #65.#69 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#19 = Class #70 // java/lang/Object
#20 = Utf8
#21 = Utf8 ()V
#22 = Utf8 Code
#23 = Utf8 LineNumberTable
#24 = Utf8 LocalVariableTable
#25 = Utf8 this
#26 = Utf8 Lcom/evan/springboot/study/TestStringAndStringBuild;
#27 = Utf8 main
#28 = Utf8 ([Ljava/lang/String;)V
#29 = Utf8 args
#30 = Utf8 [Ljava/lang/String;
#31 = Utf8 ts
#32 = Utf8 MethodParameters
#33 = Utf8 m1
#34 = Utf8 s1
#35 = Utf8 Ljava/lang/String;
#36 = Utf8 s2
#37 = Utf8 s3
#38 = Utf8 m2
#39 = Utf8 sb
#40 = Utf8 Ljava/lang/StringBuilder;
#41 = Utf8 S3
#42 = Utf8 m3
#43 = Utf8 i
#44 = Utf8 I
#45 = Utf8 str
#46 = Utf8 StackMapTable
#47 = Class #71 // java/lang/String
#48 = Utf8 m4
#49 = Class #60 // java/lang/StringBuilder
#50 = Utf8 SourceFile
#51 = Utf8 TestStringAndStringBuild.java
#52 = NameAndType #20:#21 // "":()V
#53 = Utf8 com/evan/springboot/study/TestStringAndStringBuild
#54 = NameAndType #33:#21 // m1:()V
#55 = NameAndType #38:#21 // m2:()V
#56 = NameAndType #42:#21 // m3:()V
#57 = NameAndType #48:#21 // m4:()V
#58 = Utf8 123
#59 = Utf8 456
#60 = Utf8 java/lang/StringBuilder
#61 = NameAndType #72:#73 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#62 = NameAndType #74:#75 // toString:()Ljava/lang/String;
#63 = Class #76 // java/lang/System
#64 = NameAndType #77:#78 // out:Ljava/io/PrintStream;
#65 = Class #79 // java/io/PrintStream
#66 = NameAndType #80:#81 // println:(Ljava/lang/String;)V
#67 = Utf8
#68 = NameAndType #72:#82 // append:(I)Ljava/lang/StringBuilder;
#69 = NameAndType #80:#83 // println:(Ljava/lang/Object;)V
#70 = Utf8 java/lang/Object
#71 = Utf8 java/lang/String
#72 = Utf8 append
#73 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#74 = Utf8 toString
#75 = Utf8 ()Ljava/lang/String;
#76 = Utf8 java/lang/System
#77 = Utf8 out
#78 = Utf8 Ljava/io/PrintStream;
#79 = Utf8 java/io/PrintStream
#80 = Utf8 println
#81 = Utf8 (Ljava/lang/String;)V
#82 = Utf8 (I)Ljava/lang/StringBuilder;
#83 = Utf8 (Ljava/lang/Object;)V
{
public com.evan.springboot.study.TestStringAndStringBuild();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/evan/springboot/study/TestStringAndStringBuild;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class com/evan/springboot/study/TestStringAndStringBuild
3: dup
4: invokespecial #3 // Method "":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method m1:()V
12: aload_1
13: invokevirtual #5 // Method m2:()V
16: aload_1
17: invokevirtual #6 // Method m3:()V
20: aload_1
21: invokevirtual #7 // Method m4:()V
24: return
LineNumberTable:
line 12: 0
line 13: 8
line 14: 12
line 15: 16
line 16: 20
line 17: 24
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 args [Ljava/lang/String;
8 17 1 ts Lcom/evan/springboot/study/TestStringAndStringBuild;
MethodParameters:
Name Flags
args
public void m1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: ldc #8 // String 123
2: astore_1
3: ldc #9 // String 456
5: astore_2
6: new #10 // class java/lang/StringBuilder
9: dup
10: invokespecial #11 // Method java/lang/StringBuilder."":()V
13: aload_1
14: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #13 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return
LineNumberTable:
line 20: 0
line 21: 3
line 22: 6
line 23: 25
line 24: 32
LocalVariableTable:
Start Length Slot Name Signature
0 33 0 this Lcom/evan/springboot/study/TestStringAndStringBuild;
3 30 1 s1 Ljava/lang/String;
6 27 2 s2 Ljava/lang/String;
25 8 3 s3 Ljava/lang/String;
public void m2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=1
0: ldc #8 // String 123
2: astore_1
3: ldc #9 // String 456
5: astore_2
6: new #10 // class java/lang/StringBuilder
9: dup
10: invokespecial #11 // Method java/lang/StringBuilder."":()V
13: astore_3
14: aload_3
15: aload_1
16: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: aload_3
21: aload_2
22: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: pop
26: aload_3
27: invokevirtual #13 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore 4
32: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
35: aload 4
37: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return
LineNumberTable:
line 27: 0
line 28: 3
line 29: 6
line 30: 14
line 31: 20
line 32: 26
line 33: 32
line 34: 40
LocalVariableTable:
Start Length Slot Name Signature
0 41 0 this Lcom/evan/springboot/study/TestStringAndStringBuild;
3 38 1 s1 Ljava/lang/String;
6 35 2 s2 Ljava/lang/String;
14 27 3 sb Ljava/lang/StringBuilder;
32 9 4 S3 Ljava/lang/String;
public void m3();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: ldc #16 // String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: iconst_5
7: if_icmpge 35
10: new #10 // class java/lang/StringBuilder
13: dup
14: invokespecial #11 // Method java/lang/StringBuilder."":()V
17: aload_1
18: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: iload_2
22: invokevirtual #17 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
25: invokevirtual #13 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: astore_1
29: iinc 2, 1
32: goto 5
35: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
38: aload_1
39: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return
LineNumberTable:
line 37: 0
line 38: 3
line 39: 10
line 38: 29
line 41: 35
line 42: 42
LocalVariableTable:
Start Length Slot Name Signature
5 30 2 i I
0 43 0 this Lcom/evan/springboot/study/TestStringAndStringBuild;
3 40 1 str Ljava/lang/String;
StackMapTable: number_of_entries = 2
frame_type = 253 /* append */
offset_delta = 5
locals = [ class java/lang/String, int ]
frame_type = 250 /* chop */
offset_delta = 29
public void m4();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: new #10 // class java/lang/StringBuilder
3: dup
4: invokespecial #11 // Method java/lang/StringBuilder."":()V
7: astore_1
8: iconst_0
9: istore_2
10: iload_2
11: iconst_5
12: if_icmpge 27
15: aload_1
16: iload_2
17: invokevirtual #17 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
20: pop
21: iinc 2, 1
24: goto 10
27: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
30: aload_1
31: invokevirtual #18 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
34: return
LineNumberTable:
line 45: 0
line 46: 8
line 47: 15
line 46: 21
line 49: 27
line 50: 34
LocalVariableTable:
Start Length Slot Name Signature
10 17 2 i I
0 35 0 this Lcom/evan/springboot/study/TestStringAndStringBuild;
8 27 1 sb Ljava/lang/StringBuilder;
StackMapTable: number_of_entries = 2
frame_type = 253 /* append */
offset_delta = 10
locals = [ class java/lang/StringBuilder, int ]
frame_type = 250 /* chop */
offset_delta = 16
}
SourceFile: "TestStringAndStringBuild.java"
内容大致分为4部分:
第一部分:显示了生成这个class的java源文件,版本信息,生成时间等。
第二部分:显示了该类所涉及的常量池
第三部分:显示了该类的构造器,编译器自动插入的
第四部分:显示了main方法信息(这个是我们需要重点解读的)
常量池
Class: 类或接口的符号引用
Fieldref: 字段的符号引用
Methodref: 类中方法的符号引用
InterfaceMethodref: 接口中方法的符号引用
String: 字符串类型常量
Integer: 整形常量
Float: 浮点型常量
Long: 长整形常量
Double: 双进度浮点型常量
NameAndType: 字段或方法的符号引用
utf-8: UTF-8编码的字符串
MethodType: 标志方法类型
InvokeDynamic: 表示一个动态方法调用
字段描述符
FieldType | Type | interpretation |
---|---|---|
B | byte | |
C | char | |
D | double | |
F | float | |
I | int | |
J | long | |
LClassName | reference | |
S | short | |
Z | boolean | |
[ | reference | one array dimension |
6: new #10 // class java/lang/StringBuilder
9: dup
10: invokespecial #11 // Method java/lang/StringBuilder."":()V
13: aload_1
14: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #13 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return
从解字节码中可以看出,m1()方法源码中使用+号拼接,但是在字节码中也被编译成stringBuilder方式
所以可以得出结论,字符串拼接,+号和stringBuilder是相等的,效率一样
可以看到,m3()方法中的循环体内,每一次循环都会创建StringBuilder对象,效率低于 m4()方法。