intern method learning of String class

  • The intern() method in the String class belongs to the native method
  • Because of the changes in the implementation of the method area in different versions of JDK, especially the movement of the string constant pool, the intern() method also changes

1. Change of intern method

1.1 String.intern() method in JDK 1.6

  • In JDK 1.6, the string constant pool is in the permanent generation and the string object instance is in the heap
  • Call the intern() method to try to add a string to the string constant pool
    • If there is no equivalent string in the string constant pool, the contents of the string will be copied to the pool, and then the string address in the pool will be returned
    • If an equal string exists in the string constant pool, the string address in the pool is returned
  • The following code: after calling the intern() method, it will copy a string from the pool and return the string address in the pool
    String str1 = new String("hello") + new String("world");
    str1.intern();
    String str2 = "helloworld";
    System.out.println(str1 == str2); //false
    

1.2 String.intern() method of JDK 1.7 and later

  • Since JDK 1.7, the string constant pool has been moved from the permanent generation to the Java heap, and the new string object is also located in the Java heap
  • Call the intern() method to try to add a string to the string constant pool
    • If there is no equal string in the string constant pool, the address of the string in the Java heap will be copied to the pool, and then the address of the string in the pool will be returned.
    • That is, the intern method returns the address of the string object in the Java heap

      This change is to reduce the memory overhead of the Java heap

    • If an equal string exists in the string constant pool, the string address in the pool is returned
  • Therefore, the same code, str1 and str2 point to the same address. When making = = judgment, it will return true

2. Compile time string literal

2.1 introduction

A question

  • Why does str1 point to a String object in the Java heap and str2 point to a String in the String constant pool?
String str1 = new String("hello") + new String("world");
String str2 = "helloworld";
  • One might say that this is not simple: the String object is assigned to str1 and the String literal is assigned to str2
  • str1 of course points to the object instance in the Java heap, and str2 of course points to the string (or string literal) in the string constant pool

Another question

  • As far as we know, there are many ways to get a string reference

    // Direct acquisition
    String str1 = "hello";
    String str2 = new String("world");
    String str3 = new StringBuilder("lucy").append(" jack").toString();
    // String splicing
    String str4 = "hello, " + new String("world");
    String str5 = "computer" + "Software";
    String str6 = new String("hello, " + "world");
    
  • There are so many ways, which way to get the string reference from the string constant pool?

2.2 compile time string literals

A law

  • When the intern() method is not executed, the literal amount of the string that can be determined at compile time will be automatically put into the string constant pool

  • At this point, the String reference points to an address that will be in the String constant pool

  • Note: the intern() method must not be executed. Otherwise, in JDK 1.7 and later, the String reference looks to get the address in the String constant pool, but actually points to the object address in the Java pair

  • The following code changes the execution order of the intern() method and will produce different results in JDK 1.8

    public static void main(String[] args) {
        String str1 = new String("hello") + " world";
        str1.intern();
        String str2 = "hello world";
        System.out.println("str1 == str2: " + (str1 == str2));
    
        String str3 = new String("hello") + " lucy";
        String str4 = "hello lucy";
        str3.intern();
        System.out.println("str3 == str4: " + (str3 == str4));
    }
    
  • The results are as follows:

What are string literals that can be determined at compile time?

  • Case 1: string of '' enclosed in double quotes

  • In the following code, the double quotation marks are all string literals (the display is not complete, just a simple example)

    public static void main(String[] args) {
        String str1 = new String("hello");
        String str2 = "lucy";
        String str3 = new StringBuilder("jack").append("john").toString();
        String str4 = new String("test") + "ok";
    }
    
  • The following new String() will actually create two hello strings. One is the literal value of the String during compilation, which is automatically put into the String constant pool; One is to create a String object in the Java heap after new String()

    public static void main(String[] args) {
        String str1 = new String("hello"); // The string literal hello at compile time will be automatically put into the pool
        String str2 = str1.intern(); // When using the intern() method, an equal string already exists in the pool
        System.out.println("str1 == str2: " + (str1 == str2)); // Return false
    }
    
  • Case 2: during string splicing, as long as it is not the splicing of reference and string literal, it can be determined at compile time

    public static void main(String[] args) {
        String str1 = new String("hello, " + "world"); // During compilation, string literal hello, world is spliced
        System.out.println(str1.intern() == str1); // Return false
    
        String str3 = new String("test") + "Method"; // At compile time, only test and Method string literals can be determined
        System.out.println(str3.intern() == str3); // Return true
    }
    
  • The results are as follows:

  • Special case: if the reference points to the final type (compile time constant), the string splicing with reference can be determined at compile time

    public static void main(String[] args) {
       final String string = "hello, ";
        String str3 = new String(string + "world"); // string is the final type, and the compile time value is determined, which is equivalent to the splicing of "Hello," + "world"
        System.out.println(str3.intern() == str3); // Return false
    }
    

3. Magic string java

  • According to the learning of the intern() method, the following code returns the expected results: false in JDK 1.6 and true in JDK 1.8
    • In JDK 1.8, str1.intern() should copy the address pointed to by str1 to the string constant pool, and then return the address in the pool and assign it to str2
    • In this case, str1 and str2 should actually point to the same address in the Java heap
public static void main(String[] args) {
    String str1 = new String("ja") + "va";
    String str2 = str1.intern();
    System.out.println("str1 == str2: " + (str1 == str2));  // In JDK 1.8, false is actually returned
}
  • But the actual running result returned false
  • In depth understanding of Java virtual machine (Second Edition) didn't say why, which made me confused at that time
  • Later, I learned from the blog that the static string constant with java content was defined in the sun.misc.Version class
  • When the JVM starts, it will load some necessary classes, including the sun.misc.Version class, and then the java string will be put into the string constant pool
  • Therefore, when str1.intern() is executed, the string address that already exists in the pool will be returned instead of copying the string address in the Java heap
  • Thanks for the blog: Detailed explanation of string method intern()

Reference link of String class intern() method:

Tags: Java

Posted on Sun, 05 Dec 2021 09:06:18 -0500 by Xurion