String a = new String(“aa”) + “bb” “这句话创建了多少个对象?为什么?

参考回答**

这句话:

String a = new String("aa") + "bb";

共创建了 4 个 String 对象,原因分析如下:

  1. "aa"
    • 字符串字面量 "aa" 会被加载到字符串常量池中。如果常量池中已经存在 "aa",则直接引用;如果不存在,则会创建一个 "aa" 的字符串对象存入常量池。
  2. new String("aa")
    • 使用 new 关键字会在堆中创建一个新的 String 对象,并将 "aa" 的值复制到这个堆对象中。
  3. "bb"
    • 字符串字面量 "bb" 会被加载到字符串常量池中。如果常量池中已经存在 "bb",则直接引用;如果不存在,则会创建一个 "bb" 的字符串对象存入常量池。
  4. 拼接结果
    • new String("aa") + "bb" 会触发字符串拼接操作,通过 StringBuilder 动态拼接,然后调用 toString() 方法生成一个新的 String 对象(存储在堆中)。

因此:

  • 第 1 个对象:常量池中的 "aa"
  • 第 2 个对象:堆中由 new String("aa") 创建的新对象。
  • 第 3 个对象:常量池中的 "bb"
  • 第 4 个对象:拼接结果产生的新对象。

详细讲解与拓展

1. 为什么会创建 4 个对象?

1.1 字符串字面量的处理
  • Java 中的字符串字面量(如 "aa""bb")会在编译时加载到字符串常量池中。
  • 字符串常量池的特点是:池中的字符串是唯一的,重复的字面量不会重新创建。
1.2 new String() 的行为
  • new String("aa") 会创建一个新的 String 对象,存储在堆中。即使常量池中已经有 "aa"new String() 仍然会强制在堆中分配一块新的内存。
1.3 字符串拼接的行为
  • 如果拼接的两部分中有非字符串常量(如 new String()),编译器不会对拼接进行优化,而是在运行时使用 StringBuilder 进行拼接,最终调用 toString() 生成新的 String 对象。

2. 执行流程分析

以下是这句话的执行过程,分解如下:

String a = new String("aa") + "bb";
  1. "aa" 加载
    • 检查字符串常量池中是否有 "aa"
    • 如果没有,则创建 "aa" 并加入常量池。
  2. new String("aa") 创建
    • 在堆中创建一个新的 String 对象,将常量池中 "aa" 的值复制到这个新对象中。
  3. "bb" 加载
    • 检查字符串常量池中是否有 "bb"
    • 如果没有,则创建 "bb" 并加入常量池。
  4. 拼接操作
    • 通过 StringBuilder 将堆中的 new String("aa") 和常量池中的 "bb" 拼接。
    • 调用 toString() 生成一个新的字符串对象,存储在堆中。

3. 实际代码验证

通过以下代码可以验证对象的创建过程:

public class Main {
    public static void main(String[] args) {
        String a = new String("aa") + "bb";
    }
}

使用 JDK 的 javap -c 工具查看编译后的字节码:

$ javap -c Main

对应的关键字节码解释:

  1. ldc "aa":将字符串 "aa" 加载到常量池中。
  2. new java/lang/String:在堆中创建一个新的 String 对象。
  3. ldc "bb":将字符串 "bb" 加载到常量池中。
  4. invokevirtual StringBuilder.toString():拼接后生成一个新的字符串对象。

4. 为什么需要理解这些对象的创建?

Java 中的字符串是不可变的,因此每次创建新字符串都需要分配新的内存。如果频繁进行字符串操作而不加优化,会造成不必要的内存浪费和性能问题。

  • 优化建议:
    1. 避免使用 new String()
      String a = "aa"; // 直接使用字符串字面量,避免创建额外对象
      
    2. 大量拼接时使用 StringBuilder
      StringBuilder sb = new StringBuilder();
      sb.append("aa").append("bb");
      String a = sb.toString();
      

发表回复

后才能评论