日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

剖析java中的String之__拼接

發(fā)布時間:2023/12/2 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 剖析java中的String之__拼接 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

剖析java中的String之__拼接

分類: java 31人閱讀 評論(0) 收藏 舉報

出處,?http://blog.csdn.net/izard999/article/details/6708433

網(wǎng)上剖析String的不少,關(guān)于其他的String的知識我就不累贅去說了!

本文只解釋下我在面試中遇到的String拼接的問題以及最近看到了網(wǎng)上的一道機試題跟這個有關(guān)系, 所以就想把自己對String拼接的理解分享給大家!??

去華為面試的時候, 第一筆試題就讓我費神去想了, 回來在機子上運行結(jié)果, 發(fā)現(xiàn)自己當(dāng)時答錯了, 于是就狠下心來花了點時間研究這個:

view plain
  • String?s?=?null;??
  • s?+=?"abc";??
  • System.out.println(s);??

  • 答案是nullabc!

    就這三行代碼, 我問了不下于50個人, 有資深的人也有新手的, 在不運行的情況下全答錯了。!? 可見現(xiàn)在學(xué)java的人有很多人都是速成的,而且這種原理級而又看似不怎么實用的東西幾乎沒什么人去研究, 但是后面說的機試如果能知道String拼接的原理的話。將很容易就解決!

    很早的時候我就知道String拼接中間會產(chǎn)生StringBuilder對象(JDK1.5之前產(chǎn)生StringBuffer),但是當(dāng)時也沒有去深究內(nèi)部, 導(dǎo)致在華為筆試此題就錯了!

    運行時, 兩個字符串str1, str2的拼接首先會調(diào)用 String.valueOf(obj),這個Obj為str1,而String.valueOf(Obj)中的實現(xiàn)是return obj == null ? "null" : obj.toString(), 然后產(chǎn)生StringBuilder, 調(diào)用的StringBuilder(str1)構(gòu)造方法, 把StringBuilder初始化,長度為str1.length()+16,并且調(diào)用append(str1)! 接下來調(diào)用StringBuilder.append(str2), 把第二個字符串拼接進去, 然后調(diào)用StringBuilder.toString返回結(jié)果!

    所以那道題答案的由來就是StringBuilder.append("null").append("abc").toString();

    大家看了我以上的分析以后, 再碰到諸如此類的面試題應(yīng)該不會再出錯了!


    那么了解String拼接有什么用呢?

    在做多線程的時候, 往往會用到一個同步監(jiān)視器對象去同步一個代碼塊中的代碼synchronized(Obj),?? 對同一個對象才會互斥,不是同一個對象就不會互斥!

    這里有個機試題,

    現(xiàn)有程序同時啟動了4個線程去調(diào)用TestDo.doSome(key, value)方法,由于TestDo.doSome(key, value)方法內(nèi)的代碼是先暫停1秒,然后再輸出以秒為單位的當(dāng)前時間值,所以,會打印出4個相同的時間值,如下所示:
    ??4:4:1258199615
    ??1:1:1258199615
    ??3:3:1258199615
    ??1:2:1258199615
    ??????? 請修改代碼,如果有幾個線程調(diào)用TestDo.doSome(key, value)方法時,傳遞進去的key相等(equals比較為true),則這幾個線程應(yīng)互斥排隊輸出結(jié)果,即當(dāng)有兩個線程的key都是"1"時,它們中的一個要比另外其他線程晚1秒輸出結(jié)果,如下所示:
    ??4:4:1258199615
    ??1:1:1258199615
    ??3:3:1258199615
    ??1:2:1258199616
    ?? 總之,當(dāng)每個線程中指定的key相等時,這些相等key的線程應(yīng)每隔一秒依次輸出時間值(要用互斥),如果key不同,則并行執(zhí)行(相互之間不互斥)。原始代碼如下:

    view plain
  • package?syn;??
  • ??
  • //不能改動此Test類??????
  • public?class?Test?extends?Thread{??
  • ??????
  • ????private?TestDo?testDo;??
  • ????private?String?key;??
  • ????private?String?value;??
  • ??????
  • ????public?Test(String?key,String?key2,String?value){??
  • ????????this.testDo?=?TestDo.getInstance();??
  • ????????/*常量"1"和"1"是同一個對象,下面這行代碼就是要用"1"+""的方式產(chǎn)生新的對象,?
  • ????????以實現(xiàn)內(nèi)容沒有改變,仍然相等(都還為"1"),但對象卻不再是同一個的效果*/??
  • ????????this.key?=?key+key2;???
  • ????????this.value?=?value;??
  • ????}??
  • ??
  • ??
  • ????public?static?void?main(String[]?args)?throws?InterruptedException{??
  • ????????Test?a?=?new?Test("1","","1");??
  • ????????Test?b?=?new?Test("1","","2");??
  • ????????Test?c?=?new?Test("3","","3");??
  • ????????Test?d?=?new?Test("4","","4");??
  • ????????System.out.println("begin:"+(System.currentTimeMillis()/1000));??
  • ????????a.start();??
  • ????????b.start();??
  • ????????c.start();??
  • ????????d.start();??
  • ????}??
  • ??????
  • ????public?void?run(){??
  • ????????testDo.doSome(key,?value);??
  • ????}??
  • }??
  • ??
  • class?TestDo?{??
  • ??
  • ????private?TestDo()?{}??
  • ????private?static?TestDo?_instance?=?new?TestDo();???
  • ????public?static?TestDo?getInstance()?{??
  • ????????return?_instance;??
  • ????}??
  • ??
  • ????public?void?doSome(Object?key,?String?value)?{??
  • ??
  • ????????//?以大括號內(nèi)的是需要局部同步的代碼,不能改動!??
  • ????????{??
  • ????????????try?{??
  • ????????????????Thread.sleep(1000);??
  • ????????????????System.out.println(key+":"+value?+?":"??
  • ????????????????????????+?(System.currentTimeMillis()?/?1000));??
  • ????????????}?catch?(InterruptedException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • }??
  • 此題解題的思路有很多種,不可或缺的步驟就是在doSome方法內(nèi)部用synchronized(o)把那個寫了注釋的代碼塊同步, 有些人肯定會說:

    我直接synchronized(key),不就完了么.?? 這類人肯定是新手級別的了!

    上面說了,synchronized(Obj),?? 對同一個對象才會互斥,不是同一個對象就不會互斥! 大家請看下Test類中的構(gòu)造方法里面對key做了什么處理?

    this.key = key + key2;

    關(guān)于字符串的拼接,? 如果是兩個常量的拼接, 那么你無論拼接多少下都是同一個對象,? 這個是編譯時?編譯器自動去優(yōu)化的(想知道具體原理的自己去網(wǎng)上搜下).

    view plain
  • String?a?=?"a"?+?"b";??
  • String?b?=?"a"?+?"b";??
  • System.out.println(a?==?b);??
  • 這段代碼輸出true沒有問題

    但是一旦涉及到變量了, 我在上面標(biāo)紅加粗的運行時,??? 此時拼接字符串就會產(chǎn)生StringBuilder,? 然而拼接完返回的字符串是怎么返回的呢?

    在StringBuilder.toString()中的實現(xiàn)是new String(char value[], int offset, int count), 既然是創(chuàng)建String返回的, 那么調(diào)用一次toString,就是一個不同的對象

    view plain
  • String?a?=?"a";??
  • String?b?=?"b";??
  • String?s1?=?a?+?b;??
  • String?s2?=?a?+?b;??
  • System.out.println(s1?==?s2);??
  • 這個輸出就是false!


    所以在那道機試題中, 就不能直接用synchronized(key)去同步了,? 如果你完完全全很耐心的看完本文, 那么應(yīng)該知道如何用synchronized(key)同步那段代碼了!

    不錯, 就是修改Test構(gòu)造方法中的 this.key = key + key2;為this.key = key;

    因為字符串不涉及到拼接的時候, 只要不new, 多少都是指向同一個對象!

    當(dāng)然這道多線程的題你也可以把那個key丟到集合里面去,用集合去的contains(obj)去判斷,如果集合中存在, 就取集合中的, 否則往集合中添加,但是記住一定要使用并發(fā)包下面的集合, 否則可能會拋出ConcurrentModificationException


    總結(jié)

    以上是生活随笔為你收集整理的剖析java中的String之__拼接的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。