2019-09-05

作者來源1
作者來源2

一、字符串拼接方式:+和concat和StringBuilder

源碼:

public static void main(String[] args) {

        String str = "";

        System.out.println("執(zhí)行加號拼接:");
        long starttime = System.currentTimeMillis();
        System.out.println("執(zhí)行拼接之前的時間:"+starttime);
        for (int i = 0; i < 50000; i++) {
            str += "a";
        }
        long latertime = System.currentTimeMillis();
        System.out.println("執(zhí)行拼接之后的時間:"+latertime);
        System.out.println("用加號拼接所花費的時間:"+(latertime - starttime));
        System.out.println("result== " + str);
        System.out.println("--------------------------------");


        String str1 = "";
        System.out.println("執(zhí)行concat拼接:");
        long starttime1 = System.currentTimeMillis();
        System.out.println("執(zhí)行拼接之前的時間:"+starttime1);
        for (int i = 0; i < 50000; i++) {
            str1 = str1.concat("b");
        }
        long latertime1 = System.currentTimeMillis();
        System.out.println("執(zhí)行拼接之后的時間:"+latertime1);
        System.out.println("用加號拼接所花費的時間:"+(latertime1 - starttime1));
        System.out.println("result=="+str1);
        System.out.println("--------------------------------");

        StringBuilder stringBuilder = new StringBuilder();
        System.out.println("執(zhí)行StringBuilder拼接:");
        long starttime2 = System.currentTimeMillis();
        System.out.println("執(zhí)行拼接之前的時間:"+starttime2);
        for (int i = 0; i < 50000; i++) {
            stringBuilder.append("c");
        }
        long latertime2 = System.currentTimeMillis();
        System.out.println("執(zhí)行拼接之后的時間:"+latertime2);
        System.out.println("用加號拼接所花費的時間:"+(latertime2 - starttime2));
        System.out.println("result=="+stringBuilder.toString());


    }

執(zhí)行結果圖:


image.png

由此可見,StringBuilder最快,concat次之,加號拼接最慢。

二、為什么會出現(xiàn)這樣的情況

2.1 "+"方法實現(xiàn)原理

內部實現(xiàn)采用StringBuilder的append方法進行追加,最終以toString方法轉換成String字符串,比如:

String wechat = "Hollis";
String introduce = "每日更新Java相關技術文章";
String hollis = wechat + "," + introduce;

反編譯后的結果如下,反編譯工具為jad。

String wechat = "Hollis";
String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();

通過查看反編譯后的代碼,我們可以發(fā)現(xiàn),在拼接字符串常量中,是將String轉成了StringBuilder后,使用其append方法進行處理,也就是說,,在java中使用“+”對字符串拼接,采用的原理是使用StringBuilder。
但是它與純粹使用StringBuilder的append方法是不同的:
1、每次執(zhí)行循環(huán)添加字符時,它都會創(chuàng)建一個StringBuilder對象,
2、每次執(zhí)行完后都會調用toString方法將其轉換為字符串
所以耗費了更多時間。

2.2 "concat"方法實現(xiàn)原理

concat源代碼

    public String concat(String str) {
        int otherLen = str.length();//獲取添加的字符串長度
        if (otherLen == 0) {//如果字符串長度為0,則返回字符串長度本身
            return this;
        }
        int len = value.length;//獲取原字符串的字符數(shù)組的長度
        char buf[] = Arrays.copyOf(value, len + otherLen);//將原字符串的字符數(shù)組放到buff數(shù)組中
        str.getChars(buf, len);//追加的字符串轉化成字符數(shù)組,添加到buf中
        return new String(buf, true);//產(chǎn)生一個新的字符串返回
    }

整體的實現(xiàn)過程就是完成對數(shù)組的拷貝,雖然在內存中處理是原子性操作,速度非???,但是,最后的return語句創(chuàng)建一個新的String對象,也就是每次concat操作都會創(chuàng)建一個新的String對象,這也是限制concat方法速度的原因。

2.3 "append"方法實現(xiàn)原理

代碼實現(xiàn)

    public AbstractStringBuilder append(String str) {
        if (str == null)//如果是null值,則把null作為字符串處理
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);//追加后的字符數(shù)組長度是否超過當前值
        str.getChars(0, len, value, count);//將字符串復制到目標數(shù)組
        count += len;
        return this;
    }
    private AbstractStringBuilder appendNull() {
        int c = count;
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l'; //將null添加到char[] value數(shù)組中
        count = c; //將count的值初始化
        return this;//返回結果
    }
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));//加長數(shù)組空間,并作數(shù)組拷貝
        }
    }

append方法都在做字符數(shù)組的處理,加長,拷貝等,這些都是基本的數(shù)據(jù)處理,整個方法內并沒有生成對象,只是最后執(zhí)行了toString方法返回了一個對象而已

三、題外

String str = "My name is ";
str = str + "JTZen9";

相當于str = new StringBuilder(str).append("JTZen9").toString();
也就是說,該str = str + "JTZen9",語句執(zhí)行完后,總共有三個對象

String str = "My name is " + "JTZen9";

JVM會直接把str作為一個對象,即“My name is JTZen9”

四、使用場景

1、大多數(shù)情況,我們使用“+”,符合編碼習慣和我們的閱讀
2、當在頻繁進行字符串的運算(如拼接、替換、刪除等),或者在系統(tǒng)性能臨界的時候,我們可以考慮使用concat或append方法

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容