String、StringBuilder、StringBuffer的区别
它們之間的區別:
在我們學習String類的時候,也會學習到StringBuilder和StringBuffer,但是他們之間有什么區別呢? 當然他們在具體的代碼實現上、內存分配上以及效率上都有著不同(我這里以JDK8為例);
一、代碼實現
String
從這里我們可以看出,String的底層結構是private final char value[];所以String的值是不可變的,并且實現了Comparable接口,所以是支持比較的。
StringBuilder
public final class StringBuilderextends AbstractStringBuilderimplements java.io.Serializable, CharSequence {/** use serialVersionUID for interoperability */static final long serialVersionUID = 4383685877147921099L;/*** Constructs a string builder with no characters in it and an* initial capacity of 16 characters.*/public StringBuilder() {super(16);}/*** Constructs a string builder with no characters in it and an* initial capacity specified by the {@code capacity} argument.** @param capacity the initial capacity.* @throws NegativeArraySizeException if the {@code capacity}* argument is less than {@code 0}.*/public StringBuilder(int capacity) {super(capacity);}/*** Constructs a string builder initialized to the contents of the* specified string. The initial capacity of the string builder is* {@code 16} plus the length of the string argument.** @param str the initial contents of the buffer.*/public StringBuilder(String str) {super(str.length() + 16);append(str);}/*** Constructs a string builder that contains the same characters* as the specified {@code CharSequence}. The initial capacity of* the string builder is {@code 16} plus the length of the* {@code CharSequence} argument.** @param seq the sequence to copy.*/public StringBuilder(CharSequence seq) {this(seq.length() + 16);append(seq);}@Overridepublic StringBuilder append(Object obj) {return append(String.valueOf(obj));}@Overridepublic StringBuilder append(String str) {super.append(str);return this;}從這里我們可以看出StringBuilder有一個抽象父類,他是沒有實現Comparable接口,明顯不支持比較。我們看到AbstractStringBuilder類中,value是可變的,并不像String有final修飾
AbstractStringBuilder
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() {}StringBuffer
public final class StringBufferextends AbstractStringBuilderimplements java.io.Serializable, CharSequence {/*** A cache of the last value returned by toString. Cleared* whenever the StringBuffer is modified.*/private transient char[] toStringCache;/** use serialVersionUID from JDK 1.0.2 for interoperability */static final long serialVersionUID = 3388685877147921107L;/*** Constructs a string buffer with no characters in it and an* initial capacity of 16 characters.*/public StringBuffer() {super(16);}/*** Constructs a string buffer with no characters in it and* the specified initial capacity.** @param capacity the initial capacity.* @exception NegativeArraySizeException if the {@code capacity}* argument is less than {@code 0}.*/public StringBuffer(int capacity) {super(capacity);}/*** Constructs a string buffer initialized to the contents of the* specified string. The initial capacity of the string buffer is* {@code 16} plus the length of the string argument.** @param str the initial contents of the buffer.*/public StringBuffer(String str) {super(str.length() + 16);append(str);}/*** Constructs a string buffer that contains the same characters* as the specified {@code CharSequence}. The initial capacity of* the string buffer is {@code 16} plus the length of the* {@code CharSequence} argument.* <p>* If the length of the specified {@code CharSequence} is* less than or equal to zero, then an empty buffer of capacity* {@code 16} is returned.** @param seq the sequence to copy.* @since 1.5*/public StringBuffer(CharSequence seq) {this(seq.length() + 16);append(seq);}@Overridepublic synchronized int length() {return count;}@Overridepublic synchronized int capacity() {return value.length;}而StringBuffer同樣是繼承一個抽象父類AbstractStringBuilder,它的底層結構同樣是可變的char[] value數組也沒有實現Comparable接口。
StringBuffer和StringBuilder雖然結構是一樣的,但還是有不同點。StringBuffer多了幾樣東西。
如:
1、toStringCache它是用于執行toString()方法時,把值保存到變量中,下次繼續執行toString()方法時,可以直接從變量中取出來。變量是transient 修飾的,代表著不可序列化。
2、還有一個本質上的區別,StringBuffer的方法是synchronized修飾的,代表著是線程安全的。
二、性能效率
String
我這里使用for循環,每循環一次,都往str中拼接字符串"a",總共循環10萬次。執行時間達到了平均11秒,太可怕了,效率實在太慢太慢了。
StringBuilder
// StringBuilderStringBuilder str = new StringBuilder("");long oldTime = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {str.append("a");}System.out.printf("耗時:%d ms",(System.currentTimeMillis() - oldTime));我這里使用StringBuilder的append方法進行拼接字符串,拼接1000萬次,平均執行時間只需279毫秒,這里對比String可以看出,在大量拼接字符串的時候,String的劣勢很明顯。
當然StringBuilder雖然夠快,但也有他的劣勢,在多線程的環境下是線程不安全的。
StringBuffer
// StringBufferStringBuffer str = new StringBuffer("");long oldTime = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {str.append("a");}System.out.printf("耗時:%d ms",(System.currentTimeMillis() - oldTime));這里同樣使用StringBuffer拼接字符串,同樣1000萬次,耗時平均550毫秒。雖然它沒有StringBuilder快,但是它可以保證線程安全,我們前面講過StringBuffer的方法是synchronized修飾的。當然線程安全就代表著它性能效率會被降低了,因為我們的線程需要去競爭鎖,競爭到鎖的線程才可以執行,雖然有偏向鎖,性能難免會被降低。
三、內存分配
JVM內存區域劃分如下(自畫,如果有覺得錯的地方,可以私信我修正哈)
String
String str = “a” + “b” + “c”; //我們以這段代碼為例,我們來看看內存中是如何分配的
【總所周知,字符串常量池在JDK7中從方法區搬到了堆中!】
(字面量:字符串常量池中帶"“雙引號的字,如"a”、“b”、"c"都是字面量)
我們可以看到,在使用String進行拼接不同字符串的時候,每次拼接相連,都會在常量池中創建相應的字面量。這是因為String的value是final修飾的,并不能直接修改,所以會一直創建新的對象,并重新進行賦值。
在JDK9中,String底層是“byte[]”,并不是“char[]”了,這樣做的目的就是可以通過編碼的方式來存儲,可以減少內存的占用和提高性能,我測試過性能快了不止一倍。
總結
以上是生活随笔為你收集整理的String、StringBuilder、StringBuffer的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RocketMQ实战与原理---安装、部
- 下一篇: 英语语法---名词详解