類繼承關(guān)系中圖
特點(diǎn)
String
來(lái)看幾個(gè)例子
String s1 = "hello world";
String s2 = "hello world";
System.out.println(s1 == s2);
輸出結(jié)果是true
String s1 = new String("hello world");
String s2 = new String("hello world");
String s3 = "hello world";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
輸出結(jié)果是 false、true、true
在 Java 編譯好的 class 文件中,有個(gè)區(qū)域被稱為常量池(Constant Pool),存儲(chǔ)著各種常量,其中存儲(chǔ)字符串常量的區(qū)域被習(xí)慣地稱為字符串池(String Pool)。在第一個(gè)例子中,有兩個(gè)“hello world”常量,但是在常量池中,只會(huì)創(chuàng)建一個(gè)常量,也就是說(shuō),在編譯好的 class 文件中,只能找到一個(gè)“hello world”常量。因此 s1 和 s2 指向的在常量池中同一個(gè)字符串對(duì)象,“==”比較是否是同一個(gè)對(duì)象,所以結(jié)果返回 true。
擴(kuò)展知識(shí)
private final char value[];
字符串是用一個(gè)不可變的字符數(shù)組來(lái)存儲(chǔ)字符串內(nèi)容,當(dāng) String 對(duì)象創(chuàng)建之后,就不能修改對(duì)象中存儲(chǔ)的內(nèi)容,所以說(shuō),String 類型是不可變的(immutable)
例如
String s1 = new String("hello");
s1 = s1 + " world";
因?yàn)?String 是不可變的,這段代碼會(huì)根據(jù)s1的內(nèi)容和字符串常量“ world”在heap區(qū)創(chuàng)建一個(gè)新的字符串
String s1 = new String("hello world");
該語(yǔ)句創(chuàng)建兩個(gè) String 對(duì)象,一個(gè)是在編譯時(shí),創(chuàng)建于字符串常量區(qū),一個(gè)是在運(yùn)行時(shí),創(chuàng)建于heap區(qū)。
Java對(duì)String進(jìn)行了“+”操作符重載,利用“+”可以將字符串連接。但是需要注意的是
String s1 = "hello" + " world";
該代碼與第一點(diǎn)的例子不一樣,編譯時(shí)編譯器會(huì)直接提取兩個(gè)常量的內(nèi)容,只生成“hello world”一個(gè)字符串,同理,無(wú)論多少個(gè)常量相加,都是生成一個(gè)對(duì)象。
運(yùn)行時(shí)調(diào)用 String 的 intern() 方法可以向 String Pool 中動(dòng)態(tài)添加對(duì)象。
5.String創(chuàng)建的幾種方法
- 使用“”。
- 使用 new String();
- 使用 new String("hello world");
- 使用重載操作符“+”
StringBuffer&StringBuilder
StringBuilder一個(gè)可變的字符序列是5.0新增的。此類提供一個(gè)與 StringBuffer 兼容的 API,但不保證同步。該類被設(shè)計(jì)用作 StringBuffer 的一個(gè)簡(jiǎn)易替換,用在字符串緩沖區(qū)被單個(gè)線程使用的時(shí)候(這種情況很普遍)。如果可能,建議優(yōu)先采用該類,因?yàn)樵诖蠖鄶?shù)實(shí)現(xiàn)中,它比 StringBuffer 要快。
Stringbuffer 和 StringBuilder除了線程安全的區(qū)別外,其他基本一致,都繼承于AbstractStringBuffer。
來(lái)看一下AbstractStringBuffer的源碼
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
/**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
* represented by this object
*/
@Override
public int length() {
return count;
}
/**
* Returns the current capacity. The capacity is the amount of storage
* available for newly inserted characters, beyond which an allocation
* will occur.
*
* @return the current capacity
*/
public int capacity() {
return value.length;
}
AbstractStringBuffer 使用的是可變的char數(shù)組,在創(chuàng)建 StringBuffer 和 StringBuilder 時(shí)有幾種方式,其中無(wú)參的構(gòu)造方法調(diào)用的是父類的構(gòu)造方法,創(chuàng)建大小為16的char數(shù)組
public StringBuffer() {
super(16);
}
public StringBuilder() {
super(16);
}
其他的構(gòu)造方法,StringBuilder 與之類似
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
其他常見(jiàn)方法:append、insert
三者區(qū)別
可變性
String 不可變,StringBuffer、StringBuilder可變
速度
StringBuilder > StringBuffer > String
線程安全
String、StringBuilder不安全,StringBuffer安全
總結(jié)
- 在編譯階段就能夠確定的字符串常量,完全沒(méi)有必要?jiǎng)?chuàng)建String或StringBuffer對(duì)象。直接使用字符串常量的"+"連接操作效率最高。
- StringBuffer對(duì)象的append效率要高于String對(duì)象的"+"連接操作。
- 不停的創(chuàng)建對(duì)象是程序低效的一個(gè)重要原因。那么相同的字符串值能否在堆中只創(chuàng)建一個(gè)String對(duì)象那。顯然拘留字符串能夠做到這一點(diǎn),除了程序中的字符串常量會(huì)被JVM自動(dòng)創(chuàng)建拘留字符串之外,調(diào)用String的intern()方法也能做到這一點(diǎn)。當(dāng)調(diào)用intern()時(shí),如果常量池中已經(jīng)有了當(dāng)前String的值,那么返回這個(gè)常量指向拘留對(duì)象的地址。如果沒(méi)有,則將String值加入常量池中,并創(chuàng)建一個(gè)新的拘留字符串對(duì)象。