1. 程式人生 > >Java 深究字串String類(1)之運算子"+"過載

Java 深究字串String類(1)之運算子"+"過載

一.不可改變String

String物件是不可改變的,
檢視JDK文件,發現String類中每一個看似修改String的方法,實際上都建立了一個新的String物件,而最初的String物件則絲毫未動.

java傳遞引數的時候,傳遞的是引用的一個拷貝,呼叫時,都會複製一份引用,而引用所指向的物件,一直呆在某一單一物理位置,從未變動過.

二.過載 “+” 與 StringBuilder

String物件是不可改變的,你可以給一個String物件加任意多的別名.
String物件是隻讀的,所要指向它的任何引用都不可能改變它的值.so不會對其他引用產生什麼卵影響.
用於String類中的”+” / “+=” 是Java中僅有的兩個過載過的操作符,而java並不允許我們過載任何操作符;

public class one {
    public static void main(String[] args) {
        String a = "abc";
        String b = "123" + a + "def" + 777;
        System.out.println(b);
    }
}

如上程式碼,可能這樣工作:
String有append方法,然後返回一個新的String物件的引用,以包含連線後的字串,然後再append , 再建立新物件.
這種方式當然行得通,但是為了生成最終的String,次方式會產生一堆需要垃圾回收的中間物件.然後發現其效能略lowBi.那麼編譯器真的會這樣做嗎?

來來~~,反編譯生成的.class

javap -c one.class
這是JDK自帶的工具 javap -c引數生成位元組碼

這裡寫圖片描述

懂點彙編就行,,dup,invokevirtural 就是jvm上的彙編.

看好了:
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder.””:()V
10: ldc #5 // String 123
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

編譯器自動引用java.lang.StringBuilder類,用以構造最終的String,為每個”+”呼叫一次append方法,最後呼叫toString方法生成最終的String並儲存

三.what if 在迴圈裡使用”+”呢

經過實驗發現:

1.這樣寫:

String str = "";
for(int i = 0; i < num; i++)
{
    str += "a";
}

javap -c

這裡寫圖片描述

5~33是迴圈體, 15句建立一個StringBuilder物件

可知StringBuilder在迴圈體內構建,每次迴圈,建立新的StringBuilder

2.這樣寫:

 StringBuilder a = new StringBuilder();
for(int i = 0; i < 10; i++)
{
    a.append(i); //只有String能"+"
}

這裡寫圖片描述
只建立一個StringBuilder類

所以以後寫的時候就知道咋回事了.