面试官:请聊一聊String、StringBuilder、StringBuffer三者的区别
面試官:“小伙子,在日常的寫代碼過程中,使用過String,StringBuilder和StringBuffer沒?”
我:“用過的呀!”
面試官:“那你就來聊一聊,他們之間有什么區別,不同場景下如何選擇吧”
我:“好嘞!”
在Java的開發過程中,使用頻率最高的就是String字符串,但由于在字符串存儲和拼接的過程中,涉及到很多場景需要因地制宜的選用StringBuider與StringBuffer。
我們先來聊一聊String,由源碼引入話題:
Java8中的String源碼
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
//...
}
我們從源碼中可以總結出如下幾點內容:
- String類被final關鍵字修飾,意味著它不可被繼承;
- String的底層采用了final修飾的char數組,意味著它的不可變性;
- 實現了Serializable接口意味著它支持序列化;
- 實現了Comparable接口,意味著字符串的比較可以采用compareTo()方法,而不是==號,并且Sring類內部也重寫了Object的equals()方法用來比較字符串相等。
Java9以后String的底層數據由char類型改為了byte類型,看源碼:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
private final byte coder;
private int hash;
}
這樣做的目的是為了節省字符串占用的內存空間,在大字符串處理中提升效率,同時也降低了垃圾回收的次數,提升性能。
面試官:“String類設置為不可變對象的話,豈不是每次創建或者字符串拼接的時候都會創建對象,增加開銷?那為什么還要用final修飾呢?”
我:“嗯~這個問題非常好呀,我理解的是兩個原因”
1、String 類是最常用的類之一,為了效率,禁止被繼承和重寫
2、為了安全。String 類中有很多調用底層的本地方法,調用了操作系統的API,
如果方法可以重寫,可能被植入惡意代碼,破壞程序。其實Java 的安全性在這里就有一定的體現啦。
基于以上String的特點,Java官方自然也知道它的弊端,所以為了全場景的最優方案適配,便產生了StringBuilder和StringBuffer這兩個String的近親字符串處理類,他們都實現了CharSequence 接口。
StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數組保存字符串,不過沒有使用 final 和 private 關鍵字修飾,所以可以解決在字符串拼接時的性能問題,最關鍵的是這個 AbstractStringBuilder 類還提供了很多修改字符串的方法,比如 append 方法。
源碼:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//...
}
StringBuilder源碼
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
// ...
public StringBuilder append(String str) {
super.append(str);
return this;
}
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
// ...
}
StringBuilder替代String的字符串拼接案例
Java 是一門解釋型的編程語言,所以當編譯器遇到 + 號這個操作符的時候,會將
new String("Hello") + new String("World")
解釋為
new StringBuilder().append("Hello").append("World").toString();
并且在循環字符串拼接的時候,String的“+”拼接方式,會在循環內部多次創建StringBuilder對象,白白浪費了資源,如:
String[] arr = {"he", "llo", "world"};
String s = "";
for (int i = 0; i < arr.length; i++) {
s += arr[i];
}
System.out.println(s);
這一段代碼完全就可以直接使用StringBuilder調用append實現方式來替代:
String[] arr = {"he", "llo", "world"};
StringBuilder s = new StringBuilder();
for (String value : arr) {
s.append(value);
}
System.out.println(s);
StringBuffer源碼
public final class StringBuffer extends AbstractStringBuilder implements Serializable, CharSequence {
public StringBuffer() {
super(16);
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public synchronized String toString() {
return new String(value, 0, count);
}
// 其他方法
}
從它的源碼我們可以看出,內部的實現與StringBuilder相差無機,無非是在方法的前面加了synchronized 關鍵字進行了同步,以確保在多線程場景下的線程安全,但在大部分的非多線程場景下,由于同步鎖的存在會導致執行效率過低,并且即便在多線程情況下,依舊可以通過ThreadLocal搭配StringBuilder的方式來安全的修改字符串,所以,實際開發中,StringBuilder 的使用頻率也是遠高于 StringBuffer,甚至可以這么說,StringBuilder 完全取代了 StringBuffer。
三者異同點總結
相同點:
1、都可以儲存和操作字符串
2、都使用 final 修飾,不能被繼承
3、提供的 API 相似
異同點:
1、String 是只讀字符串,String 對象內容是不能被改變的
2、StringBuffer 和 StringBuilder 的字符串對象可以對字符串內容進行修改,在修改后的內存地址不會發生改變
3、StringBuilder 線程不安全;StringBuffer 線程安全
總結
以上是生活随笔為你收集整理的面试官:请聊一聊String、StringBuilder、StringBuffer三者的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MSSQL 数据库无法打开恢复操作将数据
- 下一篇: 如何在Mac上调试iphone 打开的s