Here is the code:

public class TestMain { public static void main(String[] args) { String str0 = "123"; String str1 = "123"; System.out.println(str0 == str1); }}Copy the code

What are the results? The answer, of course, is true. Yes, the answer is true, but why? A lot of people’s first reaction is that of course two strings of “123” are equal, but you have to think about that. But “==” in Java compares not the values of two objects, but the references of two objects are equal. What does it matter if both strings are “123”? Or we could change the program

public class TestMain { public static void main(String[] args) { String str2 = new String("234"); String str3 = new String("234"); System.out.println(str2 == str3); }}Copy the code

The result is false because str2 and str3 are two different references, even though both strings are “234”. OK, return true around the first code and false around the second code to begin the article.

Why is String=String?

There is an area in the JVM called the constant pool, where data is identified at compile time and stored in compiled.class files. In addition to containing all eight basic data types (char, byte, short, int, long, float, double, Boolean), there are constant values for strings and their arrays, as well as symbolic references in textual form.

The Java stack is characterized by fast access (compared to heap blocks) but small space and a fixed data life cycle that only lasts until the end of a method. Boolean b = true, char C = ‘c’, String STR = ‘123’

1. True, c, and 123, which refer to things that can be determined at compile time, are maintained in the constant pool

2, b, c, STR the first occurrence on the left of the equals sign refers to a reference to the constant pool address of the data on the right of the equals sign

Boolean, char, String these are the types of references

One feature of stacks is data sharing.

String 1 = “123”; String 1 = “123”; String 1 = “123”; String 1 = “123”; Str1 also refers to “123” in the constant pool, so line 7 str0 == str1 returns true.

Because str0 and str1 both point to the address of the string “123” in the constant pool. Of course, if String str1 = “234”, it will be different, because there is no “234” in the constant pool, so it will create a “234” in the constant pool, and then str1 will represent the address of “234”.

If there is any data to be created in the constant pool, it will return the address of the data. If there is no data to be created, it will create one.

What about the second example? Each time the Java virtual machine interpreter encounters a new keyword, a chunk of heap memory is cleared to hold a String.

Str2 == str3 returns false when str2 == str3 returns false when str2 == str3 returns false when str2 == str3

Why use StringBuilder and StringBuffer to concatenate strings?

There must be a principle in development that says “Use StringBuilder and StringBuffer to concatenate strings”, but why? Here’s a code to analyze it:

public class StringTest { @Test public void testStringPlus() { String str = "111"; str += "222"; str += "333"; System.out.println(str); }}Copy the code

Javap-verbose StringTest or javap -c StringTest can be used to compile the stringtest. class file.

public void testStringPlus(); Code: ldc #17 // String 111 astore_1 new #19 // class java/lang/StringBuilder dup aload_1 invokestatic #21 // Method java/lang/String.valueOf:(Ljava/lang/Object;) L java/lang/String; invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/S tring;) V ldc #30 // String 222 invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/Str ing;) Ljava/lang/StringBuilder; invokevirtual #36 // Method java/lang/StringBuilder.toString:()Ljava/lang/ String; astore_1 new #19 // class java/lang/StringBuilder dup aload_1 invokestatic #21 // Method java/lang/String.valueOf:(Ljava/lang/Object;) L java/lang/String; invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/S tring;) V ldc #40 // String 333 invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/Str ing;) Ljava/lang/StringBuilder; invokevirtual #36 // Method java/lang/StringBuilder.toString:()Ljava/lang/ String; astore_1 getstatic #42 // Field java/lang/System.out:Ljava/io/PrintStream; aload_1 invokevirtual #48 // Method java/io/PrintStream.println:(Ljava/lang/String ;) V return }Copy the code

Each time the compiler hits a “+”, it creates a new StringBuilder, calls append, and toString to generate a new string.

This means that if you have a lot of “+” s in your code, you’ll generate a StringBuilder once per “+”, which is a waste of memory and inefficient.

There is another way to concatenate strings in Java: the concat method of strings. This method is not very good at concatenating strings.

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}
Copy the code

Buf [] creates a new String object from the String array buf[]. This means that the concat method is called N times and N String objects are copied. It’s a waste of time and space.

We need to use StringBuilder and StringBuffer to concatenate strings because the concat method for concatenating strings with “+” is inefficient. Take StringBuilder as an example:

public class TestMain { public static void main(String[] args) { StringBuilder sb = new StringBuilder("111"); sb.append("222"); sb.append("111"); sb.append("111"); sb.append("444"); System.out.println(sb.toString()); }}Copy the code

A StringBuffer, like a StringBuilder, simply maintains a char array at the bottom and adds characters to the char array each time it is appended. When sb.toString() ends, Convert the contents of a char array to a String using a new String() method;

Thus, the entire process produces only one StringBuilder and one String, which is very space-saving. The only performance penalty of StringBuilder is that when the char array is insufficient, it needs to be expanded. Array copying is required for expansion, which reduces efficiency to some extent.

StringBuffer and StringBuilder are used exactly the same way, except that StringBuffer is thread-safe and synchronizes all methods;

StringBuilder is not thread-safe, so use StringBuilder in scenarios that do not involve thread-safety, such as inside methods, to avoid synchronization overhead.

In addition, StringBuffers and StringBuilders also have an optimization point, which states that there is a performance penalty for scaling up, so if you can estimate the length of the strings to be concatenated, use constructors to specify their lengths.

You really can’t concatenate strings with “+”?

Don’t concatenate strings with “+”, as this creates a large number of useless StringBuilder objects, but it’s not a no-no. For example:

public class TestMain { public static void main(String[] args) { String str = "111" + "222" + "333" + "444"; System.out.println(str); }}Copy the code

In this case, the JVM will actually produce only a StringBuilder and a string following the append equal sign at compile time.

Note that “111”, “222”, “333”, and “444” are constants that are known at compile time, because the JVM in line 5 does not generate a StringBuilder at compile time but instead generates the string “111222333444”.

But there are two main reasons for this rarity:

1. The example is simple, but in practice a lot of “+” makes the code very unreadable

2. The content to be concatenated can be fetched from a variety of places, such as calling the interface, from a.properties file, from an.xml file. In such cases, it is not impossible to use multiple “+” methods, but it will make the code less maintainable