你了解String類嗎捣鲸?
- 1 想要了解一個類,最好的辦法就是看這個類的實現(xiàn)源代碼
String類的定義如下:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
private final char value[];
private final int offset;
private final int count;
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
....
}
- 1 String類是final類闽坡,也即意味著String類不能被繼承栽惶,并且它的屬性和方法都默認(rèn)為final方法。
- 2 String類其實是通過char數(shù)組來保存字符串的疾嗅。
- 3 下面再繼續(xù)看String類的一些方法實現(xiàn)
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = count;
int i = -1;
char[] val = value; /* avoid getfield opcode */
int off = offset; /* avoid getfield opcode */
while (++i < len) {
if (val[off + i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0 ; j < i ; j++) {
buf[j] = val[off+j];
}
while (i < len) {
char c = val[off + i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(0, len, buf);
}
}
return this;
從上面的三個方法可以看出外厂,無論是substring、concat還是replace操作都不是在原有的字符串上進(jìn)行的代承,而是重新生成了一個新的字符串對象汁蝶。也就是說進(jìn)行這些操作后,最原始的字符串并沒有被改變论悴。
- 5 對String對象的任何改變都不影響到原對象掖棉,相關(guān)的任何change操作都會生成新的對象。
深入理解String膀估、StringBuffer幔亥、StringBuilder
- 1 String str="hello world"和String str=new String("hello world")的區(qū)別
public class MyTest{
public static void main(String[] args) {
String str1 = "hello world";
String str2 = new String("hello world");
String str3 = "hello world";
String str4 = new String("hello world");
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str2==str4);
}
}
輸出結(jié)果為:
false
true
false
1)在class文件中有一部分 來存儲編譯期間生成的 字面常量以及符號引用,這部分叫做class文件常量池察纯,在運(yùn)行期間對應(yīng)著方法區(qū)的運(yùn)行時常量池帕棉。
2)因此在上述代碼中,String str1 = "hello world";和String str3 = "hello world"; 都在編譯期間生成了 字面常量和符號引用捐寥,運(yùn)行期間字面常量"hello world"被存儲在運(yùn)行時常量池(當(dāng)然只保存了一份)笤昨。通過這種方式來將String對象跟引用綁定的話,JVM執(zhí)行引擎會先在運(yùn)行時常量池查找是否存在相同的字面常量握恳,如果存在瞒窒,則直接將引用指向已經(jīng)存在的字面常量;否則在運(yùn)行時常量池開辟一個空間來存儲該字面常量乡洼,并將引用指向該字面常量崇裁。
3)總所周知,通過new關(guān)鍵字來生成對象是在堆區(qū)進(jìn)行的束昵,而在堆區(qū)進(jìn)行對象生成的過程是不會去檢測該對象是否已經(jīng)存在的拔稳。因此通過new來創(chuàng)建對象,創(chuàng)建出的一定是不同的對象锹雏,即使字符串的內(nèi)容是相同的巴比。
- 2 String、StringBuffer以及StringBuilder的區(qū)別
1)既然在Java中已經(jīng)存在了String類,那為什么還需要StringBuilder和StringBuffer類呢轻绞?
那么看下面這段代碼:
public class MyTest{
public static void main(String[] args) {
String string = "";
for(int i=0;i<10000;i++){
string += "hello";
}
}
}
這句 string += "hello";的過程相當(dāng)于將原有的string變量指向的對象內(nèi)容取出與"hello"作字符串相加操作再存進(jìn)另一個新的String對象當(dāng)中采记,再讓string變量指向新生成的對象。
2)再看下面這段代碼:
public class MyTest {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
for(int i=0;i<10000;i++){
stringBuilder.append("hello");
}
}
}
只生成了一個對象政勃,append操作是在原有對象的基礎(chǔ)上進(jìn)行的唧龄。因此在循環(huán)了10000次之后,這段代碼所占的資源要比上面小得多奸远。
3)那么有人會問既然有了StringBuilder類既棺,為什么還需要StringBuffer類?
查看源代碼便一目了然懒叛,事實上丸冕,StringBuilder和StringBuffer類擁有的成員屬性以及成員方法基本相同,區(qū)別是StringBuffer類的成員方法前面多了一個關(guān)鍵字:synchronized芍瑞,不用多說晨仑,這個關(guān)鍵字是在多線程訪問時起到安全保護(hù)作用的,也就是說StringBuffer是線程安全的。