String source code analysis, string source code
The String class maintains a char [] type value to store strings. The source code is relatively simpler.
1. Immutable
The immutability of String is mainly reflected in three aspects:
- The String class is defined as the final type and cannot be inherited.
- Value [] In String is defined as final
- All operations to generate a new String in String are called Array. copy or System. copy at the underlying layer to generate a new String object.
2. constructor: String constructor is relatively simple, but the following are special
public String(String original) { this.value = original.value; this.hash = original.hash; } String(char[] value, boolean share) { // assert share : "unshared not supported"; this.value = value; }
The above two are special constructors. The first one uses a ready-made String to initialize a New String object. The constructor directly points the value of the New String object to the old value object. Because String is immutable, you do not need to copy a value object again here. The second constructor seems to damage the non-variability of the String type (the String will also change when the parameter value changes), but the constructor is not explicitly public and can only be used in the package, the underlying String (char value []) declared as public calls Array. copy to copy the underlying data. We do not recommend that you use the above two constructors.
public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); }
The preceding constructor is typical. Many other constructor functions are similar to this one or call this constructor at the underlying layer. The input parameter is a char array (byte []). offset and count offset. The underlying layer calls the Arrays. copy function for deep replication.
Public String (StringBuffer buffer) {synchronized (buffer) {// ensure thread security this. value = Arrays. copyOf (buffer. getValue (), buffer. length () ;}} public String (StringBuilder builder) {this. value = Arrays. copyOf (builder. getValue (), builder. length ());}
The input parameters of the two constructors are StringBuffer and StringBuilder respectively. The bottom layer calls Arrays. copyOf. The only difference is that StringBuffer is thread-safe, and the synchronized keyword is required for all calls.
3. Other Methods
static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { if (fromIndex >= sourceCount) { return (targetCount == 0 ? sourceCount : -1); } if (fromIndex < 0) { fromIndex = 0; } if (targetCount == 0) { return fromIndex; } char first = target[targetOffset]; int max = sourceOffset + (sourceCount - targetCount); for (int i = sourceOffset + fromIndex; i <= max; i++) { /* Look for first character. */ if (source[i] != first) { while (++i <= max && source[i] != first); } /* Found first character, now look at the rest of v2 */ if (i <= max) { int j = i + 1; int end = j + targetCount - 1; for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++); if (j == end) { /* Found whole string. */ return i - sourceOffset; } } } return -1; } static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { /* * Check arguments; return immediately where possible. For * consistency, don't check for null str. */ int rightIndex = sourceCount - targetCount; if (fromIndex < 0) { return -1; } if (fromIndex > rightIndex) { fromIndex = rightIndex; } /* Empty string always matches. */ if (targetCount == 0) { return fromIndex; } int strLastIndex = targetOffset + targetCount - 1; char strLastChar = target[strLastIndex]; int min = sourceOffset + targetCount - 1; int i = min + fromIndex; startSearchForLastChar: while (true) { while (i >= min && source[i] != strLastChar) { i--; } if (i < min) { return -1; } int j = i - 1; int start = j - (targetCount - 1); int k = strLastIndex - 1; while (j > start) { if (source[j--] != target[k--]) { i--; continue startSearchForLastChar; } } return start - sourceOffset + 1; } }
IndexOf and lastIndexOf are mainly called at the underlying layer of the index and lastIndex functions. The read-through code will find that the underlying implementation does not have a particularly awesome kmp algorithm, and it is still implemented by one character and one character scanning. LastIndexOf still uses the continue startSearchForLastChar, which is relatively rare.
Public String replace (char oldChar, char newChar) {if (oldChar! = NewChar) {int len = value. length; int I =-1; char [] val = value;/* avoid getfield opcode */while (++ I <len) {if (val [I] = oldChar) {break ;}// if not found, this if (I <len) is returned) {char buf [] = new char [len]; for (int j = 0; j <I; j ++) {buf [j] = val [j];} while (I <len) {char c = val [I]; // replace buf [I] = (c = oldChar )? NewChar: c; I ++;} // return a new String. Use the Non-public constructor in the preceding package to return new String (buf, true) ;}} return this ;}
Replace is used to replace one character in the String object with another character. If no specific character is found, the system returns itself. If it is found, a New String object is created and returned.
--- Restore content end ---