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 或 2 | new 创建 1 个,"hello" 可能已有 |
"a" + "b"(字面量拼接) | 1 | 编译期常量折叠 |
a + b(变量拼接) | ≥ 4 | StringBuilder + StringBuilder.toString() |
new String("a").intern() | 1 或 2 | intern 后 StringTable 共享 |
sb.toString() | 1 | 创建新 String 对象 |
理解这些面试题的关键在于:字面量在 StringTable,new String() 在堆中,拼接用 StringBuilder。
到这里,「String 专题」全部完成,「执行引擎与核心专题」也全部完成。
