This article has been included in Github 110K + like Java knowledge summary class open source project JavaGuide, [Java learning + interview guide] a cover of most Java programmers need to master the core knowledge.

preface

I saw an interview question shared by my friends. Be sure to share it.

This interview question is very common in both the interview and the written test, it is very important to understand the principle!

The descriptions of the players are as follows:

However, this is a problem we don’t encounter in daily development.

The equals() method is used to compare String values. The equals method in String is overridden. The equals method of Object compares the memory addresses of objects, while the equals method of String compares whether the values of strings are equal.

However, this interview question will cover a lot of Java basics and JVM knowledge. It is very necessary to understand!

Problem solving & Principle analysis

I have improved the problem by first looking at the concatenation of strings without the final keyword. The completed code looks like this (JDK1.8) :

String str1 = "str";
String str2 = "ing";

String str3 = "str" + "ing";// Objects in the constant pool
String str4 = str1 + str2; // Create a new object on the heap
String str5 = "string";// Objects in the constant pool
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
Copy the code

For basic data types, == compares values. For reference data types, == compares the memory address of the object.

For strings whose value can be determined at compile time, that is, constant strings, the JVM stores them into the string constant pool.

The String constant pool is an area that the JVM has created for strings (the String class) to improve performance and reduce memory consumption. The main purpose is to avoid repeated String creation.

String aa = "ab"; // Put it in the constant pool
String bb = "ab"; // Search from the constant pool
System.out.println("aa==bb");// true
Copy the code

Runtime constant pool logic prior to JDK1.7 contains string constant pools stored in the method area. In JDK1.7, the string constant pool was taken from the method area to the heap.

In addition, string constants from string constant concatenation are already stored in the string constant pool at compile time, thanks to compiler optimization.

During compilation, the Javac compiler (hereafter referred to collectively as the compiler) performs a code optimization called Constant Folding. Understanding the Java Virtual Machine in Depth also introduces:

Constant folding takes the value of a constant expression and inserts it as a constant in the resulting code, which is one of the few optimizations that the Javac compiler does to source code (code optimizations are almost always done in the just-in-time compiler).

For String str3 = “STR” + “ing”; The compiler will give you String str3 = “String “; .

Not all constants are collapsed, only constants whose values are determined by the compiler at compile time:

  1. Basic data types (byte, Boolean, short, char, int, float, long, double) and string constants
  2. finalModified base data types and string variables
  3. String string concatenated by “+”, arithmetic operations between basic data types (addition, subtraction, multiplication and division), bit operations between basic data types (<<, >>, >>>)

Therefore, str1, str2, and str3 are all objects in the string constant pool.

The referenced value is indeterminable at compile time and cannot be optimized by the compiler.

Object references and String concatenation of “+” are actually implemented by calling append() on StringBuilder, and toString() on completion to get a String object.

String str4 = new StringBuilder().append(str1).append(str2).toString();
Copy the code

Therefore, STR4 is not an existing object in the string constant pool, but a new object on the heap.

I drew a picture to help me understand:

When we write code, we try to avoid concatenating multiple string objects, because this recreates the object. If you need to change strings, you can use StringBuilder or StringBuffer.

However, strings declared with the final keyword can be treated as constants by the compiler.

final String str1 = "str";
final String str2 = "ing";
// The following two expressions are equivalent
String c = "str" + "str2";// Objects in the constant pool
String d = str1 + str2; // Objects in the constant pool
System.out.println(c == d);// true
Copy the code

A String modified by the final keyword is treated as a constant by the compiler, which determines its value at compile time. The effect is to access the constant.

If the compiler knows its exact value at run time, it cannot optimize it.

The sample code looks like this (str2 can only be determined at run time) :

final String str1 = "str";
final String str2 = getStr();
String c = "str" + "str2";// Objects in the constant pool
String d = str1 + str2; // Objects in the constant pool
System.out.println(c == d);// false
public static String getStr(a) {
      return "ing";
}
Copy the code

Let’s look at a similar problem!

String str1 = "abcd";
String str2 = new String("abcd");
String str3 = new String("abcd");
System.out.println(str1==str2);
System.out.println(str2==str3);
Copy the code

What does the above code output when run?

The answer is:

false
false
Copy the code

Why is that?

Let’s look at the following way to create a string object:

// Get the object from the string constant pool
String str1 = "abcd";
Copy the code

In this case, the JVM checks for “abcd” in the string constant pool. If not, it creates one, and str1 points to an object in the string constant pool. If it does, str1 points to “abcd”.

Therefore, str1 points to objects in the string constant pool.

Let’s look at the following way to create a string object:

Create a new object directly in the heap memory space.
String str2 = new String("abcd");
String str3 = new String("abcd");
Copy the code

Whenever you create an object using new, you need to create a new object.

Creating objects using new can be summarized in three steps:

  1. Creates a string object in the heap
  2. Check if there are any string constants in the string constant pool that are equal to the string value of new
  3. If not, create a string constant of equal value in the string constant pool. If so, return the address of the string instance object in the heap.

Thus, both STR2 and STR3 are newly created objects in the heap.

String constant pools are special and can be used in two main ways:

  1. It’s in double quotation marksStringObjects are stored directly in the constant pool.
  2. If it’s not in double quotation marksStringObject, usingStringTo provide theintern()The method has the same effect.String.intern()Is a Native method that returns a reference to a String in the constant pool if the runtime constant pool already contains a String equal to the content of the String. If not, JDK1.7 (not including 1.7) processing is created in constant pool with thisStringIn JDK1.7 and later, the string constant pool is taken from the method area to the heap. Instead of creating the object in the constant pool, the JVM puts the reference to the object in the heap directly into the constant pool, reducing unnecessary memory overhead.

Example code is as follows (JDK 1.8) :

String s1 = "Javatpoint";  
String s2 = s1.intern();  
String s3 = new String("Javatpoint");  
String s4 = s3.intern();          
System.out.println(s1==s2); // True  
System.out.println(s1==s3); // False  
System.out.println(s1==s4); // True       
System.out.println(s2==s3); // False  
System.out.println(s2==s4); // True        
System.out.println(s3==s4); // False 
Copy the code

Recommended reading

  • R (RednaxelaFX) on constant folding of answer: www.zhihu.com/question/55…
  • In Depth understanding the Java Virtual Machine. Chapter 10 program compilation and Code optimization

conclusion

  1. For basic data types, == compares values. For reference data types, == compares the memory address of the object.
  2. During compilation, the Javac compiler (hereafter referred to collectively as the compiler) performs a code optimization called Constant Folding. Constant folding takes the value of a constant expression and inserts it as a constant in the resulting code, which is one of the few optimizations that the Javac compiler does to source code (code optimizations are almost always done in the just-in-time compiler).
  3. In general, we try to avoid creating strings by new. Declared in double quotation marksStringObject (String s1 = "java"It gives the compiler a chance to optimize our code and makes it easier to read.
  4. befinalAfter the keyword modificationStringIt is treated as a constant by the compiler, and its value can be determined at compile time by the compiler program. The effect is to access the constant.