<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    和風(fēng)細(xì)雨

    世上本無難事,心以為難,斯乃真難。茍不存一難之見于心,則運(yùn)用之術(shù)自出。

    特殊的String

     

    String的特殊之處

    String是Java編程中很常見的一個類,這個類的實(shí)例是不可變的(immutable ).為了提高效率,JVM內(nèi)部對其操作進(jìn)行了一些特殊處理,本文就旨在于幫助大家辨析這些特殊的地方.
    在進(jìn)入正文之前,你需要澄清這些概念:
    1) 堆與棧
    2) 相同與相等,==與equals
    3) =的真實(shí)意義.

    棧與堆

    1. 棧(stack)與堆(heap)都是Java用來在內(nèi)存中存放數(shù)據(jù)的地方。與C++不同,Java自動管理?xiàng):投眩绦騿T不能直接地設(shè)置?;蚨?。每個函數(shù)都有自己的棧,而一個程序只有一個堆.
    2. 棧的優(yōu)勢是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。另外,棧數(shù)據(jù)可以共享,詳見第3點(diǎn)。堆的優(yōu)勢是可以動態(tài)地分配內(nèi)存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數(shù)據(jù)。但缺點(diǎn)是,由于要在運(yùn)行時動態(tài)分配內(nèi)存,存取速度較慢。 3. Java中的數(shù)據(jù)類型有兩種。   一種是基本類型(primitive types), 共有8種,即int, short, long, byte, float, double, boolean, char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動變量。值得注意的是,自動變量存的是字面值,不是類的實(shí)例,即不是類的引用,這里并沒有類的存在。如int a = 3; 這里的a是一個指向int類型的引用,指向3這個字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值固定定義在某個程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。   另外,棧有一個很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。假設(shè)我們同時定義   int a = 3;    int b = 3;   編譯器先處理int a = 3;首先它會在棧中創(chuàng)建一個變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個存放3這個字面值的地址,然后將a指向3的地址。接著處理int b = 3;在創(chuàng)建完b的引用變量后,由于在棧中已經(jīng)有3這個字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時均指向3的情況。   特別注意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變量修改了這個對象的內(nèi)部狀態(tài),那么另一個對象引用變量也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導(dǎo)致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與 b的值后,再令a=4;那么,b不會等于4,還是等于3。在編譯器內(nèi)部,遇到a=4;時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。   另一種是包裝類數(shù)據(jù),如Integer, String, Double等將相應(yīng)的基本數(shù)據(jù)類型包裝起來的類。這些類數(shù)據(jù)全部存在于堆中,Java用new()語句來顯示地告訴編譯器,在運(yùn)行時才根據(jù)需要動態(tài)創(chuàng)建,因此比較靈活,但缺點(diǎn)是要占用更多的時間。

    相同與相等,==與equals

    在Java中,相同指的是兩個變量指向的地址相同,地址相同的變量自然值相同;而相等是指兩個變量值相等,地址可以不同.
    相同的比較使用==,而相等的比較使用equals.
    對于字符串變量的值比較來說,我們一定要使用equals而不是==.

    =的真實(shí)意義

    =即賦值操作,這里沒有問題,關(guān)鍵是這個值有時是真正的值,有的是地址,具體來說會根據(jù)等號右邊的部分而變化.
    如果是基本類型(八種),則賦值傳遞的是確定的值,即把右邊變量的值傳遞給左邊的變量.
    如果是類類型,則賦值傳遞的是變量的地址,即把等號左邊的變量地址指向等號右邊的變量地址.

    指出下列代碼的輸出

    String andy="andy";
    String bill="andy";

    if(andy==bill){
      System.out.println("andy和bill地址相同");
    }
    else{
      System.out.println("andy和bill地址不同");
    }

    String str=“andy”的機(jī)制分析

    上頁代碼的輸出是andy和bill地址相同.
    當(dāng)通過String str=“andy”;的方式定義一個字符串時,JVM先在棧中尋找是否有值為“andy”的字符串,如果有則將str指向棧中原有字符串的地址;如果沒有則創(chuàng)建一個,再將str的地址指向它. String andy=“andy”這句代碼走的是第二步,而String bill=“andy”走的是第一步,因此andy和bill指向了同一地址,故而andy==bill,andy和bill地址相等,所以輸出是andy和bill地址相同.
    這樣做能節(jié)省空間—少創(chuàng)建一個字符串;也能節(jié)省時間—定向總比創(chuàng)建要省時.

    指出下列代碼的輸出

    String andy="andy";
    String bill="andy";
    bill="bill";

    if(andy==bill){
      System.out.println("andy和bill地址相同");
    }
    else{
      System.out.println("andy和bill地址不同");
    }

    輸出及解釋

    上頁代碼的輸出是:andy和bill地址不同
    當(dāng)執(zhí)行bill=“bill”一句時,外界看來好像是給bill變換了一個新值bill,但JVM的內(nèi)部操作是把棧變量bill的地址重新指向了棧中一塊值為bill的新地址,這是因?yàn)樽址闹凳遣豢勺兊?要換值(賦值操作)只有將變量地址重新轉(zhuǎn)向. 這樣andy和bill的地址在執(zhí)行bill=“bill”一句后就不一樣了,因此輸出是andy和bill地址不同.

    指出下列代碼的輸出

    String andy=new String("andy");
    String bill=new String("andy");

    // 地址比較
    if(andy==bill){
      System.out.println("andy和bill地址相同");
    }
    else{
      System.out.println("andy和bill地址不同");
    }

    // 值比較
    if(andy.equals(bill)){
      System.out.println("andy和bill值相等");
    }
    else{
      System.out.println("andy和bill值不等");
    }

    輸出及機(jī)制分析

    andy和bill地址不同
    andy和bill值相等
    我們知道new操作新建出來的變量一定處于堆中,字符串也是一樣.
    只要是用new()來新建對象的,都會在堆中創(chuàng)建,而且其字符串是單獨(dú)存值的,即每個字符串都有自己的值,自然地址就不會相同.因此輸出了andy和bill地址不同.
    equals操作比較的是值而不是地址,地址不同的變量值可能相同,因此輸出了andy和bill值相等.

    指出下列代碼的輸出

    String andy=new String("andy");
    String bill=new String(andy);

    // 地址比較
    if(andy==bill){
      System.out.println("andy和bill地址相同");
    }
    else{
      System.out.println("andy和bill地址不同");
    }

    // 值比較
    if(andy.equals(bill)){
      System.out.println("andy和bill值相等");
    }
    else{
      System.out.println("andy和bill值不等");
    }


    輸出

    andy和bill地址不同
    andy和bill值相等

    道理仍和第八頁相同.只要是用new()來新建對象的,都會在堆中創(chuàng)建,而且其字符串是單獨(dú)存值的,即每個字符串都有自己的值,自然地址就不會相同.

    指出下列代碼的輸出

    String andy="andy";
    String bill=new String(“Bill");
    bill=andy;

    // 地址比較
    if(andy==bill){
      System.out.println("andy和bill地址相同");
    }
    else{
      System.out.println("andy和bill地址不同");
    }

    // 值比較
    if(andy.equals(bill)){
      System.out.println("andy和bill值相等");
    }
    else{
      System.out.println("andy和bill值不等");
    }


    輸出及解析

    andy和bill地址相同
    andy和bill值相等
    String bill=new String(“Bill”)一句在棧中創(chuàng)建變量bill,指向堆中創(chuàng)建的”Bill”,這時andy和bill地址和值都不相同;而執(zhí)行bill=andy;一句后,棧中變量bill的地址就指向了andy,這時bill和andy的地址和值都相同了.而堆中的”Bill”則沒有指向它的指針,此后這塊內(nèi)存將等待被垃圾收集.


    指出下列代碼的輸出

    String andy="andy";
    String bill=new String("bill");
    andy=bill;

    // 地址比較
    if(andy==bill){
      System.out.println("andy和bill地址相同");
    }
    else{
      System.out.println("andy和bill地址不同");
    }

    // 值比較
    if(andy.equals(bill)){
      System.out.println("andy和bill值相等");
    }
    else{
      System.out.println("andy和bill值不等");
    }

    輸出

    andy和bill地址相同
    andy和bill值相等

    道理同第十二頁

    結(jié)論

    使用諸如String str = “abc”;的語句在棧中創(chuàng)建字符串時時,str指向的字符串不一定會被創(chuàng)建!唯一可以肯定的是,引用str本身被創(chuàng)建了。至于這個引用到底是否指向了一個新的對象,必須根據(jù)上下文來考慮,如果棧中已有這個字符串則str指向它,否則創(chuàng)建一個再指向新創(chuàng)建出來的字符串. 清醒地認(rèn)識到這一點(diǎn)對排除程序中難以發(fā)現(xiàn)的bug是很有幫助的。
    使用String str = “abc”;的方式,可以在一定程度上提高程序的運(yùn)行速度,因?yàn)镴VM會自動根據(jù)棧中數(shù)據(jù)的實(shí)際情況來決定是否有必要創(chuàng)建新對象。而對于String str = new String(“abc”);的代碼,則一概在堆中創(chuàng)建新對象,而不管其字符串值是否相等,是否有必要創(chuàng)建新對象,從而加重了程序的負(fù)擔(dān)。
    如果使用new()來新建字符串的,都會在堆中創(chuàng)建字符串,而且其字符串是單獨(dú)存值的,即每個字符串都有自己的值,且其地址絕不會相同
    當(dāng)比較包裝類里面的數(shù)值是否相等時,用equals()方法;當(dāng)測試兩個包裝類的引用是否指向同一個對象時,用==。
    由于String類的immutable性質(zhì),當(dāng)String變量需要經(jīng)常變換其值如SQL語句拼接,HTML文本輸出時,應(yīng)該考慮使用StringBuffer類,以提高程序效率。

    posted on 2008-04-29 15:10 和風(fēng)細(xì)雨 閱讀(401) 評論(0)  編輯  收藏 所屬分類: J2SE

    主站蜘蛛池模板: 四虎永久在线精品免费网址| 一区二区三区免费视频网站| 亚洲AV综合色区无码一区| 国产2021精品视频免费播放| 中文字幕亚洲无线码a| 国产日韩精品无码区免费专区国产| 免费看一级做a爰片久久| 在线观看亚洲免费| 哒哒哒免费视频观看在线www | 亚洲电影日韩精品| 黄网站在线播放视频免费观看 | 亚洲精品tv久久久久久久久| 国产无遮挡无码视频免费软件| 亚洲国产精品无码久久久秋霞2| 国产成人AV片无码免费| 亚洲美女视频一区| 成人免费毛片内射美女-百度| 亚洲日本一线产区和二线| 又大又黄又粗又爽的免费视频| 亚洲五月丁香综合视频| 亚洲男人电影天堂| 亚洲国产婷婷综合在线精品| 91亚洲导航深夜福利| 一级特黄录像视频免费| 亚洲AV无码一区二区乱子伦| 亚洲成人免费电影| 亚洲av无码成人精品区一本二本 | 在线a毛片免费视频观看| 青青青视频免费观看| 久久亚洲精品国产精品黑人| 久久不见久久见免费影院| 国产精品亚洲片在线花蝴蝶| 亚洲av中文无码乱人伦在线咪咕 | 永久免费毛片在线播放| 男女猛烈xx00免费视频试看| 亚洲国产精品特色大片观看完整版| 久久久高清免费视频| 国产免费人成视频尤勿视频| 亚洲成a人片毛片在线| 亚洲国产精品国产自在在线| 狼群影院在线观看免费观看直播|