bhp*_*psh 36 java string string-concatenation string-building string-pool
在一次采访中,有人问我要在给定问题上创建的对象数量:
String str1 = "First";
String str2 = "Second";
String str3 = "Third";
String str4 = str1 + str2 + str3;
我回答说将在字符串池中创建6个对象。
三个变量中的每个变量都为3。
1代表str1 + str2(假设str)。
1代表str2 + str3。
1将代表str + str3(str = str1 + str2)。
我给出的答案正确吗?如果没有,正确答案是什么?
And*_*lko 31
Any answer to your question will depend on the JVM implementation and the Java version currently being used. I think it's an unreasonable question to ask in an interview.
On my machine, with Java 1.8.0_201, your snippet results in this bytecode
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
which proves that 5 objects are being created (3 String literals*, 1 StringBuilder, 1 dynamically produced String instance by StringBuilder#toString).
On my machine, with Java 12.0.2, the bytecode is
// 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
which magically changes "the correct answer" to 4 objects since there is no intermediate StringBuilder involved.
*Let's dig a bit deeper.
12.5. Creation of New Class Instances
A new class instance may be implicitly created in the following situations:
- Loading of a class or interface that contains a string literal (§3.10.5) may create a new String object to represent the literal. (This will not occur if a string denoting the same sequence of Unicode code points has previously been interned.)
In other words, when you start an application, there are already objects in the String pool. You barely know what they are and where they come from (unless you scan all loaded classes for all literals they contain).
The java.lang.String class will be undoubtedly loaded as an essential JVM class, meaning all its literals will be created and placed into the pool. 
Let's take a randomly selected snippet from the source code of String, pick a couple of literals from it, put a breakpoint at the very beginning of our programme, and examine if the pool contains these literals.
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.");
        }
    }
    ...
}
They are there indeed.
 

As an interesting find, this IDEA's filtering has a side effect: the substrings I was looking for have been added to the pool as well. The pool size increased by one ("bytes String" was added) after I applied this.contains("bytes String").
Where does this leave us?
We have no idea whether "First" was created and interned before we call String str1 = "First";, so we can't state firmly that the line creates a new instance.
Tur*_*g85 18
根据给定的信息,不能肯定地回答该问题。正如JLS§15.18.1中所述:
为了提高重复字符串连接的性能,Java编译器可以使用
StringBuffer该类或类似技术来减少通过对表达式求值而创建的中间String对象的数量。
这意味着答案至少取决于所使用的具体Java编译器。
我认为我们能做的最好的就是给一个间隔作为答案:
str1对str3编译过程中从未使用过并折叠级联,使得仅一个String被创建-object( -一个通过引用str4)String创建的s 的最大可感知数目应为5:分别为str1to str3,1 for tmp = str1 + str2和for str4 = tmp + str3。所以...我的回答是“一到五个String对象之间的东西”。至于仅为此操作创建的对象总数...我不知道。这也可能取决于例如如何精确地StringBuffer实现。
顺便说一句:我想知道问这些问题的原因是什么。通常,不需要关心那些细节。
Java 8可能会创建5个对象:
StringBuilderString随着Java 9的改变,String连接已不再使用StringBuilder。
| 归档时间: | 
 | 
| 查看次数: | 1138 次 | 
| 最近记录: |