如JEP 280中所述:指示字符串串联:
将由
javac生成的静态String-串联字节码序列更改为使用对JDK库函数的invokedynamic调用。这将使未来能够优化字符串串联,而不需要进一步更改javac产生的字节码
在这里,我想了解invokedynamic调用的用途,以及字节码串联与invokedynamic有何不同
“旧”方式输出一系列面向StringBuilder的操作。考虑这个程序:
公共类示例{
公共静态void main(字符串[]args)
{
字符串结果=args[0]+“-”+args[1]+“-”+args[2];
系统输出打印项次(结果);
}
}
如果我们使用JDK 8或更早版本编译它,然后使用javap-c示例查看字节码,我们会看到如下内容:
公开课范例{
公众榜样();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“<;init>”:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:new#2//类java/lang/StringBuilder
3:dup
4:invokespecial#3//方法java/lang/StringBuilder。“<;init>”:()V
7:aload_0
8:iconst_0
9:aaload
10:invokevirtual#4//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
13:ldc#5//String-
15:invokevirtual#4//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
18:aload_0
19:iconst_1
20:aaload
21:invokevirtual#4//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24:ldc#5//String-
26:invokevirtual#4//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29:aload_0
30:iconst_2
31:aaload
32:invokevirtual#4//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35:invokevirtual#6//方法java/lang/StringBuilder.toString:()Ljava/lang/String;
38:astore_1
39:getstatic#7//fieldjava/lang/System.out:Ljava/io/PrintStream;
42:aload_1
43:invokevirtual#8//方法java/io/PrintStream.println:(Ljava/lang/String;)V
46:返回
}
如您所见,它创建一个StringBuilder,并使用append。这是非常低效的,因为StringBuilder中内置缓冲区的默认容量只有16个字符,而且编译器也无法事先知道如何分配更多,因此它最终不得不重新分配。这也是一堆方法调用。(请注意,JVM有时可以检测并重写这些调用模式,以提高它们的效率。)
让我们看看Java 9生成了什么:
公开课范例{
公众榜样();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“<;init>”:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:aload_0
1:iconst_0
2:aaload
3:aload_0
4:iconst_1
5:aaload
6:aload_0
nsticu:2
8:aaload
9:invokedynamic#2,0//invokedynamic#0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
14:astore_1
15:getstatic#3//Field java/lang/System.out:Ljava/io/PrintStream;
18:aload_1
19:invokevirtual#4//方法java/io/PrintStream.println:(Ljava/lang/String;)V
22:返回
}
哦,天哪,但这太短了。:-)它从StringConcatFactory调用makeConcatWithConstants,在Javadoc中这样说:
方法来促进字符串连接方法的创建,该方法可用于在类型自适应和参数的部分求值之后有效地连接已知类型的已知数量的参数。这些方法通常用作
invokedynamic调用站点的引导方法,以支持Java编程语言的字符串连接功能