String類別內部維護了一個char[]類型的value用來儲存字串,相對來說原始碼較為簡單些。
String的不可變主要體現在三個方面:
String類別被定義為final類型,不可被繼承
String中的value[]被定義為final
String中的所有產生新的String的操作底層都會呼叫Array.copy或System.copy來產生一個新的String物件
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; }
以上兩個是較為特殊的一類建構函數,第一個用一個現成的String來初始化一個新的String對象,建構方法直接將新的String對象的value指向舊的value對象。由於String是不可變的,所以這裡不需要重新copy一份value的物件。第二個建構方法看似會破壞String類型的不可變性(當參數value變化時String也會改變),但建構方法並沒有宣告為public,只允許在套件內使用,被宣告為public的String( char value[])底層呼叫的是Array.copy來實現底層資料拷貝的,上述的兩個建構函式已經不建議使用
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); }
上面這個建構子較為典型,許多其他的建構子都與其類似或底層呼叫了該建構函數,入參是一個char數組(byte[]),offset偏移位置及count偏移量。底層呼叫Arrays.copy函數來進行深度複製。
public String(StringBuffer buffer) { synchronized(buffer) { //保证线程安全 this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } } public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); }
上述兩個建構子入參分別是StringBuffer和StringBuilder,底層都是呼叫Arrays.copyOf,唯一不同的是StringBuffer是線程安全的,所有呼叫時都需要用synchronized關鍵字。
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和lastIndexOf主要是index和lastIndex函數的底層調用,通讀程式碼會發現底層實作並沒有特別牛逼的kmp演算法,仍然是一個字元一個字元掃描實現的。其中lastIndexOf還是用了continue startSearchForLastChar;相對來說比較少見。
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; } } //如果找不到则返回this if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; //替换 buf[i] = (c == oldChar) ? newChar : c; i++; } //返回新的String,利用上述包内的非public构造函数 return new String(buf, true); } } return this; }
replace用於將String物件中的一個字元替換為另一個字符,如果找不到製定的字元則返回本身,如果找到則會另建一個新的String物件傳回。
---恢復內容結束---
#以上是String原始碼的實例解讀的詳細內容。更多資訊請關注PHP中文網其他相關文章!