First, create directly

1. Diagram the creation process

Code and bytecode combat

2.1. Create string constants in the constant pool

Implementation process:

Create the string directly, stack it into the string constant pool, and then save the string reference to the local variable pool.

Public class Test {public static void main(String[] args) {String a = "ab"; Public static void main(java.lang.string []); public static void main(java.lang.string []); String ab 2: astore_1 3: return} String ab 2: astore_1 3: return}Copy the code
Create a string object in the heap

Implementation process:

  1. Create a String in the heap;
  2. Declare string “ab” in constant pool;
  3. Initialize a String by calling the String initialization method based on the value “ab”
Public class Test {public static void main(String[] args) {String a = new String("ab"); Public static void main(java.lang.string []); public static void main(java.lang.string []); Code: 0: new #2 // class java/lang/String 3: dup 4: ldc #3 // String ab 6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;) V 9: astore_1 10: return }Copy the code

Two, combination creation

During string concatenation, whenever there is concatenation of variables or string objects in the heap, a StringBuilder object will be created first and used to complete the concatenation process of one string by one.

Scenario 1: In the constant pool (string object + string object)

Implementation process:

  1. The procedure for executing “a” + “b” is the same as the procedure for creating “a” and “b”, which is created directly in the string constant pool.
  2. During the creation of ab, “a” and “b” need to be used, but “A” and “b” already exist in the constant string pool. Therefore, the string concatenation is directly completed without repeated creation. The string “ab” is created in the constant pool, and the address is assigned to the string object reference ab.
Public class Test {public static void main(String[] args) {String a = "a"; String b = "b"; String ab = "a" + "b"; Public static void main(java.lang.string []); public static void main(java.lang.string []); Code: 0: LDC #2 // String a 2: astore_1 3: LDC #3 // String b 5: astore_2 ldc #4 // String ab 8: astore_3 9: return }Copy the code

Scenario 2: In the constant pool (string object reference + string object reference)

Implementation process:

  1. The creation of strings A and B is not surprising and is declared directly in the string constant pool.
  2. After the String ab = a + b; What did he do when he was in the hospital? The StringBuilder object is created, and the initialization method is called to initialize the object.
  3. Execute aload_1 to load the variable of number 1, which is a reference to string A, from the local variable.
  4. Execute the Invokespecial directive to call the StringBuilder internal Append method to complete the concatenation of string A.
  5. Repeat procedure 3-4 to complete the concatenation of string B.
  6. The invokevirtual directive calls the StringBuilder internal method toString to create a new String.
  7. Push the new String by reference to ab.
Public class Test {public static void main(String[] args) {String a = "a"; String b = "b"; String ab = a + b; Public static void main(java.lang.string []); public static void main(java.lang.string []); Code: 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: new #4 // class java/lang/StringBuilder 9: dup 10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 13: aload_1 14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder; 17: aload_2 18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder; 21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 24: astore_3 25: return }Copy the code

Scenario 3: String object + Final constant in constant pool

Implementation process:

  1. Declare the string “a” to the constant pool.
  2. With the addition of the final modifier, why is there no longer a declaration procedure for the string “b”? TODO question to be solved.
  3. Declare “ab” directly in the constant pool for the string ab.
Public class Test {public static void main(String[] args) {String a = "a"; final String b = "b"; String ab = "a" + b; Public class Test {public Test(); Public static void main(java.lang.string []); public static void main(java.lang.string []); Code: 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String ab 5: astore_3 6: return }Copy the code

Scenario 4: Objects in the heap + string object references in the constant pool

Implementation process:

  1. Create the string “b” in the string constant pool, and then save the string reference to the local variable.
  2. Create a StringBuilder object and call the StringBuilder initialization method.
  3. Create a String in the heap, declare the String “a” in the String constant pool, and initialize the String you just created.
  4. The append method of the Stringbuilder object is called to concatenate the value of the created String.
  5. Call the Append method of the StringBuilder object again to concatenate the “b” to which the string b points.
  6. An internal method toString() is called to generate a String object, which is stored as a reference to the local variable pool.
Public class Test {public static void main(String[] args) {String b = "b"; String ab = new String("a") + b; Public static void main(java.lang.string []); public static void main(java.lang.string []); Code: 0: ldc #2 // String b 2: astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 10: new #5 // class java/lang/String 13: dup 14: ldc #6 // String a 16: invokespecial #7 // Method java/lang/String."<init>":(Ljava/lang/String;) V 19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder; 22: aload_1 23: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder; 26: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 29: astore_2 30: return }Copy the code

The rogue intern() function

First look at the following procedure, if a point of no ambiguity completely correct, from the point of view of cherish life, do not continue to see.

Clear the first level

Public void test1() {String s1 = new String("hello world"); String s1 = new String("hello world"); String s1 = new String("hello world"); String s2 = s1.intern(); String s3 = "hello world"; System.out.println(s1 == s2); // false System.out.println(s3 == s2); // true }Copy the code

Pass the second level

Public void test2() {String s1 = new String("12") + new String("3"); String s2 = s1.intern(); String s3 = "123"; System.out.println(s1 == s2); // true System.out.println(s2 == s3); // true System.out.println(s1 == s3); // true } public void test2() { String s1 = new String("12") + new String("3"); String s3 = "123"; System.out.println(s1 == s3); // false }Copy the code

Pass the third level

@Test public void test3() { String s1 = new String("12") + new String("3"); String s2 = s1.intern(); String s3 = new String("12") + new String("3"); String s4 = s3.intern(); String s5 = "123"; System.out.println(s1 == s2); // true System.out.println(s2 == s4); // true System.out.println(s5 == s3); // false }Copy the code

Principle of drafting

Before looking at the diagram, let’s take a quick look at two data structures in hotspot:

Constant Pool: Similar to an array that stores the contents of Constant string entities

String Table: The underlying structure is similar to HashTable, but without expansion, it stores the addresses of strings

supplement

After the String is declared in the String constant pool, we can assume that hotspot will default to calling the intern() method to store the address in the String Table. It doesn’t, but the process is too complicated and involves the subdivision of loading and parsing, which is a rough understanding here.

The constant pool technique of thought abstraction

Compiler load and runtime load

During the compilation of source code to bytecode, the string resources that can be determined are stored in the constant pool. String resources that can only be verified in the compiler are all stored in the heap, and different types of resources are stored in different locations, just like the kitchen and study, living room and bedroom design in a house today.

Analyze the underlying structure of Constant Pool and String Table

Constant Pool stores actual contents, while String Table stores references. One of the requirements of these two data structures is fast lookup, and String Table needs to meet the function of fast lookup. Therefore, address reference is designed as the data structure corresponding to hash code. We can take out the address value to achieve the effect of quickly searching resources in Constant Pool with the minimum memory resource overhead. Of course, there are a lot of questions, like how do we design a String Table so that we can quickly find and locate the values of the contents of the Table, what do we do with the address of the object that we call intern() in the heap in the String Table because the object in the heap is going to be reclaimed, and if the object in the heap is reclaimed, Will the addresses stored in the String Table also be cleared? The more you know, the more you don’t know…

References:

  1. Add two string objects and compare them to string literals. www.zhihu.com/question/26…
  2. [after reading this JVM, ali interviewers are not afraid!] blog.csdn.net/Java_3y/art…
  3. Ultimate analysis way [String to create a memory] blog.csdn.net/kevindai007…
  4. [The Java ® Virtual Machine Specification] docs.oracle.com/javase/spec…