
而StringBuffer與StringBuilder雖也是final,但都是繼承自AbstractStringBuilder,其append實現方法都是重寫AbstractStringBuilder里的。2、線程安全與不安全String中的對象是不可變的,可看為常量,所以是線程安全的StringBuffer也是線程安全的。其主要方法都加了synchronized,顯然線程安全。部分源碼如下:
而StringBuilder的方法沒有加synchronized,在多線程下是不安全的。線程安全與不安全造成了StringBuilder與StringBuffer在效率方面有區別。這三者的速度排序是這樣的:String<StringBuffer<StringBuilder所以,在經常要操作字符串的情況下,多線程下,盡量用StringBuffer,單線程下,則盡量使用StringBuilder或許會有疑問:String為什么是最慢的,String不是經常看到String = str1+str2嗎?為什么是不可變的?其實jvm在實現String的加減并不是簡單的加減。Jvm有一個常量池,用來存放常量,并且是線程共享的。如:String s1= "abc";String s2= "abc";實際上jvm會在常量池創建“abc”這個常量對象。而s2再次賦值為abc時,jvm會先到常量池查找,找到后,并不會再次創建這個對象,而只是返回了abc這個對象的引用而已,即s1和s2此時指的同一個對象,其值也是一樣。String s3 = new String("abc");此時創建兩個對象,一個存放在堆中(String對象),一個存放在常量池中("abc"),還有一個對象引用s3,存放在棧。這個時候如果在new一個對象,如下:String s4 = new String("abc");此時只創建一個對象,和存放在棧上的引用s4,jvm檢測到常量池里存有abc了,直接把abc引用給了s4.String s5 = "ab"+"cd";這個加法編譯時會自動優化了。因為兩個常量的值都是已經確定了的。相當于String s5="abcd";所以這個過程還是很快的但是如果是下面的加法;String s6 = "ab";String s7 = "cd";String s8 = s6+s7;String s9 ="abcd";則可就不一樣了。s6和s7都是對象,編譯時其值不是確定的,所以不會自動優化。而底層對這個加法的實現是這樣的。運行時jvm創建一個StringBuilder。并用s6所指的字符串完成初始化,然后用這個StringBuilder對象調用append方法合并s7的字符串cd,在調用StringBuilder的toString方法完成類型轉換,形成的新對象即引用給s8。這會導致s8!=s9.所以String的加法整體上說沒有StringBuffer和StringBuilder的效率高。final String s1 = "cd;String s2= "ab" + s1;String s3 = "abcd";System.out.PRintln("s2 = s3 : "+ (s2 == s3)); 上面的str1在編譯時會被認為是常量,所以s2+s1這里會被編譯優化。所以導致最后s2和s3是同一個對象。運行結果為true
新聞熱點
疑難解答