Preface
This article mainly introduces the relevant content about JDK source code analysis, StringBuilder and StringBuffer. It is shared for your reference and learning. I won’t say much below. Let’s take a look at the detailed introduction together.
Statement of String class
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {…}The String class uses a final modifier to indicate that it cannot be inherited. At the same time, it also implements three interfaces, implementing the Serializable interface to indicate that the String class can be serialized; implementing the Comparable<T> interface mainly provides a compareTo method for comparing String strings; also implements the CharSequence interface, which represents that char is worth a readable sequence (CharBuffer, Segment, String, StringBuffer, and StringBuilder also implements the CharSequence interface)
String main fields and attribute descriptions
/*character array value, storing the actual characters in the String */private final char value[];/*The hash value of the string default value 0*/private int hash; /*The hash value of the string default value 0*//*A comparator used to sort String objects, the compareToIgnoreCase method uses */public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
String Partial Method Analysis
The String class provides a series of constructors, and several of them are no longer recommended, as shown in the figure below:
Constructor
Here are the implementations of two commonly used constructors:
//String str = new String("123")public String(String original) { this.value = original.value; this.hash = original.hash;}//String str3 = new String(new char[] {'1','2','3'});public String(char value[]) { //Copy the character array value to value this.value = Arrays.copyOf(value, value.length); }boolean equals(Object anObject)
The String class overrides the equals method to compare this string with the specified object. The result is true if and only if the parameter is not null and is a String object representing the same character sequence as this object.
public boolean equals(Object anObject) { //Compare object references directly, and return true if (this == anObject) { return true; } //Compare the character sequence of the current object with anObject value 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; }int compareTo(String anotherString)
Compare the character sequence of two strings bit by bit. If a bit character is not the same, return the difference in the Unicode value of the two characters of that bit. All bits are the same, calculate the difference in the length of the two strings. If the two strings are the same, return 0.
public int compareTo(String anotherString) { int len1 = value.length; int len2 = anotherString.value.length; //Take the length of a string with a smaller length int lim = Math.min(len1, len2); char v1[] = value; char v2[] = anotherString.value; int k = 0; while (k < lim) { //Compare the character sequence value of the two strings one by one. If it is not equal, return the difference between the Unicode of the two characters at that position char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; //Return the difference between Unicode} k++; } //All bits of a smaller string are compared, and the difference between the lengths of the two strings is returned//If the two strings are the same, the difference between the lengths is 0, that is, the same string returns 0 return len1 - len2; } The compareToIgnoreCase(String str) method is implemented similarly. The upper and lower case of characters is ignored during comparison, and the implementation method is as follows:
public int compare(String s1, String s2) { int n1 = s1.length(); int n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toUpperCase(c1); c2 = Character.toUpperCase(c2); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { // No overflow because of numeric promotion return c1 - c2; } } } } return n1 - n2; }native String intern()
When the intern method is called, if the pool already contains a string equal to this String object (determined with the equals(Object) method), the string in the pool is returned. Otherwise, add this String object to the pool and return a reference to this String object.
All literal strings and string assignment constant expressions are operated using the intern method, for example: String str1 = "123";
String memory location: constant pool OR heap
String objects can be created directly through literals or through constructors. What's the difference?
1. String objects created by literal or literal strings through "+" splicing are stored in the constant pool. If the constant pool exists during actual creation, the reference will be directly returned. If it does not exist, the string object will be created.
2. Create a string object using the constructor, and create a String object directly in the heap
3. Call the intern method, and return the object will be put into the constant pool (if it does not exist, it will be placed into the constant pool, and if it does exist, it will be returned to the reference)
The following is an example of the memory allocation of String objects:
String str1 = new String("123"); String str2 = "123"; String str3 = "123"; String str4 = str1.intern(); System.out.println(str1==str2); // false str1 creates an object in the heap, str2 creates an object in the constant pool System.out.println(str2==str3); // true str2 creates an object in the constant pool, str3 directly returns a reference to the object created by str2, so str2 and str3 point to the same object in the constant pool System.out.println(str4==str3); // true str4 returns an object with a value of "123" in the constant pool, so str4, str2 and str3 are equal.About string stitching example:
public class StringTest { public static final String X = "ABC"; // Constant X @Test public void Test() { String str5 = new String("ABC"); String str6 = str5+"DEF"; //Create String str7 = "ABC"+"DEF"; //Constant pool String str8 = X+"DEF"; //X is a constant, and the value is fixed, so the value of X+"DEF" has been set to ABCDEF. In fact, after compilation, the code is equivalent to String str8 = "ABCDEF" String str9 = "ABC"; String str10 = str9+"DEF"; //System.out.println(str6==str7); //false System.out.println(str8==str7); //true System.out.println(str10==str7); //false System.out.println(X==str9); //true} }The decompiled code will be clear at a glance:
Memory allocation is as follows:
String, StringBuffer, StringBuilder
Since the property value[] character array for storing strings maintained internally by String type is modified with final:
/** The value is used for character storage. */private final char value[];
It indicates that it can be modified after assignment. Therefore, we believe that the String object is immutable once created. If you encounter frequent splicing string operations during development, if you use the contact provided by String or use the "+" splicing string directly, new strings will be frequently generated, which will be inefficient. Java provides two other classes: StringBuffer and StringBuilder, which are used to solve this problem:
Take a look at the following code:
String str1="123"; String str2="456"; String str3="789"; String str4 = "123" + "456" + "789"; //Add constants, the compiler automatically recognizes String str4="123456789" String str5 = str1 + str2 + str3; //Sticket string variables, it is recommended to use StringBuilder StringBuilder sb = new StringBuilder(); sb.append(str1); sb.append(str2); sb.append(str3);
The following is the implementation of the StringBuilder class, which only intercepts some of the code analyzed:
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{ //Split string @Override public StringBuilder append(String str) { //Calling the parent class AbstractStringBuilder.append super.append(str); return this; } } abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The character array that stores strings, non-final type, different from String class*/ char[] value; /** * The count is the number of characters used. */ int count; public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); //Check whether the capacity needs to be expanded to ensureCapacityInternal(count + len); //Copy the string str to value str.getChars(0, len, value, count); count += len; return this;} private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code // minimumCapacity=count+str.length // If the capacity after str is spliced is greater than the value capacity, expand if (minimumCapacity - value.length > 0) { //Expand capacity, and copy the current value value to the expanded character array, return the new array reference value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } //StringBuilder expansion private int newCapacity(int minCapacity) { // overflow-conscious code // Calculate expansion capacity// The default expansion array length is expanded by 2 times the original number (value[]) group length and then 2 are added to the rule. Why add 2? int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }}The same is true for StringBuffer and StringBuilder. The value[] character array maintained internally is mutable. The only difference is that StringBuffer is thread-safe. It synchronizes all methods. StringBuilder is thread-not safe. Therefore, when multi-threaded operation and sharing string variables, StringBuffer is preferred for string splicing processing. Otherwise, StringBuilder can be used. After all, thread synchronization will also bring certain consumption.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.