您的问题的任何答案都将取决于JVM实现和当前使用的Java版本。我认为在采访中问这是一个不合理的问题。
爪哇 8
在我的机器上,使用 Java 1.8.0_201 时,您的代码段会生成此字节码
L0
LINENUMBER 13 L0
LDC "First"
ASTORE 1
L1
LINENUMBER 14 L1
LDC "Second"
ASTORE 2
L2
LINENUMBER 15 L2
LDC "Third"
ASTORE 3
L3
LINENUMBER 16 L3
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 3
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 4
这证明了正在创建5个对象(3个文本*,1个StringBuilder
,1个由StringBuilder#toString
动态生成的实例)。String
String
Java 12
在我的机器上,使用Java 12.0.2,字节码是
// identical to the bytecode above
L3
LINENUMBER 16 L3
ALOAD 1
ALOAD 2
ALOAD 3
INVOKEDYNAMIC makeConcatWithConstants(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; [
// handle kind 0x6 : INVOKESTATIC
java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
// arguments:
"\u0001\u0001\u0001"
]
ASTORE 4
它神奇地将“正确答案”更改为4个对象,因为不涉及中间部分。StringBuilder
*让我们更深入地挖掘一下。
在以下情况下,可能会隐式创建新的类实例:
- 加载包含字符串文本 (§3.10.5) 的类或接口可能会创建一个新的 String 对象来表示文本。(如果以前已暂存表示相同 Unicode 码位序列的字符串,则不会发生这种情况。
换句话说,当您启动应用程序时,字符串池中已经有对象。您几乎不知道它们是什么以及它们来自哪里(除非您扫描所有加载的类以查找它们包含的所有文本)。
毫无疑问,该类将作为基本 JVM 类加载,这意味着其所有文本都将被创建并放入池中。java.lang.String
让我们从 的源代码中随机选择一个片段,从中挑选几个文字,在程序的开头放置一个断点,然后检查池是否包含这些文字。String
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence,
Constable, ConstantDesc {
...
public String repeat(int count) {
// ...
if (Integer.MAX_VALUE / count < len) {
throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
" times will produce a String exceeding maximum size.");
}
}
...
}
他们确实在那里。
作为一个有趣的发现,这个IDEA的过滤有一个副作用:我正在寻找的子字符串也被添加到池中。应用 this.contains(“bytes String”
) 后,池大小增加了一个(添加了“bytes String”)。
这给我们留下了什么?
在我们打电话之前,我们不知道是否被创建和实习,所以我们不能坚定地声明这条线创建了一个新的实例。"First"
String str1 = "First";