Skip to content

new String() 创建对象数面试题

最经典的 String 面试题

new String("hello") 到底创建了几个对象?这是 Java 面试中出现频率最高的题目之一。

直接回答:1 个或 2 个

new String("hello") 的答案取决于 StringTable 中是否已有 "hello"

java
public class NewStringQuestion {
    public static void main(String[] args) {
        // 情况一:StringTable 中没有 "hello"
        // 创建 2 个对象
        String s1 = new String("hello");
        // 对象1: new String() 在堆中创建的新 String 对象
        // 对象2: "hello" 字符串对象(在 StringTable 中)

        // 情况二:StringTable 中已有 "hello"
        // 创建 1 个对象
        String s2 = new String("hello");
        // 对象: new String() 在堆中创建的新 String 对象
        // ("hello" 已在 StringTable 中,不重复创建)
    }
}

题目一:经典变形

java
public class ClassicQuestion {
    public static void main(String[] args) {
        String s = new String("ab");
    }
}

答案:1 个或 2 个

  • 如果 "ab" 不在 StringTable → 2 个
  • 如果 "ab" 已在 StringTable → 1 个

题目二:字节码验证

java
public class ByteCodeVerify {
    public static void main(String[] args) {
        String s = new String("ab");
    }
}

javap -c 字节码:

java
public static void main(java.lang.String[]);
    Code:
      0: new           #16          // new String
      3: dup                        // 复制引用
      4: ldc           #17          // 加载常量池中的 "ab"
      6: invokespecial #18          // 调用 String(String) 构造器
      9: astore_1                 // 存到局部变量
     10: return

关键步骤:

0: new #16          → 在堆中分配 String 对象
4: ldc #17          → 从常量池加载 "ab"
                     → 如果 StringTable 中没有 "ab",创建 "ab"
6: invokespecial    → 调用构造器

实际上创建了几个对象?

  • new #16 → 肯定创建了 1 个 String 对象(堆中)
  • ldc #17 → 可能创建了 1 个字符串对象(在 StringTable 中)

题目三:字面量拼接

java
public class LiteralConcat {
    public static void main(String[] args) {
        String s = "a" + "b";
    }
}

javap -c 字节码:

java
public static void main(java.lang.String[]);
    Code:
      0: ldc           #16          // 加载常量池中的 "ab"
      2: astore_1
      3: return

答案:1 个对象

编译器在编译时把 "a" + "b" 优化成了 "ab" —— 这叫常量折叠。因为 "a""b" 都是编译期常量,编译器在编译时就计算出了结果。

题目四:变量拼接

java
public class VariableConcat {
    public static void main(String[] args) {
        String a = "a";
        String b = "b";
        String s = a + b;
    }
}

javap -c 字节码:

java
public static void main(java.lang.String[]);
    Code:
       0: ldc           #16          // "a"
       2: astore_1
       3: ldc           #17          // "b"
       5: astore_2
       6: new           #18          // StringBuilder
       9: dup
      10: invokespecial #19
      13: aload_1                  // append(a)
      14: invokevirtual #20
      17: aload_2                  // append(b)
      18: invokevirtual #20
      21: invokevirtual #21          // toString()
      24: astore_3
      25: return

答案:至少 3 个对象

  • "a" → StringTable 中的字符串对象
  • "b" → StringTable 中的字符串对象
  • new StringBuilder() → 堆中的 StringBuilder 对象
  • new String(...)StringBuilder.toString() 创建的 String 对象

所以实际是 4 个对象(StringBuilder.toString() 本身会创建新的 String)。

题目五:StringBuilder 的 toString()

java
public class StringBuilderToString {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        String s = sb.toString();
    }
}

StringBuilder.toString() 的实现:

java
public String toString() {
    return new String(this, 0, count);
    // 内部创建了一个新的 String 对象
}

答案:至少 3 个对象

  • new StringBuilder() → 堆中的 StringBuilder 对象
  • sb.append("hello") → StringTable 中的 "hello"
  • sb.toString() → 堆中新创建的 String 对象

题目六:StringBuilder 空构造器 vs 指定大小

java
public class StringBuilderSize {
    public static void main(String[] args) {
        // 空构造器:默认容量 16
        StringBuilder sb1 = new StringBuilder();

        // 指定大小:指定初始容量
        StringBuilder sb2 = new StringBuilder(100);

        // 指定字符:容量 = 字符串长度 + 16
        StringBuilder sb3 = new StringBuilder("hello");
    }
}

StringBuilder 内部容量机制

java
// 空构造器
public StringBuilder() {
    super(16);  // char[] value = new char[16]
}

// 指定初始容量
public StringBuilder(int capacity) {
    super(capacity);  // char[] value = new char[capacity]
}

// 指定初始字符串
public StringBuilder(String str) {
    super(str.length() + 16);  // char[] value = new char[str.length() + 16]
    append(str);
}

内存优化建议:如果能预估字符串长度,用带初始容量的构造器可以避免扩容。

题目七:intern() 与对象数量

java
public class InternObjectCount {
    public static void main(String[] args) {
        String s = new String("hello").intern();
    }
}

答案:1 个或 2 个对象

  • "hello" → 如果不在 StringTable 中,创建 1 个(StringTable)
  • new String("hello") → 创建 1 个(堆)
  • intern() → 如果 StringTable 中没有,加入并返回

面试回答模板

问:new String("hello") 创建了几个对象?

答:答案是 1 个或 2 个。

具体来说:
1.  new String("hello") 一定会创建一个新的 String 对象(在堆中)
2.  "hello" 字符串字面量,如果之前不在 StringTable 中,
    会创建一个字符串对象加入 StringTable

所以:
- StringTable 中没有 "hello" → 创建 2 个对象
- StringTable 中已有 "hello" → 创建 1 个对象

验证方法:看字节码中 ldc 指令(加载常量池)和 new 指令。

本节小结

代码对象数量说明
new String("hello")1 或 2new 创建 1 个,"hello" 可能已有
"a" + "b"(字面量拼接)1编译期常量折叠
a + b(变量拼接)≥ 4StringBuilder + StringBuilder.toString()
new String("a").intern()1 或 2intern 后 StringTable 共享
sb.toString()1创建新 String 对象

理解这些面试题的关键在于:字面量在 StringTable,new String() 在堆中,拼接用 StringBuilder

到这里,「String 专题」全部完成,「执行引擎与核心专题」也全部完成。

基于 VitePress 构建