java stringbuffer长度限制_Java中的String、StringBuffer和StringBuilder
作為作為一個已經入了門的java程序猿,肯定對Java中的String、StringBuffer和StringBuilder都略有耳聞了,尤其是String 肯定是經常用的。但肯定你有一點很好奇,為什么java中有三個關于字符串的類?一個不夠嗎!先回答這個問題,黑格爾曾經說過——存在必合理,單純一個String確實是不夠的,所以要引入StringBuffer。再后來引入StringBuilder是另一個故事了,后面會詳細講到。
要了解為什么,我們就得先來看下這三者各自都有什么樣的特點,有什么樣的異同,對其知根知底之后,一切謎團都會被解開。
String
點開String的源碼,可以發現String被定義為final類型,意味著它不能被繼承,再仔細看其提供的方法,沒有一個能對原始字符串做任何操作的,有幾個開啟了貌似是操作原字符串的,比如replaceFirst replaceAll,點進去一看,其實是重新生成了一個新的字符串,對原始內容沒有做任何修改。
是的,從實現的角度來看,它是不可變的,所有String的變更其實都會生成一個新的字符串,比String str = "abcdefghijklmnopqrstuvwxy"; str = str + "z"; 之后新生成的a-z并不包含原來的a-y,原來的a-y已經變成垃圾了。簡單概括,只要是兩個不同的字符,肯定都是兩個完全不同不相關的對象,即便其中一個是從另一個subString出來的,兩個也沒有任何關系。 如果是兩個相同的字符串,情況比較復雜,可能是同一份也可能不是。如果在JVM中使用G1gc,而且開啟-XX:+UseStringDeduplication ,JVM會對字符串的存儲做優化,所以如果你的服務中有大量相同字符串,建議開啟這個參數。
Java作為一個非純面向對象的語言,除了提供分裝對象外,也提供了一些原始類型(比如:int long double char),String的使用居然可以像用原始類型一樣不需要new,直接String str = "a"這樣聲明,我覺得String更像是面向對象和非面向對象結合的一個產物。
String最大的特點就是 不可變,這是它的優點,因為不可變意味著使用簡單,沒有線程安全的問題。 但這也是它的缺點,因為每次變更都會生成一個新的字符串,明顯太浪費空間了。
StringBuffer
我覺得StringBuffer是完全因為String的缺點而生的。我們日常使用String的過程中,肯定經常會用到字符串追加的情況,按String的實現,沒次追加即便只是一個字符,都是生成一個完全不同的對象,如果這次操作很頻繁很多的話會大幅提高內存的消耗,并且增加gc的壓力。對于這種問題,StringBuffer是如何解決的呢?我們直接從源碼上來看。
但看StringBuffer里,幾乎所有的方法都會調super父類,其實它所有的實現都是在AbstractStringBuilder里的。鑒于我們對其最長用的方法是append,所以我們就從append入手,其實append也是StringBuffer比較核心的功能。
/** * The value is used for character storage. */ char[] value; AbstractStringBuilder(int capacity) { value = new char[capacity]; } 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; } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }原來是StringBuffer父類AbstractStringBuilder有個char數組value,用來存放字符串所有的字符,StringBuffer默認初始大小是16。StringBuffer在每次append的時候,如果value的容量不夠,就會申請一個容量比當前所需大一倍的字符數組,然后把舊的數據拷貝進去。這種一次性擴容一倍的方式,在我們之前https://xindoo.blog.csdn.net/article/details/82555800中已經看到過了。一次性多申請內存,雖然看起來會有大段的內存空閑,但其實可以減少String append時頻繁創建新字符串的問題。
所以記住,如果你代碼中對String頻繁操作,千萬不用用String而是選擇用StringBuffer或者我們下面要講的StringBuilder。還有一個優化點,如果你能提前知道你字符串最大的長度,建議你在創建StringBuffer時指定其capacity,避免在append時執行ensureCapacityInternal,從而提升性能。
對于StringBuffer還有一個點沒提到,注意看它源碼的所有方法,除構造函數外,所有的方法都被synchronized修飾,意味著它是有個線程安全的類,所有操作查詢方法都會被加同步,但是如果我們只是單線程呢,想用StringBuffer的優勢,但又覺得加同步太多余,太影響性能。這個時候就輪到StringBuilder上場了。
StringBuilder
StringBuilder從類圖上看和StringBuffer完全沒有任何區別,再打開它的源碼,和StringBuffer一樣幾乎啥邏輯都沒有,全是調調super父類AbstractStringBuilder,它和StringBuffer最大的區別就是所有方法沒有用synchronized修復,它不是一個線程安全的類,但也意味著它沒有同步,在單線程情況下性能會優于StringBuffer。
總結
看完上面內容,我覺得你應該知道上面時候用String、什么時候用StringBuffer、什么時候用StringBuilder了。
彩蛋
我們來看個比較底層的東西,是關于jvm對String優化的,現在有如下代碼。
public class StringTest { public static void main(String[] args) { String str = "abc"; str = str + "d"; str = str + "e"; }}我們用javac StringTest.java編譯成class文件,然后用 javap -c StringTest 生成字節碼,內容如下
public class StringTest { public StringTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String abc 2: astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."":()V 10: aload_1 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #6 // String d 16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: return}? java git:(master) ? javap -c StringTestCompiled from "StringTest.java"public class StringTest { public StringTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String abc 2: astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."":()V 10: aload_1 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #6 // String d 16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: return}? java git:(master) ? javac StringTest.java? java git:(master) ? javap -c StringTest Compiled from "StringTest.java"public class StringTest { public StringTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String abc 2: astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."":()V 10: aload_1 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #6 // String d 16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: new #3 // class java/lang/StringBuilder 26: dup 27: invokespecial #4 // Method java/lang/StringBuilder."":()V 30: aload_1 31: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 34: ldc #8 // String e 36: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 39: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 42: astore_1 43: return}其實可以看出,java底層實現字符串+的時候其實是用StringBuilder的append()來實現的,如果有字符串的連續+,jvm用StringBuilder append也可以實現優化。
備注:源碼來自JDK11版權聲明:本文為博主原創文章,轉載請注明出處。 博客地址:https://xindoo.blog.csdn.net/
總結
以上是生活随笔為你收集整理的java stringbuffer长度限制_Java中的String、StringBuffer和StringBuilder的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NiceScroll文档阅读笔记-Nic
- 下一篇: mui 头部横向滚动菜单