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

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

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

    隨筆-126  評論-247  文章-5  trackbacks-0

    前言:
    字符串 (String) 是 java 編程語言中的核心類之一,在我們平常時候使用也比較很普遍,應用廣泛。
    但你是否知道什么是字符串直接量,知不知道有個字符串駐留池,字符串的駐留池可以用來緩存字符串直接量。


    什么是直接量
    直接量是指:在程序中,通過源代碼直接指定的值。
    eg:
    int personId = 8080 ;
    String name = "fancy" ;

    對于 java 中的字符串直接量,JVM 會使用一個字符串駐留池來緩存它們。一般情況下,字符串駐留池中的字符串對象不會被 GC (Garbage Collection,垃圾回收) 所回收,
    當再次使用字符串駐留池中已有的字符串對象時候,無需再次創建它,而直接使它的引用變量
    指向字符串駐留池中已有的字符串對象。

    String 基礎

    String 類代表字符串。字符串是常量,它們的值在創建之后是不能再被更改的。在 java 中除了 synchronized之外,不可變的類也是線程安全的,
    因此,String 類本身也是線程安全的。String 類的實例對象其實是可以被共享的。

    例代碼 

    1
    2        String name = "fancy";                  // @1
    3        String nick    = "fancydeepin"// @2
    4        name = nick;
    5        System.out.println(name);    // export:fancydeepin
    6


    結果輸出 :fancydeepin

    這是怎么回事?不是說 String 是不可變的字符串嗎?怎么這里又變了?
    是這樣的,在這里 name 只是一個引用類型變量,并不是一個 String 對象,@1中創建了一個 "fancy" 的字符串對象,
    @2中創建了一個 "fancydeepin" 的字符串對象,name 引用 (就像一個指針) 剛開始是指向 "fancy" 對象,而后,name 又重新指向 "fancydeepin" 對象,
    在示例代碼中,整個過程只創建了兩個 String 對象 (不知道我這樣說你能不能理解,為什么是只創建了兩個 String 對象?而不是 1個、3個...  @3),
    一個是 "fancy" 對象,另外一個是 "fancydeepin" 對象。而這兩個對象被創建出來后并沒有被改變過,之所以程序會輸出 fancydeepin,完全只是因為
    name 引用所指向的對象發生了改變。

    如果你是本著認真的態度看著我的貼子,細心的你,是否會留意到:
    當 name 引用重新指向另外一個對象的時候,那 name 之前引用的對象 ( "fancy" 對象 ) JVM 在底層會怎么處理它呢?是會立即來回收它來釋放系統資源嗎?
    答案是否定的。雖然這時候程序再也不訪問 "fancy" 這個對象,但 JVM 還是不會來回收它,它將在程序運行期間久駐內存,為什么會這樣呢?
    再往下說就扯到 java 的內存管理機制了,這里點到即止。在這里你可以簡單的將它理解成 "fancy" 對象被緩存了起來 ( 實際上也是因為被緩存了 )。

    字符串駐留池
    當比較兩個 String 對象時候,是應該用 "==" 呢?還是應該選擇 equals 呢?相信絕大部分人絕大多時候使用的都是選擇用 equals 方法。
    "==" 和 equals 的用法相信大家都很熟悉了,"==" 比較的是兩個對象的哈希碼值是否相等,而 equals 比較的是對象的內容是否一樣。
    而絕大部分時候我們比較兩個 String 對象的時候只是想比較它們的內容是否相等,這樣看來,只能選 equals 了,但真的是這樣嗎?
    答案是否定的。你一樣也可以用 "==" 來完成這樣的一件事情,而且 "==" 的效率無論如何都是要比使用 equals 的效率要高的,但前提是,
    需要使用字符串的駐留池,才能使用 "==" 來替代 equals 作比較。
    String 里面有個方法叫 intern(),執行效率很高,但也許你還不曾用過,下面是摘自API中 intern() 方法的描述:

    “當調用 intern 方法時,如果池已經包含一個等于此 String 對象的字符串(用 equals(Object) 方法確定),則返回池中的字符串。
    否則,將此 String 對象添加到池中,并返回此 String 對象的引用。
    它遵循以下規則:
    對于任意兩個字符串 st,當且僅當 s.equals(t)true 時,s.intern() == t.intern()
    才為 true。 ”

    例代碼:

     1
     2             String name = new String("fancy");
     3            
     4        if(name == "fancy") {    // false
     5            System.out.println("equals 1");
     6        }
    else {
     7            System.out.println("not equals 1");    // Be printed
     8        }

     9        
    10        name = name.intern();    // 將字符串添加到駐留池
    11        
    12        if(name == "fancy") {    // true
    13            System.out.println("equals 2");        // Be printed
    14        }
    else {
    15            System.out.println("not equals 2");
    16        }

    17


    輸出結果:

    1
    2not equals 1
    3equals 2
    4

     


    由上面的示例代碼可以看到,字符串駐留池的使用是非常簡單的,池中的對象可以被共享,只要你將字符串添加到池中,就能夠直接使用
    "==" 來比較兩個對象,而不是只能使用 equals 來作比較。將字符串添加到駐留池來使用 "==" 作比較的方式要比直接使用 equals 效率要高些。

    再論 String、StringBuffer StringBuilder

    由 synchronized 修飾的方法可以保證方法的線程安全,但是會降低該方法的執行效率;

    翻開 API,很容易就能知道:StringBuffer 是線程安全的可變字符序列,StringBuilder 是一個可變的字符序列,是線程不安全的;
    網上說的所謂的使用 StringBuffer 的效率更高更好,這已經不合時宜,這是 java 1.5 之前的版本的說法,早過時了現在!!
    現在是反過來了,由于 StringBuilder 不是線程安全的,StringBuilder 效率會比 StringBuffer 效率更高一些。

    你可以不相信我說的,但你總該相信程序跑出來的結果吧,下面是示例代碼:

     1
     2        StringBuffer  buffer  = new StringBuffer();
     3        StringBuilder builder = new StringBuilder();
     4        int COUNT = 10;       // 測試 COUNT 趟
     5        final int N = 100000// 每趟操作 N 次
     6        double beginTime, costTime; // 每趟開始時間和耗費時間
     7        double bufferTotalTime = 0.0D, buliderTotalTime = 0.0D// StringBuffer 和 StringBuilder 測試 COUNT 趟的總耗時
     8        while(COUNT -- > -1) {
     9            // 也可以測試每趟都創建一個新的對象,這樣 StringBuilder 效率比 StringBuffer 的效率變得更明顯了
    10            /**
    11            StringBuffer  buffer  = new StringBuffer();
    12            StringBuilder builder = new StringBuilder();
    13            */

    14            System.out.println("----------------------------------<" + (COUNT + 1+ ">");
    15            beginTime = System.currentTimeMillis();
    16            for(int i = 0; i < N; i++) {
    17                buffer.append(i);
    18                buffer.length();
    19            }

    20            costTime = System.currentTimeMillis() - beginTime;
    21            bufferTotalTime  += costTime;
    22            System.out.println("StringBuffer  費時: --->> " + costTime);
    23            beginTime = System.currentTimeMillis();
    24            for(int i = 0; i < N; i++) {
    25                builder.append(i);
    26                builder.length();
    27            }

    28            costTime = System.currentTimeMillis() - beginTime;
    29            buliderTotalTime += costTime;
    30            System.out.println("StringBuilder 費時: --->> " + costTime);
    31            System.out.println("----------------------------------<" + (COUNT + 1+ ">");
    32        }

    33        System.out.println("bufferTotalTime / buliderTotalTime = " + (bufferTotalTime / buliderTotalTime));
    34


    后臺輸出結果:

     1
     2----------------------------------<10>
     3StringBuffer  費時: --->> 32.0
     4StringBuilder 費時: --->> 16.0
     5----------------------------------<10>
     6----------------------------------<9>
     7StringBuffer  費時: --->> 21.0
     8StringBuilder 費時: --->> 15.0
     9----------------------------------<9>
    10----------------------------------<8>
    11StringBuffer  費時: --->> 25.0
    12StringBuilder 費時: --->> 35.0
    13----------------------------------<8>
    14----------------------------------<7>
    15StringBuffer  費時: --->> 24.0
    16StringBuilder 費時: --->> 8.0
    17----------------------------------<7>
    18----------------------------------<6>
    19StringBuffer  費時: --->> 48.0
    20StringBuilder 費時: --->> 38.0
    21----------------------------------<6>
    22----------------------------------<5>
    23StringBuffer  費時: --->> 22.0
    24StringBuilder 費時: --->> 8.0
    25----------------------------------<5>
    26----------------------------------<4>
    27StringBuffer  費時: --->> 23.0
    28StringBuilder 費時: --->> 9.0
    29----------------------------------<4>
    30----------------------------------<3>
    31StringBuffer  費時: --->> 25.0
    32StringBuilder 費時: --->> 7.0
    33----------------------------------<3>
    34----------------------------------<2>
    35StringBuffer  費時: --->> 23.0
    36StringBuilder 費時: --->> 7.0
    37----------------------------------<2>
    38----------------------------------<1>
    39StringBuffer  費時: --->> 78.0
    40StringBuilder 費時: --->> 59.0
    41----------------------------------<1>
    42----------------------------------<0>
    43StringBuffer  費時: --->> 21.0
    44StringBuilder 費時: --->> 11.0
    45----------------------------------<0>
    46bufferTotalTime / buliderTotalTime = 1.6056338028169015
    47


    StringBuffer 在測試中平均耗時是 StringBuilder 的 1.6 倍以上,再測多次,都是 1.6 倍以上。StringBuffer 和 StringBuilder 的性能孰更加優,一眼明了。

    最后,如果你想知道 @3 (在上面我已經用紅色粗體標出) 的結果,不妨說一下:
    eg:
    String mail = "fancydeepin" + "@" + "yeah.net";

    來,一起來看一下上面的這條語句,想一下,這條語句將會創建幾個 String 的對象呢?
    1個? 2個? 3個? 4個? 5個? ... ...

    也許你會認為是4個,它們分別是:"fancydeepin"、"@"、"yeah.net"、"fancydeepin@yeah.net"
    也許你會認為是5個,它們分別是:"fancydeepin"、"@"、"yeah.net"、"fancydeepin@"、"fancydeepin@yeah.net"
    也許 ... ...

    但實際上,這條語句只創建了一個 String 對象!
    為什么會這樣呢?原因很簡單,這是因為,mail 在 編譯的時候其值就已經確定,它就是 "fancydeepin@yeah.net" 。
    當程序處于運行期間且當上面的這條語句被執行到的時候,那么 mail 所引用的對象就會被創建,而 mail 的值由于在編譯的時候已經確定
    它是  "fancydeepin@yeah.net" ,所以最終只有一個 String 對象被創建出來,而這個對象就是  "fancydeepin@yeah.net" 對象。

    這樣解釋都能夠理解了吧?真的理解了嗎?是真的理解才好,不妨再來看一個:
    eg:
    String mail = new String("fancydeepin@yeah.net");

    這回又創建了幾個對象呢?
    答案是2個。為什么不是1個了呢?2個又是哪2個呢?
    可以很肯定的告訴你,它們分別是: "fancydeepin@yeah.net"、new String()
    這是因為,這回 mail 在編譯的時候它的值是還不能夠確定的,編譯只是將源代碼翻譯成字節碼,程序還并沒有跑起來,還 new 不了對象,
    所以在編譯完成之后,mail 的值是還不能夠確定的。
    當程序處于運行期間且當上面的這條語句被執行到的時候,這時候才開始去確定 mail 的引用對象,首先,"fancydeepin@yeah.net" 對象會被創建,
    之后,再執行 new String(),所以這條語句最后實際上是創建了 2個 String 對象。






     



      
    posted on 2012-07-09 01:07 fancydeepin 閱讀(2780) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 免费无遮挡无码视频在线观看| 两个人看的www免费| 亚洲Av无码乱码在线播放| aaa毛片视频免费观看| 亚洲成在人线电影天堂色| 国产美女精品久久久久久久免费| 青青久久精品国产免费看| 亚洲一本综合久久| 国产性生交xxxxx免费| 久久一本岛在免费线观看2020| 亚洲一线产区二线产区区| 亚洲精品无码av人在线观看| 欧洲精品成人免费视频在线观看| 一级全免费视频播放| 亚洲一区二区三区免费视频 | 四虎影永久在线高清免费| 国产在线播放线91免费| 久久精品国产亚洲av麻豆图片| 国产亚洲美女精品久久久| 成人黄动漫画免费网站视频 | 无码乱人伦一区二区亚洲| 午夜高清免费在线观看| 久久成人无码国产免费播放| 亚洲成AV人片高潮喷水| 亚洲日本国产精华液| 亚洲欧洲日产国码无码久久99| 日韩视频免费一区二区三区| 久久伊人免费视频| 黄桃AV无码免费一区二区三区| 性色av极品无码专区亚洲| 亚洲欧洲日产国产最新| 亚洲免费人成在线视频观看| 在线免费观看国产视频| 美女网站免费福利视频| 国产猛男猛女超爽免费视频| 有色视频在线观看免费高清在线直播 | 日韩精品久久久久久免费| 一级人做人爰a全过程免费视频| 亚洲色丰满少妇高潮18p| 亚洲福利一区二区三区| 亚洲视频一区调教|