Reputation: 231
We know that in JDK8 and below, strings using a plus sign for concatenation will be compiled into StringBuilder for performance optimization, but after JDK9, it will be implemented using the java.lang.invoke.StringConcatFactory#makeConcatWithConstants
method.
However, after decompiling java.lang.Object
, it can be seen that its toString
method is still implemented using StringBuilder:
public java.lang.String toString();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: new #1 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #7 // Method getClass:()Ljava/lang/Class;
11: invokevirtual #13 // Method java/lang/Class.getName:()Ljava/lang/String;
14: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: ldc #23 // String @
19: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_0
23: invokevirtual #25 // Method hashCode:()I
26: invokestatic #29 // Method java/lang/Integer.toHexString:(I)Ljava/lang/String;
29: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: areturn
LineNumberTable:
line 256: 0
LocalVariableTable:
Start Length Slot Name Signature
0 36 0 this Ljava/lang/Object;
Looking through the source code, it can be seen that it still uses the plus sign to connect the three parts:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Rewrite the same code into a class to compile:
public class Main {
public String fooString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
}
It can be seen from the decompilation that it is still implemented using the java.lang.invoke.StringConcatFactory#makeConcatWithConstants
method:
public java.lang.String fooString();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
start local 0 // Main this
0: aload_0
1: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
4: invokevirtual #11 // Method java/lang/Class.getName:()Ljava/lang/String;
7: aload_0
8: invokevirtual #17 // Method java/lang/Object.hashCode:()I
11: invokestatic #21 // Method java/lang/Integer.toHexString:(I)Ljava/lang/String;
14: invokedynamic #27, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
19: areturn
end local 0 // Main this
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 20 0 this LMain;
So why is the plus sign used in Object
class implemented using StringBuilder
while class A
(mentioned above) using makeConcatWithConstants
? Does the bytecode of the Object class provided by the JDK do not match the source code, or is there a special optimization for the Object class at compile time?
Upvotes: 23
Views: 2440
Reputation: 44220
It's explained in the JEP. Emphasis mine
java.base exemptions. Since this feature uses a core library feature (java.lang.invoke) to implement a core language feature (String concatenation), we have to exempt the java.base module from using the indified String concat. Otherwise a circularity happens when the java.lang.invoke.* machinery requires String concat to work, which in turn requires the java.lang.invoke.* machinery. This exemption may limit the performance improvements observed from this feature, since many java.base classes will not be able to use it. We consider this an acceptable downside, which should be covered by the VM's optimizing compilers.
Upvotes: 24