一渣刷、Java String 類——String字符串常量
字符串廣泛應用 在Java 編程中,在 Java 中字符串屬于對象矗烛,Java 提供了 String 類來創(chuàng)建和操作字符串辅柴。
需要注意的是,String的值是不可變的,這就導致每次對String的操作都會生成新的String對象碌嘀,這樣不僅效率低下涣旨,而且大量浪費有限的內(nèi)存空間。我們來看一下這張對String操作時內(nèi)存變化的圖:
我們可以看到筏餐,初始String值為“hello”开泽,然后在這個字符串后面加上新的字符串“world”,這個過程是需要重新在棧堆內(nèi)存中開辟內(nèi)存空間的魁瞪,最終得到了“hello world”字符串也相應的需要開辟內(nèi)存空間穆律,這樣短短的兩個字符串,卻需要開辟三次內(nèi)存空間导俘,不得不說這是對內(nèi)存空間的極大浪費峦耘。為了應對經(jīng)常性的字符串相關的操作,
引入了兩個新的類——StringBuffer類和StringBuild類來對此種變化字符串進行處理旅薄。
二辅髓、Java StringBuffer 和 StringBuilder 類——StringBuffer字符串變量、StringBuilder字符串變量
當對字符串進行修改的時候少梁,需要使用 StringBuffer 和 StringBuilder 類洛口。
和 String 類不同的是,StringBuffer 和 StringBuilder 類的對象能夠被多次的修改凯沪,并且不產(chǎn)生新的未使用對象第焰。
StringBuilder 類和 StringBuffer 之間的最大不同在于 StringBuilder 的方法不是線程安全的(不能同步訪問)。
由于 StringBuilder 相較于 StringBuffer 有速度優(yōu)勢妨马,所以多數(shù)情況下建議使用 StringBuilder 類挺举。然而在應用程序要求線程安全的情況下,則必須使用 StringBuffer 類烘跺。
三者的繼承結構
三者的區(qū)別:
(1)字符修改上的區(qū)別(主要湘纵,見上面分析)
(2)初始化上的區(qū)別,String可以空賦值滤淳,后者不行梧喷,報錯
①String
String s = null;
String s = “abc”;
②StringBuffer
StringBuffer s = null; //結果警告:Null pointer access: The variable result can only be null at this location
StringBuffer s = new StringBuffer();//StringBuffer對象是一個空的對象
StringBuffer s = new StringBuffer(“abc”);//創(chuàng)建帶有內(nèi)容的StringBuffer對象,對象的內(nèi)容就是字符串”
三、可變性上
String字符串的本質脖咐,就是在String類內(nèi)部維護了一個字符數(shù)組,并且這個數(shù)組被final修飾伤柄,因此String是不可變對象
/** The value is used for character storage. */
private final char value[];
StringBuffer和StringBuilder都繼承于AbstractStringBuilder,不過AbstractStringBuilder內(nèi)的字符數(shù)組是沒有被final修飾的,因此StringBuffer和StringBuilder對象是可變的
/**
* The value is used for character storage.
*/
char[] value;
三文搂、線程安全上
由于String是不可變的适刀,很顯然String類是線程安全的,而StringBuffer和StringBuilder都繼承于AbstractStringBuilder的一些公共方法煤蹭,不過在重寫時笔喉,StringBuffer對這些方法加了同步鎖:
@Override
public synchronized int length() {
return count;
}
@Override
public synchronized int capacity() {
return value.length;
}
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
super.ensureCapacity(minimumCapacity);
}
/**
* @since 1.5
*/
@Override
public synchronized void trimToSize() {
super.trimToSize();
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
@Override
public synchronized void setLength(int newLength) {
toStringCache = null;
super.setLength(newLength);
}
四取视、是否實現(xiàn)了equals和hashCode方法
String實現(xiàn)了equals()方法,和hashCode()方法常挚,可以看到equals方法是比較的值作谭,而不是引用。
奄毡,new String("java").equals(new String("java"))的結果為true折欠;
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof 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;
}
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
而StringBuffer沒有實現(xiàn)equals()方法和hashCode()方法,因此吼过,new StringBuffer("java").equals(new StringBuffer("java"))的結果為false锐秦,將StringBuffer對象存儲進Java集合類中會出現(xiàn)問題。
五盗忱、初始化方式
當創(chuàng)建String對象時酱床,可以利用構造方法String str = new String("Java")的方式來對其進行初始化,也可以直接用賦值的方式String s = "Java"來初始化趟佃。
而StringBuffer只能使用構造方法StringBuffer sb = new StringBuffer("hello")的方式初始化扇谣。
小結:
綜上,在執(zhí)行效率方面闲昭,StringBuilder最高罐寨,StringBuffer次之,String最低序矩,
(1)如果要操作少量的數(shù)據(jù)用 String衩茸;
(2)多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) StringBuffer;
(3)單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) StringBuilder贮泞。