Don’t know if you have such experience, is not neutral in a industry face, and then browse to it for a long time, I am such, inadvertently today, CTRL + click, point source into a string, just do not have what matter, this afternoon is inside see, unexpectedly, slow to come next time, is my colleague took me to let me to have a meal, Ha ha ha, but the advantage is, I also sort out some string class knowledge, also share with you, sort out the bad also hope to forgive
This article first personal public account: Java Architect Federation, updated daily technical good articles
First, the String class
The best way to learn about a class is to look at its implementation source code. Look at the source code for the String class:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** The offset is the first index of the storage that is used. */ private final int offset; /** The count is the number of characters in the String. */ private final int count; /** Cache the hash code for the string */ private int hash; /** Use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; . }Copy the code
A few points can be seen from the above:
1) The String class is final, which means that the String class cannot be inherited and its member methods are all final by default. In Java, classes decorated with final are not allowed to be inherited, and all member methods in that class default to final methods.
The String class uses an array of char attributes to hold a String.
Let’s look at some of the String method implementations:
public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > count) { throw new StringIndexOutOfBoundsException(endIndex); } if (beginIndex > endIndex) { throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value); } public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } char buf[] = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); return new String(0, count + otherLen, buf); } public String replace(char oldChar, char newChar) { if (oldChar ! = newChar) { int len = count; int i = -1; char[] val = value; /* avoid getfield opcode */ int off = offset; /* avoid getfield opcode */ while (++i < len) { if (val[off + i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0 ; j < i ; j++) { buf[j] = val[off+j]; } while (i < len) { char c = val[off + i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(0, len, buf); } } return this; }Copy the code
As you can see from the above three methods, neither the sub operation, concat operation, nor replace operation is performed on the original string, but instead regenerates a new string object. That is, the original string is not changed.
One thing to always remember here is that “strings are immutable once created. Any changes to the String do not affect the original object, and any associated change operations generate new objects.”
String constant pool
We know that string allocation, like any other object allocation, is expensive in time and space, and we use a lot of strings. To improve performance and reduce memory overhead, the JVM makes some optimizations when instantiating strings: it uses a pool of string constants. Whenever we create a string constant, the JVM first checks the string constant pool and returns a reference to the instance in the constant pool if the string already exists there. If the string does not exist in the constant pool, it is instantiated and placed in the constant pool. Because of the immutability of String strings, we can be pretty sure that there can never be two identical strings in the constant pool (this is crucial to understand).
Constant pools in Java actually come in two forms: static constant pools and runtime constant pools. The static constant pool is the constant pool in *. Class files. The constant pool in class files contains not only string (number) literals, but also class and method information, which occupies most of the space of the class file. The JVM loads the constant pool from the class file into memory and stores it in the method area after class loading.
Take a look at the following program:
String a = "chenssy";
String b = "chenssy";
Copy the code
A, B, and literally Chenssy all refer to the “Chenssy” object in the JVM’s string constant pool, and they all refer to the same object.
String c = new String("chenssy");
Copy the code
The new keyword must generate an object chenssy (note that this chenssy is different from the chenssy one above) and that object is stored in the heap. So there should be two objects: C on the stack and Chenssy on the heap. But there is no such thing as two identical string objects in Java. Therefore, chenSSY in the heap should refer to Chenssy in the string constant pool. So C –>chenssy– > Pool chenssy. The whole relationship is as follows:
From the picture above, we can clearly understand the relationship between them. So when we change the value in memory, it changes everything.
** A, B, C, and CHENssy are different objects, but we can understand them from the internal structure of String. String c = new String(“chenssy”); Even though c’s content is created in the heap, its internal value still refers to chenssy’s value in the JVM constant pool, and it still constructs ChenSSY with the ChenSSY string constant.
Here are a few more examples:
Example 1:
Public void test1(){String str1="aaa"; String str2="aaa"; System.out.println("===========test1============"); System.out.println(str1==str2); Str1 and str2 refer to the same object}Copy the code
Execute the above code and the result is: true. Analysis: When String str1=”aaa” is executed, the JVM first looks for the presence of “aaa” in the String pool. If not, it creates an object in the String pool and returns the reference address of the object to the String constant str1. So str1 will point to the string object “aaa” in the pool; If so, no object is created and the address of the object “aaa” in the pool is returned and assigned to the string constant. When str2 is created, the string object “aaa” already exists in the string pool, and the reference address of the object “AAA” is directly returned to STR2, so that STR2 refers to the object “AAA” in the pool, which means that str1 and STR2 refer to the same object. So the statement system.out. println(str1 == str2) prints: true.
Example 2:
Public void test2(){String str3=new String("aaa"); String str4=new String("aaa"); System.out.println("===========test2============"); System.out.println(str3==str4); // create a new object.Copy the code
Execute the above code and the result is: false.
Analysis: When a new string object is created using the new keyword, the JVM first looks for “aaa” in the string pool. If it does, it creates “AAA” in the heap instead of in the pool. We then return the address of the “AAA” object in the heap to str3, so that STR3 points to the “AAA” string object created in the heap; If not, a” AAA “string object is first created in the string pool, then a” AAA” string object is created in the heap, and then the address return of the “AAA” string object in the heap is assigned to the STR3 reference, so that STR3 refers to the “AAA” string object created in the heap. When you execute String str4=new String(“aaa”), because you use the new keyword to create an object, each new object is a new object, i.e., str3 and str4 refer to two different objects, So system.out. println(str3 == str4) prints: false.
Example 3:
Public void test3(){String s0=" helloWorld "; String s1="helloworld"; String s2="hello"+"world"; System.out.println("===========test3============"); System.out.println(s0==s1); System.out.println(s0==s2); // s0 is the same object as s2.Copy the code
Execute the above code, and the result is true, true.
Analysis: Because the “helloworld “in s0 and s1 are string constants that are determined at compile time, s0s1 is true; “Hello” and “world “are also string constants. When a string is concatenated from multiple string constants, it must be a string constant itself, so S2 is also parsed as a string constant at compile time, so s2 is also a reference to” HelloWorld “in the constant pool. So we get s0s1 is equal to s2.
Example 4:
Public void test4(){String s0=" helloWorld "; String s1=new String("helloworld"); String s2="hello" + new String("world"); System.out.println("===========test4============"); System.out.println( s0==s1 ); //false System.out.println( s0==s2 ); //false System.out.println( s1==s2 ); //false }Copy the code
Execute the above code and the result is: false, false, false.
Strings created with new String() are not constants and cannot be determined at compile time. Therefore, strings created with new String() are not put into the constant pool. They have their own address space.
S0 is also a reference to “helloWorld” in the constant pool, s1 is a reference to a new object created at runtime “helloWorld” because it cannot be determined at compile time, s2 is also a reference to a new object created at runtime “helloWorld” because it has the second part of new String(” world “). So it’s also a reference to the newly created object “HelloWorld”.
Example 5:
Public void test5(){String str1=" ABC "; String str2="def"; String str3=str1+str2; System.out.println("===========test5============"); System.out.println(str3=="abcdef"); //false }Copy the code
Execute the above code and the result is: false.
Analysis: Because str3 refers to the “abcdef” object in the heap, and “abcdef” is an object in the string pool, the result is false. The JVM puts String STR =” ABC “in the constant pool at compile time, whereas String str3=str1+str2 is known at run time. New objects are also made at run time. This code creates a total of five objects, two in the string pool and three in the heap. The + operator creates two strings in the heap with the values “ABC” and “def”, that is, copies these two values from the String pool, creates two objects in the heap, then creates str3, and assigns the heap address of “abcdef” to STR3.
Step: 1) Create an intermediate block in the stack to store the reference str1, which refers to the String constant “ABC” in the pool. 2) Create an intermediate block in the stack to store the reference str2, which refers to the String constant “def” in the pool. 3) Create an intermediate block in the stack to store reference STR3. 4) Str1 + str2 restores a new String object “abcdef” via toString(), the last step in StringBuilder, thus creating a space in the heap for this object. 5) Reference str3 to the new String restored in the heap (str1 + str2). 6) Str3 points to an object in the heap, while the constant “abcdef” is in the pool, and the output is false.
Example 6:
Public void test6(){String s0 = "a1"; String s1 = "a" + 1; System.out.println("===========test6============"); System.out.println((s0 == s1)); //result = true String s2 = "atrue"; String s3= "a" + "true"; System.out.println((s2 == s3)); //result = true String s4 = "a3.4"; String s5 = "a" + 3.4; System.out.println((s4 == s5)); //result = true }Copy the code
Execute the above code, and the result is true, true, true.
Analysis: At compile time, the JVM optimizes the “+” concatenation of the constant string to the concatenated value. In the case of “A “+ 1, the compiler optimizes the class to be A1. The value of the string constant is determined at compile time, so the above program ends up with true.
Public void test7(){String s0 = "ab"; String s1 = "b"; String s2 = "a" + s1; System.out.println("===========test7============"); System.out.println((s0 == s2)); //result = false }Copy the code
Execute the above code and the result is: false.
Analysis: JVM for string references, because there are string references in the string “+” connection, and the value of the reference is not determined at the program compile time, that is, “A “+ S1 cannot be optimized by the compiler, only during the program run time to dynamically allocate and assign the new address after the connection to S2. So the result of the above program is false.
Example 8:
/ * * * is the "+" String constants and a reference to a String of the difference between "+" * / public void test8 () {String test = "javalanguagespecification"; String str="java"; String str1="language"; String str2="specification"; System.out.println("===========test8============"); System.out.println(test == "java" + "language" + "specification"); System.out.println(test == str + str1 + str2); }Copy the code
Execute the above code, the result is true, false.
Analysis: Why the above results? This is because string literal concatenation is performed at compile time by the Java compiler, which means that when the compiler compiles, The “Java”, directly to the “language” and “specification” of the three literal for “+” operation to get a “javalanguagespecification” constants, and directly put the constants in a string in the pool, do, in fact, a kind of optimization, Combining three literals into one avoids creating redundant string objects. The string reference “+” operation is performed during Java runtime, i.e., STR + STR2 + STR3 is evaluated during program execution, recreating a concatenated string object in heap memory. To summarize: literal “+” concatenation is done at compile time, and the concatenated string is stored in the string pool; The “+” concatenation of string references takes place at runtime, and the newly created string is stored in the heap.
Adding strings directly is efficient because the compiler determines its value, i.e., “I”+”love”+” Java “; Is optimized to “Ilovejava” at compile time. For indirect addition (that is, including string references), s1+s2+s3; This is less efficient than direct addition because reference variables are not optimized at the compiler.
Example 9:
Public void test9(){String s0 = "ab"; final String s1 = "b"; String s2 = "a" + s1; System.out.println("===========test9============"); System.out.println((s0 == s2)); //result = true }Copy the code
Execute the above code and the result is: true.
Analysis: The only difference from example 7 is that the s1 string is modified with final. For a final modified variable, it is resolved at compile time to a local copy of the constant value stored in its own constant pool or embedded in its bytecode stream. So “A” + s1 is the same thing as “A” + “b”. So the result of the above program is true.
Example 10:
Public void test10(){String s0 = "ab"; final String s1 = getS1(); String s2 = "a" + s1; System.out.println("===========test10============"); System.out.println((s0 == s2)); //result = false } private static String getS1() { return "b"; }Copy the code
Execute the above code and the result is: false.
S0 and s2 are not the same object, so the result of the above program is false. S0 and s2 are not the same object.
Third, summary
1. The String class is immutable when initialized.
Strings use private final char value[] to store strings, which means that you cannot modify the contents of a String after it is created. For this reason, strings are said to be immutable. Programmers cannot modify existing immutable objects. We can create immutable objects ourselves, as long as we don’t provide methods to modify the data in the interface. However, String objects do have the ability to edit strings, such as replace(). These editing functions are implemented by creating a new object rather than making changes to an existing object. Such as:
s = s.replace("World", "Universe");
Copy the code
The above call to s.replace() creates a new string “Hello Universe!” And returns a reference to the object. By assigning, the reference S points to the new string. If there are no other references to the original string “Hello World!” , the original string object will be garbage collected.
2. Reference variables and objects
A aa; This statement declares A reference variable aa of class A (we often call it A handle), and objects are typically created by new. So aa is just a reference variable, it’s not an object.
3. How to create a string
There are two ways to create strings:
(1) Create a string using “” quotes;
(2) Create a string using the new keyword.
Combined with the above examples, the summary is as follows:
(1) Strings created using “” quotes alone are constants that are stored in the String Pool at compile time;
(2) Objects created using new String(“”) are stored in the heap and are newly created at runtime;
When new creates a string, it checks to see if there are any strings with the same value in the pool. If so, it copies a string to the heap and returns the address in the heap. If not, create a copy in the heap and return the address in the heap (note that you do not need to copy from the heap to the pool at this point, otherwise, the string in the heap will always be a subset of the pool, resulting in wasted pool space)!
“Aa” + “aa” = “aa” = “aa” = “aa” = “aa” = “aa” = “aa”
(4) Objects created using string concatenators such as “aa” + s1 that contain variables are created at runtime and stored in the heap;
4. Using String does not necessarily create an object
When executing a statement containing a String in double quotes, such as String a = “123”, the JVM looks in the constant pool first, returns a reference to the instance in the constant pool if there is one, and creates a new instance and places it in the constant pool otherwise. So, when we use things like String STR = “ABC”; When defining an object in the format of String, it is always assumed that an object STR of class String has been created. ** worry about traps! The object may not have been created! It might just point to a previously created object. ** Only the new() method ensures that a new object is created each time.
5. Use new String to create an object
String a = new String(“123”); String a = new String(“123”); String a = new String(“123”);
public String(String original) { int size = original.count; char[] originalValue = original.value; char[] v; if (originalValue.length > size) { // The array representing the String is bigger than the new // String itself. Perhaps this constructor is being called // in order to trim the baggage, so make a copy of the array. int off = original.offset; v = Arrays.copyOfRange(originalValue, off, off+size); } else { // The array representing the String is the same // size as the String, so no point in making a copy. v = originalValue; } this.offset = 0; this.count = size; this.value = v; }Copy the code
We created an instance of String, but the value is equal to the value of the instance in the constant pool, i.e., there is no new String array to hold 123.
6. About String. Intern ()
The **intern method uses: ** An initially empty String pool maintained by the class String alone. When the intern method is called, if the pool already contains a String (determined by equals(oject)) equal to this String object, the String from the pool is returned. Otherwise, the String is added to the pool and a reference to the String is returned.
It follows the following rule: for any two strings s and t, s.intern() == T.intern () because true if and only if s.quals (t) is true.
String.intern(); One more note: constant pools that exist in.class files are loaded by the JVM at run time and can be extended. The String intern() method is one way to expand the constant pool; When a String instance STR calls intern(), Java looks for String constants of the same Unicode in the constant pool and returns a reference to them if there is one; if not, it adds a String of Unicode equal to STR to the constant pool and returns its reference.
/** * about string.intern () */ public void test11(){String s0 = "kvill"; String s1 = new String("kvill"); String s2 = new String("kvill"); System.out.println("===========test11============"); System.out.println( s0 == s1 ); //false System.out.println( "**********" ); s1.intern(); S1.intern (); s2 = s2.intern(); s2 = s2.intern(); // assign a reference to s2 system.out.println (s0 == s1) from the constant pool to s2 system.out.println (s0 == s1); //flase System.out.println( s0 == s1.intern() ); S1.intern () returns a reference to "kvill" in the constant pool system.out.println (s0 == s2); //true }Copy the code
Results: false, false, true, true.
7. About equals and ==
(1) for the = =, if applied to basic data types of variables (byte, short, char, int, long, float, double, Boolean), is to directly compare the stored “values” are equal; If applied to a variable of a reference type (String), it compares the address of the object to which it points (that is, whether it points to the same object).
(2) Equals is a method of the base class Object, so it is available to all classes that inherit from Object. In the Object class, the equals method is used to compare whether references to two objects are equal, that is, whether they refer to the same Object.
(3) For equals, note that equals does not apply to variables of primitive data types. If the equals method is not overridden, it compares the addresses of the objects to which the variables referring to the type refer; The String class overrides the equals method, which compares whether the strings stored in the pointed String objects are equal. Other classes, such as Double, Date, and Integer, override equals to compare the contents of the objects they point to.
Public void test12(){String s1="hello"; String s2="hello"; String s3=new String("hello"); System.out.println("===========test12============"); System.out.println( s1 == s2); Flase: s1 and s3 refer to different objects in the constant pool. S1 refers to different objects in the constant pool. Flase: s1 refers to different objects in the constant pool. System.out.println(s1 == s3); System.out.println( s1.equals(s3)); //true, s1 and s3 refer to the same object}Copy the code
8.String related + :
The + in String is often used to concatenate strings. Here’s a simple example:
/** * String related + */ public void test13(){String a = "aa"; String b = "bb"; String c = "xx" + "yy " + a + "zz" + "mm" + b; System.out.println("===========test13============"); System.out.println(c); }Copy the code
After compiling and running, the main bytecode parts are as follows:
public static main([Ljava/lang/String; )V L0 LINENUMBER 5 L0 LDC "aa" ASTORE 1 L1 LINENUMBER 6 L1 LDC "bb" ASTORE 2 L2 LINENUMBER 7 L2 NEW java/lang/StringBuilder DUP LDC "xxyy " INVOKESPECIAL java/lang/StringBuilder.<init> (Ljava/lang/String; )V ALOAD 1 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; LDC "zz" INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; LDC "mm" INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; ALOAD 2 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; ASTORE 3 L3 LINENUMBER 8 L3 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ALOAD 3 INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String; )V L4 LINENUMBER 9 L4 RETURN L5 LOCALVARIABLE args [Ljava/lang/String; L0 L5 0 LOCALVARIABLE a Ljava/lang/String; L1 L5 1 LOCALVARIABLE b Ljava/lang/String; L2 L5 2 LOCALVARIABLE c Ljava/lang/String; L3 L5 3 MAXSTACK = 3 MAXLOCALS = 4 }Copy the code
Obviously, bytecode can lead to the following conclusions: (1) when + String concatenation is used for String concatenation in.string, if all String constants are used at the beginning of the concatenation operation, as many String constants will be directly concatenated after compilation, forming new String constants to participate in the subsequent concatenation (it can also be easily seen through the decompression tool JD-GUI);
(2). The strings are concatenated from left to right. For different strings, first create a StringBuilder object with the leftmost string as an argument, then append the right one. Finally, the StringBuilder object is converted to a String using the toString() method (note: multiple String constants in the middle are not automatically concatenated).
String c = “xx” + “yy “+ a + “zz” + “mm” + b; String c = new StringBuilder(“xxyy “).appEnd (a).append(“zz”).appEnd (“mm”).appEnd (b).toString();
Conclusion: When you concatenate multiple strings with +, you’re actually producing a StringBuilder object and a String object.
9. The immutability of String causes the + sign to be used in String variables:
String s = "a" + "b" + "c";
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = s1 + s2 + s3;
Copy the code
String s = “ABC “; As you can see from the above example, the compiler is optimized to create only one object. We can also see from the above example that S4 cannot be optimized at compile time and object creation is equivalent to:
StringBuilder temp = new StringBuilder();
temp.append(a).append(b).append(c);
String s = temp.toString();
Copy the code
String (+) = String (+) = String (+) = String (+) = String (+))
public class Test { public static void main(String args[]) { String s = null; for(int i = 0; i < 100; i++) { s += "a"; }}}Copy the code
Every time we do + we create a StringBuilder object, and then we throw it away after append. The next time the loop arrives it regenerates a StringBuilder object, then appEnd string, and so on until the loop ends. If we append the StringBuilder object directly, we can save n-1 object creation and destruction time. So for applications where strings are concatenated in a loop, a StringBuffer or StringBulider object is used for append operations.
10. The difference between String, StringBuffer, StringBuilder
(1) Mutable vs. immutable: String is an immutable String object, StringBuilder and StringBuffer are mutable String objects (their internal character arrays are of variable length).
(2) Whether multi-thread safety: the object in String is immutable, which can be understood as a constant, obviously thread safety. StringBuffer and StringBuilder are identical except that most methods in StringBuffer are thread-safe and are modified with the synchronized keyword, which StringBuilder does not. Can be considered non-thread-safe.
StringBuilder > StringBuffer > String StringBuilder > StringBuffer > String For example String STR = “hello”+ “world” is more efficient than StringBuilder st = new StringBuilder().append(“hello”).append(“world”) Therefore, each of these classes has its own advantages and disadvantages, and should be used according to different circumstances. For String addition operations or small changes, String STR =”hello” is recommended. StringBuilder is recommended when adding strings frequently, and StringBuffer is recommended when using multiple threads.
11. Use and understanding of final in String
final StringBuffer a = new StringBuffer("111"); final StringBuffer b = new StringBuffer("222"); a=b; Final StringBuffer a = new StringBuffer("111"); a.append("222"); // The compiler passesCopy the code
As you can see, **final only applies to the “value “(that is, the memory address) of the reference. This forces the reference to point only to the object it originally pointed to, and changing its pointing can cause compile-time errors. ** Final is not responsible for changes to the object it points to.
12. How many objects did String STR = new String(” ABC “) create?
This problem is said in many books, such as “Java programmer interview treasure book”, including many domestic big companies will encounter written interview questions, most of the online circulation and some interview books are said to be two objects, this statement is one-sided.
First you have to figure out what it means to create an object. When was the creation created? Does this code create 2 objects at run time? Of course not, decompilation with Javap-c yields the bytecode content executed by the JVM:
Obviously, new is called only once, that is, only one object is created. And here’s where it gets confusing, because this code actually only creates one object at run time, which is an “ABC” object on the heap. Why is everyone talking about two objects? There’s a difference between executing code and loading a class. It is true that an “ABC” object is created in the runtime constant pool during class loading, and only a String object is created during code execution. So, the question is if you change it to String STR = new String(” ABC “) how many strings are involved? The logical explanation is two. Personally, if you encounter this question during the interview, you can ask the interviewer whether “how many objects are created or how many objects are involved in the execution of this code” and then answer it according to the specific.
13. Advantages and disadvantages of string pool: The advantage of string pool is that it avoids creating strings with the same content, saves memory, saves the time of creating the same string, and improves performance; String pooling, on the other hand, has the disadvantage of sacrificing the time that the JVM needs to traverse objects in the constant pool, but the time cost is relatively low.
4. Comprehensive examples
package com.spring.test; Public class StringTest {public static void main(String[] args) {/** * String pools * The JAVA Virtual Machine (JVM) has a String pool that holds many strings; * And can be shared, so it improves efficiency. * Since the String class is final, its value is immutable once created. The String pool is maintained by the String class, and we can call intern() to access the String pool. */ String s1 = "abc"; // create an object in the String pool String s2 = "ABC "; System.out.println("s1 ==s2: "+(s1==s2)); system.out. println("s1 ==s2: "+(s1==s2)); System.out.println("s1.equals(s2) : "+ (s1.equals(s2))); / / / / write write true values are equal -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- over / * * * scene 2: New String("") * */ String s3 = new String(" ABC "); // create two objects, one in the string pool and one in the heap; String s4 = new String(" ABC "); System.out.println("s3 ==s4: "+(s3==s4)); // the stack addresses of s3 and S4 are different, pointing to different addresses of the heap. System.out.println("s3.equals(s4) : "+(s3.equals(s4))); System.out.println("s1 ==s3: "+(s1==s3)); System.out.println("s1.equals(s3) : "+(s1.equals(s3))); / / write true value/same/write -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- over/scene 3: * * * * due to the constant values were determined at compile time (optimization). * Here, "ab" and "CD" are constants, so the value of the variable str3 can be determined at compile time. String str3 = "abcd"; String str3 = "abcd"; */ String str1 = "ab" + "cd"; //1 object String str11 = "abcd"; System.out.println("str1 = str11 : "+ (str1 == str11)); / / write -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- over / * * * scenario 4: * Local variable str2,str3 stores the addresses of two internals (intern string objects). Str2 +str3: * The JVM first creates a StringBuilder class in the heap, initializes it with the detention string object pointed to by STR2, and then calls the Append method to merge the detention strings pointed to by STR3. * It then calls toString() of StringBuilder to create a String in the heap, and finally stores the heap address of the newly generated String in the local variable STR3. * * Str5 stores the address of the detention string object corresponding to "abcd" in the string pool. * Str4 and STR5 address is of course different. * * There are actually five String objects in memory: * Three detention String objects, a String object, and a StringBuilder object. */ String str2 = "ab"; //1 object String str3 = "CD "; //1 object String str4 = str2+str3; String str5 = "abcd"; System.out.println("str4 = str5 : " + (str4==str5)); / / false / / write -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- over / * * * scene 5: * The JAVA compiler optimizes string + primitive/constant as a constant expression directly evaluated. */ string str6 = "b"; string str6 = "b"; String str7 = "a" + str6; String str67 = "ab"; System.out.println("str7 = str67 : "+ (str7 == str67)); //↑str6 is a variable that will be parsed at run time. final String str8 = "b"; String str9 = "a" + str8; String str89 = "ab"; System.out.println("str9 = str89 : "+ (str9 == str89)); / / write str8 as constant variables, compile time will be optimized / / write -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- over}}Copy the code
Running results:
s1 == s2 : true s1.equals(s2) : true s3 == s4 : false s3.equals(s4) : true s1 == s3 : false s1.equals(s3) : true str1 = str11 : true str4 = str5 : false str7 = str67 : false str9 = str89 : true