[Java] String storage and memory address issues in JVM

overview

The memory address of String is a point that is often asked in Java interviews. For example, what is the difference between a directly copied String and a new String? How does the address change during string concatenation? etc.
To sort out these address issues, we should first know how String is stored in the JVM.

1. Storage of String objects in JVM

First give the definition: strings are stored in the constant pool (Constant Pool)
in the method area . What is the constant pool? The constant pool is generated during compilation and is used to store various literals and symbol references generated by the compiler. For example, int a = 8; String a = "abc"; 8 and "abc" will be put into the constant pool during the compilation phase. Of course, the constant pool can also be expanded during runtime to put new constants into the pool. The most commonly used method is the intern() method of String, which will be described in detail later.

Let’s look at this simple code again

	String str = "aa";
	String str1 = "aa";
	String str2 = new String("aa");
	String str3 = new String("aa");
	System.out.println(str == str1);//true
	System.out.println(str2 == str3);//false
	System.out.println(str == str2);//false

Why is this the result?
According to the execution order of the program, first, "aa" as a literal, that is, a constant, will be added to the constant pool during compilation, and then the JVM assigns its address in the constant pool to str ; when it comes to str1, the JVM first Check whether there is a constant "aa" in the constant pool. Since "aa" has been created in the constant pool when assigning a value to str, the JVM directly returns this address to str1. Therefore, the addresses of str and str1 are the same, and the result is true.

Coming to str2 and str3, these two are Strings produced by new and are objects. Where are the objects stored? Stored in the heap, so essentially str2 and str3 store the addresses of these two objects in the heap . new twice, they are different objects, so the addresses of str2 and str3 are not the same, and false is returned.

Now look at the last output, str == str2? One of them stores the address in the constant pool, and the other stores the address in the heap. How can they be equal? ​​They return false.

2. About string splicing

Let’s look at this piece of code

	String a = "Hello2";
	String b = "Hello";
	final String c = "Hello";
	
	String d = b + "2";
	String e = c + "2";
	String f = "Hello" + "2";
	
	System.out.println(a==d);//false
	System.out.println(a==e);//true
	System.out.println(a==f);//true

First of all, a, b, and c are all literal assignments, so now there are two strings "Hello2" and "Hello" in the constant pool. Based on the above results we can draw the following two conclusions:

(1) When adding strings, the result of static string addition will be added to the constant pool . If there is this result in the constant pool, its reference will be returned directly; if not, the string will be created and the reference will be returned. Because the constant pool now already has "Hello2", the values ​​of e and f are actually references to "Hello2" in the constant pool, and a, e, and f are all equal.

(2) When adding strings, if they contain variables, such as b in d, they will not enter the constant pool . In DeBug in IDEA, we force the statement String d = b + "2"; and you will find that the bottom layer of the program actually creates a StringBuffer first, and then calls the append() method to add b and "2" to the StringBuffer. Then call toString() to return the spliced ​​string, and the final toString() source code looks like this:

@Override
public String toString() {
    
    
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

see it! It returns a new String ! Of course, the address of this String will not be the same as any existing object.
Regarding string splicing, just distinguish between these two situations.

3. About the intern() method

As we mentioned before, the String from new is not directly stored in the constant pool, and the function of the intern() method is to add the string to the constant pool, and then return the address of the string in the constant pool.

String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = str1 + str2;
String str5 = new String("ab");
 
System.out.println(str5 == str3);//false
System.out.println(str5.intern() == str3);//true
System.out.println(str5.intern() == str4);//false
System.out.println(str5.intern() == str4.intern());//true

When calling str5.intern(), the JVM queries the constant pool to see if there is the string "ab". Because it has been created when str3 is assigned a value, its address is returned directly. str4 is obtained by adding two variables, so it is equivalent to coming from new.

Another point that needs attention is: if you just call str5.intern(), str5 itself will not change, it will still be the address in the heap. If you want str5 to store the address in the constant pool, you need to change str5.intern() The return value is then assigned to str5. You can do the following tests:

String str3 = "ab";
String str5 = new String("ab");
str5.intern();
System.out.println(str5 == str3);//false
str5 = str5.intern();
System.out.println(str5 == str3);//true

Guess you like

Origin blog.csdn.net/weixin_43390123/article/details/124376835