I think all Java programmers have been bothered by this new String question. This is a common Java interview question, but unfortunately there are so many opinions on the Internet that there is no standard answer. Some say one object was created, some say two, and some say maybe one or two, but neither has produced any evidence of killing the other, leaving us melon eaters in a dilemma as to whom to trust.

But today, Lao Wang dares to talk to you about this topic, and by the way take out some evidence.

As it stands, there are three answers to the number of objects created by the new String(” XXX “) :

  1. Somebody said I created an object;
  2. Someone said I created 2 objects;
  3. Someone said they created one or two objects.

In more than one answer key controversial points in the “pool” string constants, in some way that say new string constant pool create a string object, some people say that the new string string constant pool will not go when creating objects, but in the calling intern () method, to string constant pool detection and create a string.

Let’s start with the string constant pool.

String constant pool

String allocation, like other object allocation, takes a high cost of time and space. If a large number of strings are frequently created, the performance of the program will be greatly affected. Therefore, the JVM introduced the concept of Constant Pool Table of strings to improve performance and reduce memory overhead.

String constant pool is equivalent to a constant pool up space is similar to the buffer zone, direct assignment for strings (String s = “XXX”), in each time you create a String using existing String String constant pool, if there is no such String String constant pool, will create the String in the String constant pool, Then return the variable with the reference address, as shown below:

The above statement can be proved by the following code:

public class StringExample { public static void main(String[] args) { String s1 = "Java"; String s2 = "Java"; System.out.println(s1 == s2); }} Copy the codeCopy the code

The result of the above program is true, indicating that s1 and s2 refer to the same address.

We’ll mention the string constant pool changes in different JDK versions.

Here, by the way, I send you a classic learning materials, I used in university and work of the classic e-book library (including data structure, operating system, C++/C, network classics, front-end programming classics, Java related, programmer cognition, career development), interview and job summary are packed here.

Click here to get directly:

Computer Classics required reading list (including download methods)

Java to master the interview with the most complete information package (including download methods)

Memory layout for constant pools

Since JDK 1.7, we have replaced immortal generations with meta-spaces, moving the string constant pool from the method area to the Java heap.

The JDK 1.7 memory layout is shown below:

The JDK 1.8 memory layout is shown below:

The biggest difference between JDK 1.8 and JDK 1.7 is that JDK 1.8 cancels the permanent generation and sets up a meta-space. Official to memory that is due to a permanent generation often enough or memory leaks occur, will be Java. Lang. OutOfMemoryError: PermGen anomalies, so the area will be permanently abandoned to yuan space, change in order to use the local memory space, website to explain details: openjdk.java.net/jeps/122

The answer to decrypt

People who think that new creates 1 object think that new String just creates an object on the heap and only looks up and creates strings in the constant pool when you use intern().

People who think that new creates two objects think that new String creates an object on the heap and also creates a String in the String constant pool.

People who think it’s possible to create one or two objects with new say that the new String will first check the constant pool for the String, and if it does, it will just create one String on the heap and point to the String in the constant pool, and if it doesn’t, it will create two objects, Create a new string in the constant pool, then return the reference to the object on the heap, as shown below:

Wang thinks the right answer is to create one or two objects.

Technology demonstration

Back to the controversial point of the question, does a new String create a character in a constant pool? We can get to the correct conclusion by decompiling the following code:

public class StringExample { public static void main(String[] args) { String s1 = new String("javaer-wang"); String s2 = "wang-javaer"; String s3 = "wang-javaer"; }} Copy the codeCopy the code

Javap -v StringExample javap -v StringExample javac StringExample

Classfile /Users/admin/github/blog-example/blog-example/src/main/java/com/example/StringExample.class Last modified 16 April 2020; size 401 bytes SHA-256 checksum 89833a7365ef2930ac1bc3d7b88dcc5162da4b98996eaac397940d8997c94d8e Compiled from "StringExample.java" public class com.example.StringExample minor version: 0 major version: 58 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #16 // com/example/StringExample super_class: #2 // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #2.#3 // java/lang/Object."<init>":()V #2 = Class #4 // java/lang/Object #3 = NameAndType #5:#6 // "<init>":()V #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8 ()V #7 = Class #8 // java/lang/String #8 = Utf8 java/lang/String #9 = String #10 // javaer-wang #10 = Utf8 javaer-wang #11 = Methodref #7.#12 // java/lang/String."<init>":(Ljava/lang/String;) V #12 = NameAndType #5:#13 // "<init>":(Ljava/lang/String;) V #13 = Utf8 (Ljava/lang/String;) V #14 = String #15 // wang-javaer #15 = Utf8 wang-javaer #16 = Class #17 // com/example/StringExample #17 = Utf8 com/example/StringExample #18 = Utf8 Code #19 = Utf8 LineNumberTable #20 = Utf8 main #21 = Utf8 ([Ljava/lang/String; )V #22 = Utf8 SourceFile #23 = Utf8 StringExample.java { public com.example.StringExample(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=4, args_size=1 0: new #7 // class java/lang/String 3: dup 4: ldc #9 // String javaer-wang 6: invokespecial #11 // Method java/lang/String."<init>":(Ljava/lang/String;)V 9: astore_1 10: ldc #14 // String wang-javaer 12: astore_2 13: ldc #14 // String wang-javaer 15: astore_3 16: Return LineNumberTable: line 5: 0 line 6: 10 line 7: 13 line 8: 16} SourceFile: "stringexample. Java" Copies the codeCopy the code

Note: the above code also runs in jdk1.8.0_101.

S1 = new String(“javaer-wang”); s1 = new String(“javaer-wang”); The “javaer-wang” character is defined as #10 = Utf8 javaer-wang, which means that strings created at compile-time in the new mode are put into the compile-time string constant pool. So the new String method will evaluate the String constant pool first, if it doesn’t have a new String it will create two objects, if it already exists it will only create one object in the heap that points to the String in the String constant pool.

So the question is, is this code true or false?

String s1 = new String("javaer-wang"); String s2 = new String("javaer-wang"); System.out.println(s1 == s2); Copy the codeCopy the code

Since new String creates a String in the constant pool, the result of the execution should be true. The heap address of s1 and s2 is different, so the result must be false, as shown in the following figure:

As can be seen from the figure, s1 and S2 references must be the same, while S3 and S4 references are different, and the corresponding program code is as follows:

public static void main(String[] args) { String s1 = "Java"; String s2 = "Java"; String s3 = new String("Java"); String s4 = new String("Java"); System.out.println(s1 == s2); System.out.println(s3 == s4); } Duplicate codeCopy the code

The results of program execution are also in line with expectations:

true false

Expand the knowledge

We know that strings are final, which means that they cannot be modified without being assigned. But in addition to optimizations for string constant pools, the compiler also optimizes strings that can be validated at compile time, such as the following code:

public static void main(String[] args) { String s1 = "abc"; String s2 = "ab" + "c"; String s3 = "a" + "b" + "c"; System.out.println(s1 == s2); System.out.println(s1 == s3); } Duplicate codeCopy the code

S2 would create two strings “ab” and “c” in the String constant pool, s3 would create three strings, and their reference comparisons would be false, but they are not, they would both be true, thanks to compiler optimization.

Javap -c StringExample javap -c StringExample javac StringExample

Warning: File. / StringExample. The class does not contain class StringExample Compiled from "StringExample. Java" public class com. Example. StringExample { public com.example.StringExample(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #7 // String abc 2: astore_1 3: ldc #7 // String abc 5: astore_2 6: ldc #7 // String abc 8: astore_3 9: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 12: aload_1 13: aload_2 14: if_acmpne 21 17: iconst_1 18: goto 22 21: iconst_0 22: invokevirtual #15 // Method java/io/PrintStream.println:(Z)V 25: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 28: aload_1 29: aload_3 30: if_acmpne 37 33: iconst_1 34: goto 38 37: iconst_0 38: Invokevirtual # 15 / Method/Java/IO/PrintStream println (Z) V 41: return} copy codeCopy the code

From Code 3 and 6 you can see that the strings are optimized by the compiler to the string “ABC”.

I myself liver six copies of PDF < about Java entry to god >, the whole network spread more than 10W +, search “code farmers attack” after paying attention to the public number, in the background reply PDF, get all PDF

Six PDF links

conclusion

In this article we looked at the compiled code in Javap -v XXX and found that new String creates this String for the first time in the String constant pool. That is, the way new creates a String may create one or two objects. If the string already exists in the constant pool, only one variable is created on the heap and points to the value in the string constant pool. If there are no related characters in the string constant pool, the string is created first before returning a variable referencing the string to the heap space. We also covered the string constant pool changes in JDK 1.7 and JDK 1.8 and compiler optimizations for determining strings to help you understand string comparisons.

The last words are not easy to be original. The author spent more than 5 hours on nearly 3000 text descriptions and a large number of beautiful pictures. Writing is a cool and helpful thing, and the author hopes to keep on doing it. If you feel useful, please click on a “like” bar, thank you.

For more exciting content, please follow the wechat public account “Code farmers attack”.