Don't ask me how many objects new string created! I'll prove it to you!

Posted by wulfgar on Fri, 17 Apr 2020 09:46:27 +0200

Yunqi information:[ Click to see more industry information]
Here you can find the first-hand cloud information of different industries. What are you waiting for? Come on!

I think all Java programmers have been bothered by this new String question, which is a high-frequency Java interview question, but unfortunately, there are different opinions on the Internet, and even no standard answer can be found. Some say that we have created one object, some say that we have created two objects, others say that we may have created one or two objects, but no one has come up with evidence to kill the other, which makes our melon eaters in a dilemma, and we don't know who to trust.

But today, Lao Wang has the courage to talk to you about this topic and show some evidence by the way.

In the current situation, there are three answers to the number of objects created by new String("xxx"):

1. It is said that an object has been created;

2. It is said that two objects have been created;

3. It is said that one or two objects have been created.

The key issue of multiple answers lies in "string constant pool". Some people say that the new string will create a string object in the constant pool. Some people say that the new string will not create an object in the string constant pool, but will detect and create a string in the string constant pool when calling the inter () method.

Let's talk about the string constant pool first.

String constant pool

String allocation, like other object allocation, costs a lot of time and space. If you need to create a large number of strings frequently, it will greatly affect the performance of the program. Therefore, in order to improve performance and reduce memory overhead, the JVM introduces the concept of Constant Pool Table.

String constant pool is equivalent to opening a constant pool space for strings, similar to cache area, for strings with direct assignment (String s="xxx") for example, when creating a string, the string that already exists in the string constant pool will be used first. If there is no relevant string in the string constant pool, the string will be created in the string constant pool first, and then the reference address will return the variable, as shown in the following figure:

The above statement can be proved by the following code:

    public static void main(String[] args) {
        String s1 = "Java";
        String s2 = "Java";
        System.out.println(s1 == s2);
    }
}

The execution result of the above program is: true, indicating that variable s1 and variable s2 point to the same address.

By the way, let's talk about the changes of different JDK versions of string constant pool.

Memory layout of constant pool

After JDK 1.7, the Metaspace replaced by immortality moved the string constant pool from the method area to the Java heap.

The memory layout of JDK 1.7 is as follows:

The memory layout of JDK 1.8 is as follows:

The biggest difference between JDK 1.8 and JDK 1.7 is that JDK 1.8 will permanently cancel the generation and set up a meta space. The official explanation is that because the permanent memory is often not enough or memory leaks, the exception of java.lang.OutOfMemoryError: PermGen will pop out. Therefore, the permanent area will be abandoned and the meta space will be used instead of the local memory space.

Decryption of answers

The person who thinks that the new method creates an object thinks that the new String only creates an object on the heap, and only when using the intern(), can it find and create a string in the constant pool.

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

Those who think that the new method is possible to create one or two objects think that the new String will first go to the constant pool to determine whether there is such a string. If there is one, only one string will be created on the heap and point to the string in the constant pool. If there is no such string in the constant pool, then two will be created Objects, first create a new String in the constant pool, and then return the reference to the object on the heap, as shown in the following figure:

Lao Wang thinks the right answer: create one or two objects.

technological verification

To solve the problem, you have to tie the bell. Go back to that dispute point, will new String create characters in the constant pool? We can draw a correct conclusion by decompiling the following code. The code is as follows:

    public static void main(String[] args) {
        String s1 = new String("javaer-wang");
        String s2 = "wang-javaer";
        String s3 = "wang-javaer";
    }
}

First, we use javac StringExample.java to compile the code, and then we use javap -v StringExample to view the compiled results. The relevant information is as follows:

  Last modified 2020 April 16th 2013; 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"

Note: the above code is also compiled in jdk1.8.0_101.

The Constant pool represents the string Constant pool. We found our string S1 = new String ("Java Er Wang") in the string Constant pool during string compilation; The defined "javaer Wang" character can be seen in the information ා 10 = utf8 javaer Wang, that is, the string created in the new mode during compilation will be put into the string Constant pool during compilation, that is, the new String

If there is no new string, two objects will be created. If there is already one, only one object will be created in the heap to point to the string in the string constant pool.

So the question is, is the execution result of the following code true or false?

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

Since new String will create a string in the constant pool, the result of execution should be true. In fact, it's not the address on the heap of variables s1 and s2 compared here. Because the address on the heap is different, the result must be false, as shown in the following figure:

It can be seen from the figure that the references of s1 and s2 must be the same, while the references of s3 and s4 are different. The corresponding program code is as follows:

    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);
}

The results of the program implementation are also in line with expectations:

true false

Expand knowledge

We know that String is final decorated, that is to say, it must be assigned and cannot be modified. However, in addition to the optimization of String constant pool, the compiler also optimizes strings that can be confirmed during compilation, such as the following code:

    String s1 = "abc";
    String s2 = "ab" + "c";
    String s3 = "a" + "b" + "c";
    System.out.println(s1 == s2);
    System.out.println(s1 == s3);
}

According to the idea that String cannot be modified, s2 should create two strings "ab" and "c" in the String constant pool, s3 will create three strings, and their reference comparison results must be false, but in fact, their results are all true, which is the credit of compiler optimization.

Similarly, we use Java C StringExample.java to compile the code first, and then use the javap -c StringExample command to view the compiled code as follows:

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
}

From Code 3 and 6, we can see that strings have been optimized to "abc" by the compiler.

summary

In this article, we look at the compiled code through javap-v XXX and find that new String will create this string in the string constant pool for the first time, that is to say, the way of creating a string through new may create one or two Objects. If the string already exists in the constant pool, only one variable will be created on the heap and it will point to the value in the string constant pool. If there are no relevant characters in the string constant pool, the variable that references the string to the heap space will be created first. We also changed the string constant pool in JDK 1.7 and JDK 1.8 and optimized the compiler to determine the string, hoping to help you understand the string comparison.

[yunqi online class] product technology experts share every day!
Course address: https://yqh.aliyun.com/live

Join the community immediately, face to face with experts, and keep abreast of the latest news of the course!
[yunqi online classroom community] https://c.tb.cn/F3.Z8gvnK

Original release time: April 17, 2020
Author: Java Chinese community
This article comes from:“ Nuggets ”For more information, you can focus on "gold diggers"

Topics: Java JDK jvm