字串String的+和+=及迴圈操作String的原理
String物件是不可變的:意思就是無論是對String的新增或修改,出現一個全新的String內容時,都意味著誕生了一個新的物件。但是如果內容不變的話,增加的只是物件的引用而已。
例如:
String a = "ljh"; String b = "ljh"; String c = "ljh"; System.out.println(a==b); System.out.println(b==c);
結果都是true
但是這種不可變性會產生一些效能上的問題,所以JVM對String物件過載“+”“+=”進行了一些優化
操作符“+”可以用來連線String
String aaa = "ljh"; Stringbbb = "big"; String ccc = aaa+bbb+"aaaa";
在jdk8中,上述程式碼中在底層其實是編譯器擅自呼叫了StringBuilder類進行+的操作,主要原因是StringBuilder的append()更加高效,我們來看一下位元組碼。
public static void main(java.lang.String[]); Code: 0: ldc #2 // String ljh 2: astore_1 3: ldc #3 // String big 5: astore_2 6: new #4 // class java/lang/StringBuilder 9: dup 10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 13: aload_1 14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 17: aload_2 18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: ldc #7 // String aaaa 23: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 26: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 29: astore_3 30: return
可以看出一共有四個物件,分別是三個String 和一個StringBuilder
我們再來看一下+=
String a = "aaa"; a += "bbb";
位元組碼如下
Code: 0: ldc #2 // String aaa 2: astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 10: aload_1 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #6 // String bbb 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
可以看出先建立了一個“aaa”字串,然後當a遇到+=時,建立了一個StringBuilder物件,並append了aaa字串。之後建立了一個“bbb”物件,然後append了bbb字串,最後呼叫StringBuilder的toString方法。
接下來再看看迴圈中呼叫+=會是什麼樣子
String a = "aaa"; a += "bbb"; for(int i=0;i<5;i++){ a+="ccc"; }
Code:
0: ldc #2 // String aaa
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String bbb
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: iconst_0
24: istore_2
25: iload_2
26: iconst_5
27: if_icmpge 56
30: new #3 // class java/lang/StringBuilder
33: dup
34: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
37: aload_1
38: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: ldc #8 // String ccc
43: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
49: astore_1
50: iinc 2, 1
53: goto 25
56: return
可以看出先建立String物件aaa,之後建立StringBuilder並初始化StringBuilder append aaa,然後建立bbb物件,並append( bbb),然後我們發現在迴圈中依舊建立了一個新的StringBuilder,也就是沒經過一次迴圈都要建立一個新的StringBuilder物件。
這時我們做一個優化,提前建立StringBuilder物件
String a = "aaa"; a += "bbb"; StringBuilder sb = new StringBuilder(a); for(int i=0;i<5;i++){ sb.append("ccc"); }
Code:
0: ldc #2 // String aaa
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String bbb
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: aload_1
28: invokespecial #8 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
31: astore_2
32: iconst_0
33: istore_3
34: iload_3
35: iconst_5
36: if_icmpge 52
39: aload_2
40: ldc #9 // String ccc
42: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
45: pop
46: iinc 3, 1
49: goto 34
52: return
可以看出迴圈體跳回34行,並不會不斷地建立新的StringBuilder,大大提高了效率和減小了垃圾數量!,所以我們要注意自己的寫法!避免無謂的消耗相關推薦
字串String的+和+=及迴圈操作String的原理
String物件是不可變的:意思就是無論是對String的新增或修改,出現一個全新的String內容時,都意味著誕生了一個新的物件。但是如果內容不變的話,增加的只是物件的引用而已。例如:String a = "ljh"; String b = "ljh"; String c
氣泡排序和字串(String)物件及處理字串的方法
氣泡排序 第一種方法 var times=0; var arr=[12,3,6,9,77,37]; for(var i=0;i<arr.length-1;i++){ //控制比較的行數 for (var j=0;j<arr.length-i-1;j+
四:Java之字符串操作String、StringBuffer和StringBuilder
equal const wstring str asi 有時 string對象 階段 stringbu string是我們經經常使用到的一個類型,事實上有時候認為敲代碼就是在重復的操作字符串,這是C的特點,在java中。jdk非常好的封裝了關於字符串的操
String[]和List<String>的區別及相互轉換
Hello,everybody。好幾天不見啦,我一直在想著怎麼整場大戲,琢磨寫個好點的文章。(其實是因為玩了一個星期,emmmm,因為懶)。 1.兩者的區別 結構方面: List< String >:泛型,非定長,可變。 String[]:陣列,定長,不可
matlab 迴圈儲存變數為.mat 以及save函式報錯:錯誤使用 save 引數必須包含字串(Argument must contain a string.)的處理辦法
目的是儲存一組名稱連續的.mat資料做深度學習用。 直接上程式碼: for i = 1 : 1 : loop_num T(:, :, i) = data(:, :, i); name = ['your_path/test_', num2str(i), '.ma
java中String字串拼接“+”和StringBuffer的效率對比
1、前言 (1)最近在做資料傳輸時,由於接收的資料量較大,在字串拼接時使用了以前感覺方便的“+”進行字串拼接,最後拼接到最後時間越來越多,導致效率變慢。 2、String拼接 首先來看一下兩個String用“+”號拼接需要的時間 String aa="E0 00 00 00 00
javasc中字串(String)物件及處理字串的方法
字串的屬性 length 的介紹: 在JavaScript 中,對於字串來說,要掌握的屬性就只有一個,那就是 length 屬性.我們可以通過 length屬性來獲取字串的長度. 語法:字串名稱.length 說明:length 屬性很簡單,但是在字串操作中經常要用到,這個大家一定
字串格式的方法%s、format和python3.6新特性f-string和型別註解
一、%s msg = '我叫%s,今年%s,性別%s' %('帥哥',18,'男') print(msg) # 我叫帥哥,今年18,性別男 二、format # 三種方式: # 第一種:按順序接收引數 s1 = '我叫{},今年{},性別{}'.for
String字串 切割和替換
public static void main(String[] args) { String str = "adb,de,fg"; /** * 在當前字串中,用後面的替換掉字串中所有出現的前面的,返回新的字串 */ String replace =
論 java中String 和 new String還有物件中的String字串在記憶體中的儲存
一直以來,所有人都說,java中的String型別是不可變的,可是為什麼不可變確很少有人說的透徹,String和new String的區別,物件中的String和直接定義一個String是否有區別,一直都是一知半解。看了很多文件都是各種猜測,沒有具體程式碼來
BigDecimal轉String,int,double及簡單操作運算、方法
BigDecimal b = new BigDecimal(12.10); //BigDecimal 轉換成 string資料型別 string c = b.toString(); //BigDeci
C++中字串string和整數int的互相轉化方式
Talk is cheap, show me the code. 一、string轉int的方式 採用最原始的string, 然後按照十進位制的特點進行算術運算得到int,但是這種方式太麻
python的字串(String)及其常見操作(方法、函式)
字串(string) -----------------------------------------------------------------------------------------------------------------------------------------
字串 String和StringBuffer的區別(從程式碼講解)
Java面試中經常問到字串,下面是根據百度面試整理出來的內容: 一、String和StringBuffer有什麼區別? String的長度是不可變的,StringBuffer的長度是可變的。 如果你對字串中的內容經常進行操作,特別是內容要修改時,那麼使用StringBuff
Java入門之API的使用及String 和StringBuilder類的常見方法
API:學習JAVA幫助文件;使用步驟:1.開啟API文件;2.點選左上角顯示按鈕3.點選索引標籤,在輸入框內輸入你要學習的內容;學習一個新的類的步驟:1.看類的宣告:搞清楚這個類的一個修飾情況(繼承,實現)2.看類的說明:看這個類的功能描述;3.看類的構造方法摘要:瞭解建
Object類中的toString()方法和equals()方法,String類中的equals()方法和==常量符號,StringBuffer帶緩衝的字串
1、Object類中toString() 所有的類都預設的繼承了Object類 Object類中的toString方法返回的是類的名字和該物件雜湊碼組成的字串 System.out.printf(類物件名)實際輸出的是該物件的toString()方法所返回的字串 為了實際需求需要子類重寫父類
Redis支持的五種數據類型及相應操作:String(字符串),Hash(哈希),List(列表),Set(集合)及zset(sorted set:有序集合)
list 支持 哈希 keys 當前 zset 存在 key-value second key 命令(key命令:用於管理 redis 的key)相應操作: key 命令 說明 del key [key...] dump key 序列化給定 key
C++中string類及檔案流類(ofstream,ifstream)的基本操作---按行讀取文件
先說明一個問題:java構建物件只能使用new的方法,而C++則不然。 下面程式碼實現讀取test.txt檔案中的內容並顯示,同時將某一個字串輸入到檔案test1.txt中。 函式getline(ifstream& param1, string& param
matlab:字串陣列和string的區別
前言 在用sprintf()格式化輸出時,發現formatSpec可以是單引號建立的字串陣列,也可以是string(‘str’)建立的string。所以產生了疑惑,這兩者有什麼區別,各適用在什麼場合 官方文件 Character arrays and st
C#: 字串string和位元組陣列byte[]的轉換
string轉byte[]: byte[] byteArray = System.Text.Encoding.Default.GetBytes ( str ); byte[]轉string: string str = System.Text.Encoding.Default.GetStri