String
String is the most commonly used object in JAVA. It is such a most commonly used and common object. When you study deeply, you find that we don't really understand it very well, so let's learn it together!
Because of the immutable nature of String, Java implements a constant pool internally. When a String is created, it will first go to the constant pool to see if there are any examples with the same value, and if so, return it directly. Saves memory and speeds up the loading of strings. Immutable objects are also guaranteed to remain thread-safe in concurrency
characteristic
- String constants, which are actually String objects
- All Strings not created by new are placed in the constant pool
- Objects of type String are immutable
- String implements the CharSequence interface
How to create a String object
String str1 = "abcd";
String str2 = new String("abcd");
These two different creation methods are different. The first way is to get the object in the constant pool, and the second way is to create a new object directly in the heap memory space.
As long as you use the new method, you need to create a new object
Concatenation expression + (plus sign)
- Only new objects created by using "+" concatenation between String objects created by using quotation marks to contain text will be added to the string pool.
- For all "+" connection expressions that contain new objects (including null) in the new method, the new objects generated by it will not be added to the string pool.
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println(str3 == str4);//false
String str5 = "string";
System.out.println(str3 == str5);//true
1、 Sting s; //定义了一个变量s,没有创建对象;
2、 = // 赋值,将某个对象的引用(句柄)赋给s ,没有创建对象;
3、 “abc” //创建一个对象;
4、 new String(); // 创建一个对象。
Common method
length returns the length of the string
isEmpty determines whether the string is empty
charAt gets char according to the index position
getChars copies the char of the corresponding position range into the array
equals, equalsIgnoreCase The comparison order is the reference address, the length of the char array, and the content of the char array.
compareTo compares string sizes
startsWith, endsWith judge the prefix and suffix
hashCode calculates the hash value, the formula is s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
indexOf finds the position of the first occurrence
lastIndexOf finds the last occurrence
substring returns the substring (the old version is to return a new string that references the parent string, saving reallocation of memory. But in fact, if the substring references a parent string that occupies a lot of space, the parent string will not be used because the substring has been used all the time. The method is garbage collected, and the new version of substring re-copy the char array every time)
concat concatenates strings (concatenates char arrays, recreates strings)
replace replaces all old characters with new characters (it will traverse the char array once, look for it when it exists, and then replace it to avoid allocating the char array every time)
matches to determine whether it conforms to the regular pattern (reuse Pattern.matches() method)
contains determines whether a substring is included (reuse indexOf() method)
replaceFirst replaces only once
replaceAll replaces all regular occurrences
split splits the string according to the regular
toLowerCase returns lowercase
toUpperCase returns uppercase
trim remove leading and trailing spaces
toCharArray re-copy the char array to return
join(CharSequence delimiter, CharSequence… elements)
String.join(",", "you", "bao", "luo"); //out: you,bao,luo
equals(Object anObject)
String.equals() code logic:
Determine whether the incoming object and the current object are the same object, and if so, return true directly;
Determine whether the incoming object is a String, if not, return false (if it is null, it does not hold);
Determine whether the incoming String is the same length as the current String, if not, return false;
Cyclically compare the char[] arrays of the two strings, and compare the characters one by one to see if they are consistent. If they are inconsistent, return false directly;
Returns true if no mismatch is found at the end of the loop;
JDK8源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
- intern(): naive method, which directly returns the reference in the constant pool
When the intern() method is called, the JVM will use the equals() method to find out whether there is an equivalent String in the constant pool. If it exists, it will directly return the address of the String object in the constant pool; if it does not exist, it will create an equivalent String. String (that is, the equivalent char[] array string, but char[] is a newly created copy space), and then returns the address of this newly created space;
When looking for an equivalent String in the constant pool, there is usually not only one string but multiple strings, so the efficiency will be relatively low. In addition, in order to ensure uniqueness, a lock is required;
String str1 = "ab";
String str2 = new String("ab");
System.out.println(str1== str2);//false
System.out.println(str2.intern() == str1);//true
System.out.println(str1== str2);//false
str2 = str2.intern();
System.out.println(str1== str2);//true
Knowledge point
- In the place where x.toString() is called, ""+x can be used instead;
- String + concatenation operation
public static void main(String[] args) throws InterruptedException {
String s = "a";
String st = s + "b" + "c";
}
javap out====>
Code:
stack=3, locals=3, args_size=1
0: ldc #19 // String a
2: astore_1
3: new #21 // class java/lang/StringBuilder
6: dup
7: aload_1
8: invokestatic #23 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
11: invokespecial #29 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
14: ldc #32 // String b
16: invokevirtual #34 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #38 // String c
21: invokevirtual #34 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #40 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore_2
28: return
- StringBuffer is a thread safe operation
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
- StringBuilder is not thread safe
public StringBuilder append(String str) {
super.append(str);
return this;
}
System.err.println("hello,world"); ##hello,world实际是String对象
printf formatted output
FAQ
1. String str1 = "abc"; System.out.println(str1 == "abc");
Steps:
a> Create a space in the stack to store the reference str1;
b> Create a space in the String pool to store String constants" abc";
c> refers to str1 to point to the String constant "abc" in the pool;
d> the address pointed to by str1 is the address of the constant "abc", and the output is true;
String str2 = new String("abc"); System.out.println(str2 == "abc");
Steps:
a> Create a space in the stack to store the reference str2;
b> Create a space in the heap to store a new String The object "abc";
c> refers to str2 to point to the newly created String object "abc" in the heap;
d> The address of the object referred to by str2 is the address in the heap, while the address of the constant "abc" is in the pool, and the output is false;
note : For the object generated by new, it will go to the constant pool to check whether there is "abc", if not, first create an "abc" object in the constant pool, and then create a copy of the "abc" object in the constant pool in the heap object;String s2 = new String("Hello"); How many objects are produced?
First of all, during the working process of the jvm, a memory space will be created to store the string object. We call this memory space the string pool;
String s2 = new String("Hello"); JVM first looks in the string pool to see if it can't find the string "Hello", if found, do nothing; otherwise, create a new string object , put it in the string pool. Since new is encountered, a string object is also created on the memory heap (not in the string pool) to store "Hello", and the string object in memory (not in the string pool) is returned to s2.
Re: If there is no "Hello" in the constant pool, create two objects. If "Hello" exists in the original constant pool, it is an object;other
String str1 = "a";
String str2 = "b";
String str3 = str1 + "b";
//str1 和 str2 是字符串常量,所以在编译期就确定了。
//str3 中有个 str1 是引用,所以不会在编译期确定。
//又因为String是 final 类型的,所以在 str1 + "b" 的时候实际上是创建了一个新的对象,在把新对象的引用传给str3
final String str1 = "a";
String str2 = "b";
String str3 = str1 + "b";
//这里和\(3\)的不同就是给 str1 加上了一个final,这样str1就变成了一个常量。
//这样 str3 就可以在编译期中就确定了
compile-time optimization
The compiler will superimpose fixed values for string constants at compile time. String constants include "hello" or variables modified with fianl. The compiler considers these constants to be immutable.
Compiler optimizes String constant concatenation
Example 1
String str = "hello" + "java" + 1;
// 编译期编译器会直接编译为"hellojava1"
#2 = String #21 // hellojava1
#21 = Utf8 hellojava1
Example 2
public static final String A = "ab"; // 常量A
public static final String B = "cd"; // 常量B
public static void main(String[] args) {
String s = A + B; // 将两个常量用+连接对s进行初始化
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
} else {
System.out.println("s不等于t,它们不是同一个对象");
}
}
output ==> s等于t,它们是同一个对象
Explanation: Both A and B are constants, and the value is fixed, so the value of s is also fixed, which is determined when the class is compiled. That is to say: String s=A+B; is equivalent to: String s=”ab”+”cd”;
Example three
public static final String A; // 常量A
public static final String B; // 常量B
static {
A = "ab";
B = "cd";
}
public static void main(String[] args) {
// 将两个常量用+连接对s进行初始化
String s = A + B;
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
} else {
System.out.println("s不等于t,它们不是同一个对象");
}
}
output ==> s不等于t,它们不是同一个对象
Although A and B are defined as constants, they are not assigned values immediately. Before the value of s is calculated, when they are assigned, and what value they are assigned, are variables. So A and B behave like a variable until they are assigned a value. Then s cannot be determined at compile time, but can only be created at runtime
String addition operation in the loop
- Less performant code:
public void implicitUseStringBuilder(String[] values) {
String result = "";
for (int i = 0 ; i < values.length; i ++) {
result += values[i];
}
System.out.println(result);
}
Compiled bytecode:
public void implicitUseStringBuilder(java.lang.String[]);
Code:
0: ldc #11 // String
2: astore_2
3: iconst_0
4: istore_3
5: iload_3
6: aload_1
7: arraylength
8: if_icmpge 38
11: new #5 // class java/lang/StringBuilder
14: dup
15: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
18: aload_2
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: iload_3
24: aaload
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_2
32: iinc 3, 1
35: goto 5
38: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
41: aload_2
42: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: return
8: if_icmpge 38 and 35: goto 5 form a loop;
8: if_icmpge 38 means if (the opposite of i < values.length) holds, then jump to line 38 (System.out).
35: goto 5 means jump directly to line 5.
But one very important thing here is that the creation of StringBuilder objects occurs between loops, which means how many StringBuilder objects will be created for how many loops, which is obviously lower in performance.
- high performance code
public void explicitUseStringBuider(String[] values) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < values.length; i ++) {
result.append(values[i]);
}
}
public void explicitUseStringBuider(java.lang.String[]);
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
7: astore_2
8: iconst_0
9: istore_3
10: iload_3
11: aload_1
12: arraylength
13: if_icmpge 30
16: aload_2
17: aload_1
18: iload_3
19: aaload
20: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: iinc 3, 1
27: goto 10
30: return
As can be seen from the above, 13: if_icmpge 30
and 27: goto 10
constitute a loop loop, and are 0: new #5
located outside the loop, so StringBuilder will not be created multiple times.
Note: It is necessary to avoid implicit or explicit creation of StringBuilder in the loop body as much as possible
Immutable String
String objects are immutable. Every method in the String class that appears to modify a String value actually creates a brand new String object containing the modified string content
String str1 = "java";
String str2 = "java";
System.out.println\("str1=str2 " + \(str1 == str2\)\);
In code, you can create multiple aliases of the same String object, and they refer to the same object, always staying in a single physical location
Overload "+"
In Java, the only overloaded operators are "+" and "+=" for String. In addition, Java does not allow programmers to overload other operators
public class StringTest {
String a = "abc";
String b = "mongo";
String info = a + b + 47;
}
String objects are immutable, so the above code process might work like this:
- "abc" + "mongo" creates a new String object abcmongo;
- "abcmongo" + "47" creates a new String object abcmongo47;
- Reference info points to the final generated String;
But this method will generate a lot of intermediate objects that need to be garbage collected, and the performance is quite bad
Compiler optimization processing
Compiled from "StringTest.java"
public class StringTest {
java.lang.String a;
java.lang.String b;
java.lang.String info;
public StringTest();
Code:
0: aload_0
1: invokespecial #12 // Method java/lang/Object."<init>":
()V
4: aload_0
5: ldc #14 // String abc
7: putfield #16 // Field a:Ljava/lang/String;
10: aload_0
11: ldc #18 // String mongo
13: putfield #20 // Field b:Ljava/lang/String;
16: aload_0
17: new #22 // class java/lang/StringBuilder
20: dup
21: aload_0
22: getfield #16 // Field a:Ljava/lang/String;
25: invokestatic #24 // Method java/lang/String.valueOf:(
Ljava/lang/Object;)Ljava/lang/String;
28: invokespecial #30 // Method java/lang/StringBuilder."<
init>":(Ljava/lang/String;)V
31: aload_0
32: getfield #20 // Field b:Ljava/lang/String;
35: invokevirtual #33 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: bipush 47
40: invokevirtual #37 // Method java/lang/StringBuilder.ap
pend:(I)Ljava/lang/StringBuilder;
43: invokevirtual #40 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
46: putfield #44 // Field info:Ljava/lang/String;
49: return
}
Decompiling the above code will find that the compiler automatically introduces the StringBuilder class.
The compiler creates a StringBuilder object, calls the StringBuilder.append() method, and finally calls toString() to generate the result, thereby avoiding the performance loss of the intermediate object
The design idea of string constant pool
- The allocation of strings, like other object allocations, consumes high time and space costs. As the most basic data type, a large number of strings are frequently created, which greatly affects the performance of the program.
- In order to improve performance and reduce memory overhead, JVM makes some optimizations when instantiating string constants
- Open up a string constant pool for strings, similar to a buffer area
- When creating a string constant, first insist on whether the string exists in the string constant pool
- If the string exists, return the reference instance, if it does not exist, instantiate the string and put it in the pool
- basis of realization
- The basis for this optimization is that strings are immutable and can be shared without worrying about data conflicts
- There is a table in the global string constant pool created by the runtime instance, which always maintains a reference for each unique string object in the pool, which means that they always refer to objects in the string constant pool, so, in These strings in the constant pool will not be collected by the garbage collector
- The benefits of the constant pool: The constant pool is to avoid the frequent creation and destruction of objects and affect the system performance, which realizes the sharing of objects. For example, the string constant pool, put all string literals into a constant pool at the compile stage;
- Save memory space: all the same string constants in the constant pool are merged, occupying only one space;
- Saves running time: == is faster than equals() when comparing strings. For two reference variables, only use == to determine whether the references are equal, and then you can determine whether the actual values are equal
String constant pool storage location
The string constant pool exists in the method area
String str1 = “abc”;
String str2 = “abc”;
String str3 = “abc”;
String str4 = new String(“abc”);
String str5 = new String(“abc”);
Reference
http://rednaxelafx.iteye.com/blog/774673