JDK字符串"+"操作数优化差异:Object类为何仍用StringBuilder?
为什么Object类的字符串加号编译为StringBuilder,而自定义类用makeConcatWithConstants?
我们知道,JDK 8及以下版本中,用+做字符串拼接会被编译为StringBuilder来优化性能;但JDK 9之后,普通代码默认会采用java.lang.invoke.StringConcatFactory#makeConcatWithConstants方法实现。
Object类的反编译与源码对比
反编译java.lang.Object的toString方法,可见它仍采用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;
但查看Object类的源码,toString明明是用+连接三部分内容:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
自定义类的编译结果
把相同逻辑写入自定义类Main:
public class Main { public String fooString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } }
反编译后可见,这个方法采用java.lang.invoke.StringConcatFactory#makeConcatWithConstants实现:
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;
原因分析
这既不是字节码与源码不符,也不是编译时对Object类的特殊优化,核心原因是JDK核心类库的编译策略和普通用户代码存在差异:
- 兼容性优先:
Object是所有Java类的根类,toString方法被全平台广泛调用,必须保证绝对的稳定性。StringBuilder的实现经过多年验证,行为完全确定,不会引入新依赖或潜在问题;而StringConcatFactory是JDK 9新增特性,对于核心类库来说,稳定性优先级高于性能优化。 - 编译工具链差异:JDK核心类库(包括
Object)是通过特殊编译工具或编译选项构建的,不会启用针对普通代码的StringConcatFactory优化;而用户自定义类使用标准javac编译,默认启用JDK 9及以上的字符串拼接优化。 - 避免循环依赖:
StringConcatFactory依赖java.lang.invoke包的类,而Object是类加载的基础类,如果其方法依赖StringConcatFactory,可能在类加载阶段引发循环依赖,导致JVM启动失败;使用StringBuilder则避免了这种风险,因为它的加载顺序和依赖关系更简单。
内容的提问来源于stack exchange,提问作者Hyrio
相关产品推荐
相关产品推荐

