You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 21:35:24