final類,也就是無法被繼承, 底層實際是 final char[] value ,享元模式最經典的存在。 所以存在於常量池中,並且不可改變,所以是線程安全的。 (jdk8之後常量池取消) 。 存儲於常量池中, 可以直接用=賦值(java特殊處理), 賦值時先會去常量池查找,沒有則新建。 幾乎所有操作在底層都是將char[] 複製備份之後在進行操作,並最終new String 已保證常量性. 可能引發內存泄漏。
之前的java版本引發內存泄漏的著名方法就是 不斷new String的新對象,現在應該已經修復了此問題。
String :
StringBuffer : 線程安全的字符串變量,內容長度都可被修改,多個線程可以安全的訪問StringBuffer對象
StringBuilder : 非線程安全的字符串變量,在單線程使用時,效率略高於StringBuffer,JDK 1.5之後加入
一些方法的源碼 :
// subString: 實際還是截取一段字符串,然後new 一個新的string
public String substring(int beginIndex) {
if (beginIndex < 0) {//初始位置不能爲負
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;//初始位置不能大於串長度
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {//結尾位置不能大於串長度
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;//結尾位置必須大於開始位置
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
最著名的equals :
// equals: 判斷字符串相同
public boolean equals(Object anObject) {
if (this == anObject) { // 如果是自己 那肯定是一致的
return true;
}
if (anObject instanceof String) { // 是否是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;
}
忽略大小寫的equals :
equalsIgnoreCase:忽略大小寫
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null)
&& (anotherString.value.length == value.length)
&& regionMatches(true, 0, anotherString, 0, value.length);
}
public boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len) { // 是否忽略大小寫,偏移量, 要比較的string,偏移量,要比較的長度
char ta[] = value;
int to = toffset;
char pa[] = other.value;
int po = ooffset;
// 偏移量的驗證
if ((ooffset < 0) || (toffset < 0)
|| (toffset > (long)value.length - len)
|| (ooffset > (long)other.value.length - len)) {
return false;
}
// 開始逐個對比
while (len-- > 0) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2) {
continue;
}
if (ignoreCase) {//如果忽略大小寫
char u1 = Character.toUpperCase(c1);//都變大寫在比較
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;//都變小寫在比較一次,多次判定
}
}
return false;
}
return true;
}