JAVA中String對象的比較

          1.首先介紹三個String對象比較的方法:
          (1)equals:比較兩個String對象的是否相等。例如: 
          String str1 = "hello quanjizhu";
          String str2 =str1+"haha";
          String str3 = new String("hello quanjizhu");

          System.out.println(str1.equals(str2)); 
          System.out.println(str1.equals(str3)); 
          輸出結(jié)果都為true。

          (2)= =:比較兩個String對象的指向的內(nèi)存地址是否相等。例如: 
          String str1 = "hello quanjizhu";
          String str2 =str1+"haha";
          String str3 = new String("hello quanjizhu");

          System.out.println(str1.equals(str2)); 
          System.out.println(str1.equals(str3)); 
          輸出結(jié)果都為false。

          3.原理
          要理解 java中String的運作方式,必須明確一點:String是一個非可變類(immutable)。什么是非可變類呢?簡單說來,非可變類的實例是不能被修改的,每個實例中包含的信息都必須在該實例創(chuàng)建的時候就提供出來,并且在對象的整個生存周期內(nèi)固定不變。java為什么要把String設(shè)計為非可變類呢?你可以問問 james Gosling :)。但是非可變類確實有著自身的優(yōu)勢,如狀態(tài)單一,對象簡單,便于維護(hù)。其次,該類對象對象本質(zhì)上是線程安全的,不要求同步。此外用戶可以共享非可變對象,甚至可以共享它們的內(nèi)部信息。(詳見 《Effective java》item 13)。String類在java中被大量運用,甚至在class文件中都有其身影,因此將其設(shè)計為簡單輕便的非可變類是比較合適的。 
          (1)創(chuàng)建。
              好了,知道String是非可變類以后,我們可以進(jìn)一步了解String的構(gòu)造方式了。創(chuàng)建一個Stirng對象,主要就有以下兩種方式:


          java 代碼
          String str1 = new String("abc");    
          Stirng str2 = "abc";  
               雖然兩個語句都是返回一個String對象的引用,但是jvm對兩者的處理方式是不一樣的。對于第一種,jvm會馬上在heap中創(chuàng)建一個String對象,然后將該對象的引用返回給用戶。對于第二種,jvm首先會在內(nèi)部維護(hù)的strings pool中通過String的 equels 方法查找是對象池中是否存放有該String對象,如果有,則返回已有的String對象給用戶,而不會在heap中重新創(chuàng)建一個新的String對象;如果對象池中沒有該String對象,jvm則在heap中創(chuàng)建新的String對象,將其引用返回給用戶,同時將該引用添加至strings pool中。注意:使用第一種方法創(chuàng)建對象時,jvm是不會主動把該對象放到strings pool里面的,除非程序調(diào)用 String的intern方法。看下面的例子:

          java 代碼
          String str1 = new String("abc"); //jvm 在堆上創(chuàng)建一個String對象   
            
           //jvm 在strings pool中找不到值為“abc”的字符串,因此   
           //在堆上創(chuàng)建一個String對象,并將該對象的引用加入至strings pool中   
           //此時堆上有兩個String對象   
          Stirng str2 = "abc";   
            
           if(str1 == str2){   
                   System.out.println("str1 == str2");   
           }else{   
                   System.out.println("str1 != str2");   
           }   
            //打印結(jié)果是 str1 != str2,因為它們是堆上兩個不同的對象   
            
            String str3 = "abc";   
           //此時,jvm發(fā)現(xiàn)strings pool中已有“abc”對象了,因為“abc”equels “abc”   
           //因此直接返回str2指向的對象給str3,也就是說str2和str3是指向同一個對象的引用   
            if(str2 == str3){   
                   System.out.println("str2 == str3");   
            }else{   
                   System.out.println("str2 != str3");   
            }   
           //打印結(jié)果為 str2 == str3  
             再看下面的例子:


          java 代碼
          String str1 = new String("abc"); //jvm 在堆上創(chuàng)建一個String對象   
            
          str1 = str1.intern();   
          //程序顯式將str1放到strings pool中,intern運行過程是這樣的:首先查看strings pool   
          //有沒“abc”對象的引用,沒有,則在堆中新建一個對象,然后將新對象的引用加入至   
          //strings pool中。執(zhí)行完該語句后,str1原來指向的String對象已經(jīng)成為垃圾對象了,隨時會   
          //被GC收集。   
            
          //此時,jvm發(fā)現(xiàn)strings pool中已有“abc”對象了,因為“abc”equels “abc”   
          //因此直接返回str1指向的對象給str2,也就是說str2和str1引用著同一個對象,   
          //此時,堆上的有效對象只有一個。   
          Stirng str2 = "abc";   
            
           if(str1 == str2){   
                   System.out.println("str1 == str2");   
           }else{   
                   System.out.println("str1 != str2");   
           }   
            //打印結(jié)果是 str1 == str2   
            



              為什么jvm可以這樣處理String對象呢?就是因為String的非可變性。既然所引用的對象一旦創(chuàng)建就永不更改,那么多個引用共用一個對象時互不影響。


          (2)串接(Concatenation)。
               java程序員應(yīng)該都知道濫用String的串接操作符是會影響程序的性能的。性能問題從何而來呢?歸根結(jié)底就是String類的非可變性。既然String對象都是非可變的,也就是對象一旦創(chuàng)建了就不能夠改變其內(nèi)在狀態(tài)了,但是串接操作明顯是要增長字符串的,也就是要改變String的內(nèi)部狀態(tài),兩者出現(xiàn)了矛盾。怎么辦呢?要維護(hù)String的非可變性,只好在串接完成后新建一個String 對象來表示新產(chǎn)生的字符串了。也就是說,每一次執(zhí)行串接操作都會導(dǎo)致新對象的產(chǎn)生,如果串接操作執(zhí)行很頻繁,就會導(dǎo)致大量對象的創(chuàng)建,性能問題也就隨之而來了。
              為了解決這個問題,jdk為String類提供了一個可變的配套類,StringBuffer。使用StringBuffer對象,由于該類是可變的,串接時僅僅時改變了內(nèi)部數(shù)據(jù)結(jié)構(gòu),而不會創(chuàng)建新的對象,因此性能上有很大的提高。針對單線程,jdk 5.0還提供了StringBuilder類,在單線程環(huán)境下,由于不用考慮同步問題,使用該類使性能得到進(jìn)一步的提高。

          (3)String的長度
             我們可以使用串接操作符得到一個長度更長的字符串,那么,String對象最多能容納多少字符呢?查看String的源代碼我們可以得知類String中是使用域 count 來記錄對象字符的數(shù)量,而count 的類型為 int,因此,我們可以推測最長的長度為 2^32,也就是4G。
              不過,我們在編寫源代碼的時候,如果使用 Sting str = "aaaa";的形式定義一個字符串,那么雙引號里面的ASCII字符最多只能有 65534 個。為什么呢?因為在class文件的規(guī)范中, CONSTANT_Utf8_info表中使用一個16位的無符號整數(shù)來記錄字符串的長度的,最多能表示 65536個字節(jié),而java class 文件是使用一種變體UTF-8格式來存放字符的,null值使用兩個字節(jié)來表示,因此只剩下 65536- 2 = 65534個字節(jié)。也正是變體UTF-8的原因,如果字符串中含有中文等非ASCII字符,那么雙引號中字符的數(shù)量會更少(一個中文字符占用三個字節(jié))。如果超出這個數(shù)量,在編譯的時候編譯器會報錯。


          (3)compareTo:比較兩個String對象的是否相等。例如: 
          String str1 = "hello quanjizhu";
          String str2 =str1+"haha";
          String str3 = new String("hello quanjizhu");

          System.out.println(str1.compareTo(str2)); 
          System.out.println(str1.compareTo(str3)); 
          輸出結(jié)果都為0。(若輸出結(jié)果大于0表示str1大于str2)

          2.String類的幾種初始化方法的區(qū)別
          (1) String str1 = "hello quanjizhu";
          首先到String pool中查找有沒有值為hello quanjizhu的對象,若有則讓str1直接指向此內(nèi)存地址;若沒有則在內(nèi)存堆中重新開辟空間給str1,并把hello quanjizhu加到String pool中。
          (2)String str3 = new String("hello quanjizhu");
          每次初始化都會重新在內(nèi)存堆中開辟空間給新的對象,而不會到String pool中查找,更不會添加到String pool中。除非顯示的調(diào)用intern方法。
          str3.interl();這時就會把hello quanjizhu加到String pool中。
          (3)
          String str1 = "hello quanjizhu";
          String str2 ="hello" +"quanjizhu";
           String str3 ="hello "+"quanjizhu";在編譯的時候會優(yōu)化成String str3 = "hello quanjizhu";所有str1和str2指向的是同一內(nèi)存地址。
          (4)
          String var = “quanjizhu“;
          String str4 = “hello “+var;
            System.out.println(str1= =str4)的結(jié)果是什么呢?輸出結(jié)果是false,證明了String str4 = “hello “+var;
          在內(nèi)存堆中會重新分配空間,而不是讓str4指向var的地址。換用一種定義方法:str4 = (“hello “+var4).intern();intern()方法告訴編譯器將此結(jié)果放到String pool里,因此,System.out.println(str1= =str4)輸出結(jié)構(gòu)將是true;


          posted on 2008-07-22 22:18 chenkai 閱讀(2160) 評論(3)  編輯  收藏

          評論

          # re: JAVA中String對象的比較 2010-08-13 11:27 7894

          1.首先介紹三個String對象比較的方法:
          (1)equals:比較兩個String對象的值是否相等。例如:
          String str1 = "hello quanjizhu";
          String str2 =str1+"haha";
          String str3 = new String("hello quanjizhu");

          System.out.println(str1.equals(str2));
          System.out.println(str1.equals(str3));
          輸出結(jié)果都為true。
          ???????????????????????????
          你自己測試過嗎就發(fā)外貼?  回復(fù)  更多評論   

          # re: JAVA中String對象的比較[未登錄] 2011-11-28 16:48 111

          所以說是,扯蛋~!  回復(fù)  更多評論   

          # re: JAVA中String對象的比較 2013-03-13 16:02 薩維奇而的

          nc
            回復(fù)  更多評論   


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


          網(wǎng)站導(dǎo)航:
           
          <2008年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(2)

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 鄂尔多斯市| 金坛市| 漳浦县| 囊谦县| 琼海市| 高阳县| 驻马店市| 庄浪县| 扶沟县| 桃园县| 老河口市| 雅江县| 乐平市| 封开县| 芦山县| 舟曲县| 沁源县| 柳林县| 柘荣县| 广昌县| 梁山县| 菏泽市| 赣榆县| 明光市| 南宫市| 长武县| 东方市| 潢川县| 肃南| 兴安县| 张家口市| 蒙山县| 昔阳县| 紫金县| 巴马| 乌兰浩特市| 肃北| 平乡县| 宝山区| 许昌市| 眉山市|