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

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

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

    和風細雨

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

    特殊的String

     

    String的特殊之處

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

    棧與堆

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

    相同與相等,==與equals

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

    =的真實意義

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

    指出下列代碼的輸出

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

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

    String str=“andy”的機制分析

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

    指出下列代碼的輸出

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

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

    輸出及解釋

    上頁代碼的輸出是:andy和bill地址不同
    當執行bill=“bill”一句時,外界看來好像是給bill變換了一個新值bill,但JVM的內部操作是把棧變量bill的地址重新指向了棧中一塊值為bill的新地址,這是因為字符串的值是不可變的,要換值(賦值操作)只有將變量地址重新轉向. 這樣andy和bill的地址在執行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值不等");
    }

    輸出及機制分析

    andy和bill地址不同
    andy和bill值相等
    我們知道new操作新建出來的變量一定處于堆中,字符串也是一樣.
    只要是用new()來新建對象的,都會在堆中創建,而且其字符串是單獨存值的,即每個字符串都有自己的值,自然地址就不會相同.因此輸出了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()來新建對象的,都會在堆中創建,而且其字符串是單獨存值的,即每個字符串都有自己的值,自然地址就不會相同.

    指出下列代碼的輸出

    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”)一句在棧中創建變量bill,指向堆中創建的”Bill”,這時andy和bill地址和值都不相同;而執行bill=andy;一句后,棧中變量bill的地址就指向了andy,這時bill和andy的地址和值都相同了.而堆中的”Bill”則沒有指向它的指針,此后這塊內存將等待被垃圾收集.


    指出下列代碼的輸出

    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值相等

    道理同第十二頁

    結論

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

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

    主站蜘蛛池模板: 337p日本欧洲亚洲大胆艺术| 免费福利在线视频| 亚洲欧洲自拍拍偷午夜色| 国产亚洲精品看片在线观看| 免费看a级黄色片| 亚洲午夜久久久久久噜噜噜| 67194国产精品免费观看| 偷自拍亚洲视频在线观看99| 亚洲av乱码一区二区三区| 亚洲AV日韩AV天堂久久| 国产亚洲视频在线播放| 国产一级一片免费播放| 青苹果乐园免费高清在线| 精品国产免费一区二区三区香蕉 | 一级一级一级毛片免费毛片| 亚洲综合色婷婷在线观看| 亚洲导航深夜福利| 亚洲视频在线一区二区三区| 亚洲精品无码久久久久sm| 亚洲国产成人影院播放| 国产精品公开免费视频| 精品免费国产一区二区三区| 成年性午夜免费视频网站不卡| 在线视频精品免费| 亚洲免费在线视频播放| 99久久免费中文字幕精品| 日本一卡精品视频免费| 国产午夜无码精品免费看| 国产一级a毛一级a看免费人娇| 成人A毛片免费观看网站| 日本在线观看免费高清| 性生大片视频免费观看一级| 香港经典a毛片免费观看看| 边摸边吃奶边做爽免费视频99| 色偷偷亚洲第一综合网| 国产精品亚洲AV三区| 人妻无码中文字幕免费视频蜜桃| 成年网站免费入口在线观看| 人成午夜免费大片在线观看| 一个人看的www视频免费在线观看| www成人免费视频|