java字符串连接问题
前景
在java核心技术 卷1上有这样一段话构建字符串的时候,每次使用+号都会产生一个新的String对象,会浪费资源,最好用StringBuilder。因为那本书的版本是JDK8的,所有这句话是对的,并且网上关于它的讲解也很对,下面附上一个很好的连接
https://blog.csdn.net/m0_37589327/article/details/78605268
就JDK 8而言,它的讲解是对的。当+号在不同语句中的时候,每次会new一下,创建新的对象,并且javac会调用StringBuilder。append这个方法进行+的优化。但是当我在JDK9上的时候发现了不同的答案,是JDK9的新特性,下面放上我的实验结果图,与JDK有不同之处
问题
测试代码:
public class test {
public static void main(String[] args)
{
String str = "";
long start = System.currentTimeMillis();
for(int i=0; i<100000; i++)
str += "a";
long end = System.currentTimeMillis();
System.out.println(end - start);
StringBuilder sb = new StringBuilder();
start = System.currentTimeMillis();
for(int i=0; i<100000; i++)
sb.append("a");
str = sb.toString();
end = System.currentTimeMillis();
System.out.println(end - start);
String a="";
a+="a";
a+="a";
a+="a";
}
}
反编译得到的结果
dream@love_lyy:~/java/test/src$ javap -c test.class
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: ldc #2 // String
2: astore_1
3: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
6: lstore_2
7: iconst_0
8: istore 4
10: iload 4
12: ldc #4 // int 100000
14: if_icmpge 30
17: aload_1
18: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
23: astore_1
24: iinc 4, 1
27: goto 10
30: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
33: lstore 4
35: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
38: lload 4
40: lload_2
41: lsub
42: invokevirtual #7 // Method java/io/PrintStream.println:(J)V
45: new #8 // class java/lang/StringBuilder
48: dup
49: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V
52: astore 6
54: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
57: lstore_2
58: iconst_0
59: istore 7
61: iload 7
63: ldc #4 // int 100000
65: if_icmpge 82
68: aload 6
70: ldc #10 // String a
72: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
75: pop
76: iinc 7, 1
79: goto 61
82: aload 6
84: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
87: astore_1
88: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
91: lstore 4
93: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
96: lload 4
98: lload_2
99: lsub
100: invokevirtual #7 // Method java/io/PrintStream.println:(J)V
103: ldc #2 // String
105: astore 7
107: aload 7
109: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
114: astore 7
116: aload 7
118: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
123: astore 7
125: aload 7
127: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
132: astore 7
134: aconst_null
135: astore 8
137: aload 8
139: invokedynamic #13, 0 // InvokeDynamic #1:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
144: astore 8
146: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
149: aload 8
151: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
154: return
}
理解
由于中文的我没有搜到这个答案,在stackoverflow和jdk9 API上我都看了一下这个函数,先看看API
API
API上对这两个方法的描述是:促进了最佳的字符串拼接的方法,能够有效地连接已知数量的、具有已知类型的参数。。。等于没讲。之后看看stackoverflow上怎么讲的。
stackoverflow
private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
简而言之,一共提供了6种方法供它来动态选择,至于如何动态选择,我这个新手是搞不懂的了 - -。前5种是SB——StringBuilder,可以看出来的是,并没有舍弃StringBuilder这个方法,而是更加细分了它们,达到一个更好的效果。(纯属个人理解,因为才学java一周。。。)我实现的这个测试代码的结论我觉得暂时是和JDK8测试一致的。
总结
对于我这个新手其实只要知道,JDK9 延续了JDK8的好处,并且还实现了再优化!+号连接字符串,在不同语句中,是会创建新的String对象的,就是多次做了连接,而不是在一句话里面连接好。StringBuilder优就优在这。更深入的学习,对于小白来说,不用知道。等长大了再慢慢学咯~
阅读更多- 上一篇:没有了
- 下一篇:没有了