写在JEP 280: Indify String Concatenation :
Change the static
String
-concatenation bytecode sequence generated byjavac
to useinvokedynamic
calls to JDK library functions. This will enable future optimizations ofString
concatenation without requiring further changes to the bytecode emmited byjavac
.
这里我想了解一下invokedynamic
调用的用途是什么,字节码拼接和invokedynamic
有什么不同?
最佳答案
“旧”方式输出一堆面向 StringBuilder
的操作。考虑这个程序:
public class Example {
public static void main(String[] args)
{
String result = args[0] + "-" + args[1] + "-" + args[2];
System.out.println(result);
}
}
如果我们使用 JDK 8 或更早版本编译它,然后使用 javap -c Example
查看字节码,我们会看到如下内容:
public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/StringBuilder 3: dup 4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V 7: aload_0 8: iconst_0 9: aaload 10: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 13: ldc #5 // String - 15: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 18: aload_0 19: iconst_1 20: aaload 21: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: ldc #5 // String - 26: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: aload_0 30: iconst_2 31: aaload 32: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 35: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 38: astore_1 39: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 42: aload_1 43: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 46: return }
如您所见,它创建了一个 StringBuilder
并使用了 append
。这是众所周知的相当低效的做法,因为 StringBuilder
中内置缓冲区的默认容量仅为 16 个字符,编译器 无法提前知道分配更多字符,所以它最终不得不重新分配。它也是一堆方法调用。 (不过请注意,JVM 有时 可以检测并重写这些调用模式以提高它们的效率。)
让我们看看 Java 9 生成了什么:
public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: aload_0 1: iconst_0 2: aaload 3: aload_0 4: iconst_1 5: aaload 6: aload_0 7: iconst_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 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 22: return }
哦,天哪,但那更短了。 :-) 它从 StringConcatFactory
调用 makeConcatWithConstants
,在它的 Javadoc 中这样说:
Methods to facilitate the creation of String concatenation methods, that can be used to efficiently concatenate a known number of arguments of known types, possibly after type adaptation and partial evaluation of arguments. These methods are typically used as bootstrap methods for
invokedynamic
call sites, to support the string concatenation feature of the Java Programming Language.
关于java - Java 9 中的字符串连接是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61918877/