In-depth understanding of Java common classes -----StringBuilder
In the last article we coveredString This common class, Knowing that the internals of the class actually use achar The array represents a string object of, It's just that the array of characters wasfinal retouch, once initialize It can't be modified., But for cases where string modification operations are frequently done,String The class then needs to keep creating new objects, Extremely low performance。StringBuilder Internally it is also an array of wrapped characters, Only the array is notfinal retouch, Can be constantly modified。 So for some cases where you need to modify the string frequently, We should preferStringBuilder。 indeedStringBuilder harmonyStringBuffer The internal code is almost the same, merelyStringBuffer All methods of the keywordsynchronized retouch, That means it's thread-safe., But thread safety comes at a performance cost, So in actual use, Select as appropriate。 This article focuses onStringBuilder, Here are the main points of this article:
one、The powerful parent class AbstractStringBuilder Most of the methods of StringBuilder call the parent class methods or properties, so it is clear that the parent class has a great influence on it, so we will briefly introduce its parent class, AbstractStringBuilder, from beginning to end. There are only two properties in this class.
//The value is used for character storage. char[] value; //The count is the number of characters used. int count;
The value property represents an array of characters, the role of the array and the role of the array of characters in String is the same, but the value array is not modified by final, that is, the value inside the array can be dynamically modified, which is also the meaning of the existence of StringBuilder. The count property represents not the length of the value array, it represents the number of characters actually stored in the value array, for example: the length of value is 10, I store 8 characters, the remaining position is empty, at this time the value of count is 8, and value.length() is 10.
Neither constructor is public, they are both designed to be used by subclasses.
AbstractStringBuilder() {} // initializevalue AbstractStringBuilder(int capacity) { value = new char[capacity]; }
There are also two methods for returning length.
public int length() { return count; } public int capacity() { return value.length; }
One returns the actual number of characters stored, the other returns the length of the built-in character array. There is also a method for guaranteeing the length of character arrays that has the same effect as the method we described earlier for dynamically expanding an ArrayList.
void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); }
For a StringBuilder object, we can keep appending strings to it, so we will encounter the time when the value array is not long enough, this method is used to deal with this situation, before we actually operate the value array, most will call this method to determine whether the operation will lead to array overflow, if so, the original array will be expanded twice the length plus 2 and copy the contents of the original array to the new array, and then the actual operation of the value array. (The value array has been expanded at this point).
This idea of dynamic scaling is also used in ArrayList and becomes its core advantage over normal arrays. This idea is actually a compromise solution that avoids the waste of resources that would result from creating a very large array at once, and also addresses the static limitation that once created, it cannot be changed. This kind of thinking deserves to be studied and applied.
This class also provides a method to remove all elements of the value array that are empty: the
public void trimToSize() { if (count < value.length) { value = Arrays.copyOf(value, count); } }
Look at an example.
public static void main(String[] args){ StringBuilder sb = new StringBuilder(); sb.append("hello"); System.out.println(sb.length()); System.out.println(sb.capacity()); sb.trimToSize(); System.out.println(sb.length()); System.out.println(sb.capacity()); }
Let's look at the output.
5 16 5 5
It should be explained that if the length of value is not explicitly specified, it will default to 16, and the program assigns values to the first 5 positions of value, with the next positions being empty, so we see a difference in the first output. But our trimToSize method clears all the empty positions that are not used, and the second output shows that capcity and length are the same.
Other methods in this class, such as getChars, charAt, etc., are very much the same as the corresponding methods in the String class. Here we'll look at one of the main important methods, append. The method also has a fair amount of overloading, so let's take our time.
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; }
The append method is one of the most commonly used methods when we use StringBuilder, and is used to append a string to the end of the original StringBuilder object. This method takes a String object, and if it is null will call the appendNull method to append the string "null" to the end of the original object, otherwise it will append the string to the end of the original object.
All other overloads add strings to the end of the original StringBuilder object in various forms, and if parameters of type int, long, double, boolean, etc. are passed in, then the program converts them to string types and adds them to the end. We can also specify that a part of a string be added, e.g.
public AbstractStringBuilder append(char str[], int offset, int len)
At this point, we have completed a brief introduction to the superclass AbstractStringBuilder, and as for some of the other methods in it, we will continue from his implementation class StringBuilder. Let's take a look at some of the commonly used methods regarding the StringBuilder class.
2、 Multiple overloaded constructors StringBuilder does not encapsulate any properties other than a version number, not even an array of characters, that is because it is highly dependent on its parent class and uses the array of characters encapsulated in the parent class. Including his constructor which also calls the constructor in the parent class, e.g.
public StringBuilder() { super(16); } public StringBuilder(int capacity) { super(capacity); } public StringBuilder(String str) { super(str.length() + 16); append(str); }
These constructors will call one of the parent class constructors asvalue character array initialize length, If the length of the array to be set is not explicitly passed in, then it will default to16, This was demonstrated in our previous example。 The main thing these constructors do is initialize An array of characters。 Here we lookStringBuilder An important approach to the:append。
III. Important append methods The append methods in StringBuilder all override the append method in the parent class.
@Override public StringBuilder append(boolean b) { super.append(b); return this; } @Override public StringBuilder append(char c) { super.append(c); return this; } @Override public StringBuilder append(int i) { super.append(i); return this; } @Override public StringBuilder append(long lng) { super.append(lng); return this; } @Override public StringBuilder append(float f) { super.append(f); return this; }
Actually, don't look at all the overloads, they're actually all calls to each other, and only one or two of them are really useful. They all these method overloading internal will call the corresponding method in the parent class, although it does not accept the return value, but the parent class methods complete the assignment of the value array operation, the last call after the completion of the append method returns the StringBuilder object, which means we can continuously call the append method.
In fact, we need to always understand a point, StringBuilder and StringBuffer they are in fact similar to String, the same internal are encapsulated array of characters, except that StringBuilder implements a dynamic expansion mechanism, can be dynamically expanded and can dynamically change the elements of the value array, but essentially the same.
IV. Some other details about the use of StringBuilder First let's look at a delete method that specifies the deletion of substrings within the finger range of the StringBuilder object.
public AbstractStringBuilder delete(int start, int end) { if (start < 0) throw new StringIndexOutOfBoundsException(start); if (end > count) end = count; if (start > end) throw new StringIndexOutOfBoundsException(); int len = end - start; if (len > 0) { System.arraycopy(value, start+len, value, start, count-end); count -= len; } return this; }
The core method in this method is System.arraycopy, which is also widely used in array copy transfers. This method moves all characters after the value array index position is start+len forward to the start index position and the start+count-len termination position. It is important to remember that the method does not create a new array, but rather moves elements of the original value array to achieve this. In effect the method moves all the characters following the substring that is about to be deleted to the start of the deleted substring as a whole.
The length of the value array does not change, it just overwrites the substring that will be deleted with the one that follows it, and then count -= len; Update count, but it doesn't actually remove it. But the value of count specifies the number of valid characters in that value array, and although the element is not specifically removed, only the first count of characters will be output as valid in the output. This is the underlying operation of delete, including the deleteCharAt which deletes the character at the specified position, the principle is the same.
The class also has some replace, substring and other methods, these methods and we have previously introduced the corresponding methods in the String class are similar to the underlying implementation, here is not repeated. Here we look at a method that is not in the String class, INSERT.
public AbstractStringBuilder insert(int index, char[] str, int offset,int len) { if ((index < 0) || (index > length())) throw new StringIndexOutOfBoundsException(index); if ((offset < 0) || (len < 0) || (offset > str.length - len)) throw new StringIndexOutOfBoundsException( "offset " + offset + ", len " + len + ", str.length "+ str.length); ensureCapacityInternal(count + len); System.arraycopy(value, index, value, index + len, count - index); System.arraycopy(str, offset, value, index, len); count += len; return this; }
After having the foundation of the previous delete method to learn, this insert method is simple. The method accepts four parameters, the first indicating the index position to be inserted, the second indicating the array or string of characters to be inserted, and the third and fourth parameters for intercepting that original array of characters. The core method is still System.arraycopy, but here it is called twice. The first call moves all the characters after the index position back by len lengths (leaving an empty position for the string to be inserted), and the second call inserts the array of characters into the reserved position.
The insert method has many overloads, but essentially none of them can be separated from the one we introduced above. So for the sake of lending space, I won't go into it here.
So far, we have simply introduced the completion of the basic use of StringBuilder, understanding where not, we hope you point out, learn from each other!