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

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

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

    posts - 3,comments - 1,trackbacks - 0

    最近見(jiàn)版內(nèi)對(duì)String討論的帖子很多,但是又眾說(shuō)風(fēng)云,為了讓大家徹底理解String這個(gè)特殊對(duì)象,我趁此機(jī)會(huì)來(lái)對(duì)String對(duì)象做進(jìn)一步的分析。

    友情提示:希望在閱讀之前,你已經(jīng)對(duì)String對(duì)象有了基礎(chǔ)的了解。并且已經(jīng)熟知"類型"、"引用"、"對(duì)象"、"實(shí)例化"、"堆棧"和關(guān)于Object對(duì)象的equals()方法的使用機(jī)制,并且已經(jīng)熟知String對(duì)象對(duì)equals()方法重寫(xiě)后的使用機(jī)制!

    首先大家知道,String既可以作為一個(gè)對(duì)象來(lái)使用,又可以作為一個(gè)基本類型來(lái)使用。這里指的作為一個(gè)基本類型來(lái)使用只是指使用方法上的,比如String s = "Hello",它的使用方法如同基本類型int一樣,比如int i = 1;,而作為一個(gè)對(duì)象來(lái)使用,則是指通過(guò)new關(guān)鍵字來(lái)創(chuàng)建一個(gè)新對(duì)象,比如String s = new String("Hello")。但是它的內(nèi)部動(dòng)作其實(shí)還是創(chuàng)建了一個(gè)對(duì)象,這點(diǎn)稍后會(huì)說(shuō)到。

    其次,對(duì)String對(duì)象的比較方法需要了解。Java里對(duì)象之間的比較有兩種概念,這里拿String對(duì)象來(lái)說(shuō):一種是用"=="來(lái)比較,這種比較是針對(duì)兩個(gè)String類型的變量的引用,也就是說(shuō)如果兩個(gè)String類型的變量,它們所引用同一個(gè)String對(duì)象(即指向同一塊內(nèi)存堆),則"=="比較的結(jié)果是true。另一種是用Object對(duì)象的equals()方法來(lái)比較,String對(duì)象繼承自O(shè)bject,并且對(duì)equals()方法進(jìn)行了重寫(xiě)。兩個(gè)String對(duì)象通過(guò)equals()方法來(lái)進(jìn)行比較時(shí),其實(shí)就是對(duì)String對(duì)象所封裝的字符串內(nèi)容進(jìn)行比較,也就是說(shuō)如果兩個(gè)String對(duì)象所封裝的字符串內(nèi)容相同(包括大小寫(xiě)相同),則equals()方法將返回true。

    現(xiàn)在開(kāi)始將對(duì)String對(duì)象的創(chuàng)建做具體的分析。

    首先看以下代碼段:

    String s1 = new String("Hello");
    String s2 = new String("Hello");

    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));

    以上代碼段的打印結(jié)果是:

    false
    true

    這個(gè)結(jié)果相信大家很好理解,兩個(gè)String類型的變量s1和s2都通過(guò)new關(guān)鍵字分別創(chuàng)建了一個(gè)新的String對(duì)象,這個(gè)new關(guān)鍵字為創(chuàng)建的每個(gè)對(duì)象分配一塊新的、獨(dú)立的內(nèi)存堆。因此當(dāng)通過(guò)"=="來(lái)比較它們所引用的是否是同一個(gè)對(duì)象時(shí),將返回false。而通過(guò)equals()方法來(lái)比較時(shí),則返回true,因?yàn)檫@兩個(gè)對(duì)象所封裝的字符串內(nèi)容是完全相同的。

    好,現(xiàn)在把上面的代碼段修改如下:

    String s1 = new String("Hello");
    String s2 = s1;

    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));

    以上代碼段的打印結(jié)果是:

    true
    true

    這個(gè)結(jié)果應(yīng)該更好理解,變量s1還是通過(guò)new關(guān)鍵字來(lái)創(chuàng)建了一個(gè)新的String對(duì)象,但這里s2并沒(méi)有通過(guò)new關(guān)鍵字來(lái)創(chuàng)建一個(gè)新的String對(duì)象,而是直接把s1賦值給了s2,即把s1的引用賦值給了s2,所以s2所引用的對(duì)象其實(shí)就是s1所引用的對(duì)象。所以通過(guò)"=="來(lái)比較時(shí),返回true。既然它們引用的都是同一個(gè)對(duì)象,那么通過(guò)equals()方法來(lái)比較時(shí),肯定也返回true,這里equals()方法其實(shí)在對(duì)同一個(gè)對(duì)象進(jìn)行比較,自己肯定等于自己咯。

    說(shuō)到此,其實(shí)應(yīng)該沒(méi)什么大問(wèn)題,因?yàn)檫@些都是標(biāo)準(zhǔn)的創(chuàng)建對(duì)象的動(dòng)作,但是String對(duì)象還有另一種使用方法,也就是開(kāi)頭所提到的可以作為一個(gè)基本類型來(lái)使用,請(qǐng)看以下代碼段:

    String s = "Hello";

    看到這里,相信一些初學(xué)的朋友或者對(duì)String對(duì)象還沒(méi)搞清楚的朋友開(kāi)始疑惑了,你肯定會(huì)問(wèn),這個(gè)使用方法在其內(nèi)部到底發(fā)生了什么?其實(shí)這就是String對(duì)象容易混淆的關(guān)鍵!

    其實(shí)在啟動(dòng)程序時(shí),虛擬機(jī)會(huì)創(chuàng)建一塊String對(duì)象的String緩沖池。當(dāng)String對(duì)象作為一個(gè)基本類型來(lái)使用時(shí),比如:String s = "Hello";,虛擬機(jī)會(huì)先在這個(gè)String緩沖池內(nèi)尋找是否有相同值的String對(duì)象存在,如果存在,則把這個(gè)String對(duì)象的引用賦值給s。如果不存在,虛擬機(jī)會(huì)先在這個(gè)String緩沖池內(nèi)創(chuàng)建此String對(duì)象,然后把引用賦值給s。

    說(shuō)到這里,相信大家已經(jīng)開(kāi)始明白了。那么請(qǐng)看下面的代碼段:

    String s1 = "Hello";
    String s2 = "Hello";

    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));

    以上代碼段的打印結(jié)果是:

    true
    true

    為什么這個(gè)結(jié)果?那么來(lái)分析一下。首先這兩個(gè)String對(duì)象都是作為一個(gè)基本類型來(lái)使用的,而不是通過(guò)new關(guān)鍵字來(lái)創(chuàng)建的,因此虛擬機(jī)不會(huì)為這兩個(gè)String對(duì)象分配新的內(nèi)存堆,而是到String緩沖池中來(lái)尋找。

    首先為s1尋找String緩沖池內(nèi)是否有與"Hello"相同值的String對(duì)象存在,此時(shí)String緩沖池內(nèi)是空的,沒(méi)有相同值的String對(duì)象存在,所以虛擬機(jī)會(huì)在String緩沖池內(nèi)創(chuàng)建此String對(duì)象,其動(dòng)作就是new String("Hello");。然后把此String對(duì)象的引用賦值給s1。

    接著為s2尋找String緩沖池內(nèi)是否有與"Hello"相同值的String對(duì)象存在,此時(shí)虛擬機(jī)找到了一個(gè)與其相同值的String對(duì)象,這個(gè)String對(duì)象其實(shí)就是為s1所創(chuàng)建的String對(duì)象。既然找到了一個(gè)相同值的對(duì)象,那么虛擬機(jī)就不在為此創(chuàng)建一個(gè)新的String對(duì)象,而是直接把存在的String對(duì)象的引用賦值給s2。

    這里既然s1和s2所引用的是同一個(gè)String對(duì)象,即自己等于自己,所以以上兩種比較方法都返回ture。

    到這里,對(duì)String對(duì)象的基本概念應(yīng)該都已經(jīng)理解了。現(xiàn)在我來(lái)小結(jié)一下:

    針對(duì)String作為一個(gè)基本類型來(lái)使用:

    1。如果String作為一個(gè)基本類型來(lái)使用,那么我們視此String對(duì)象是String緩沖池所擁有的。
    2。如果String作為一個(gè)基本類型來(lái)使用,并且此時(shí)String緩沖池內(nèi)不存在與其指定值相同的String對(duì)象,那么此時(shí)虛擬機(jī)將為此創(chuàng)建新的String對(duì)象,并存放在String緩沖池內(nèi)。
    3。如果String作為一個(gè)基本類型來(lái)使用,并且此時(shí)String緩沖池內(nèi)存在與其指定值相同的String對(duì)象,那么此時(shí)虛擬機(jī)將不為此創(chuàng)建新的String對(duì)象,而直接返回已存在的String對(duì)象的引用。

    針對(duì)String作為一個(gè)對(duì)象來(lái)使用:

    1。如果String作為一個(gè)對(duì)象來(lái)使用,那么虛擬機(jī)將為此創(chuàng)建一個(gè)新的String對(duì)象,即為此對(duì)象分配一塊新的內(nèi)存堆,并且它并不是String緩沖池所擁有的,即它是獨(dú)立的。

    理解了以上內(nèi)容后,請(qǐng)看以下代碼段:

    String s1 = "Hello";
    String s2 = new String("Hello");

    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));

    以上代碼段的打印結(jié)果是:

    false
    true

    根據(jù)上面的小結(jié)來(lái)進(jìn)行分析。第一行是把String作為一個(gè)基本類型來(lái)使用的,因此s1所引用的對(duì)象是屬于String緩沖池內(nèi)的。并且此時(shí)String緩沖池內(nèi)并沒(méi)有與其值相同的String對(duì)象存在,因此虛擬機(jī)會(huì)為此創(chuàng)建一個(gè)新的String對(duì)象,即new String("Hello");。第二行是把String作為一個(gè)對(duì)象來(lái)使用的,因此s2所引用的對(duì)象不屬于String緩沖池內(nèi)的,即它是獨(dú)立的。通過(guò)new關(guān)鍵字,虛擬機(jī)會(huì)為此創(chuàng)建一個(gè)新的String對(duì)象,即為它分配了一塊新的內(nèi)存堆。因此"=="比較后的結(jié)果是false,因?yàn)閟1和s2所引用的并不是同一個(gè)對(duì)象,它們是獨(dú)立存在的。而equals()方法所返回的是true,因?yàn)檫@兩個(gè)對(duì)象所封裝的字符串內(nèi)容是完全相同的。

    現(xiàn)在,相信大家已經(jīng)完全搞清楚String對(duì)象是怎么一回事了:)但是到此并沒(méi)有結(jié)束,因?yàn)镾tring對(duì)象還有更深層次的應(yīng)用。

    這里我將分析一下String對(duì)象的intern()方法的應(yīng)用。
    intern()方法將返回一個(gè)字符串對(duì)象的規(guī)范表示法,即一個(gè)同該字符串內(nèi)容相同的字符串,但是來(lái)自于唯一字符串的String緩沖池。這聽(tīng)起來(lái)有點(diǎn)拗口,其實(shí)它的機(jī)制有如以下代碼段:

    String s = new String("Hello");
    s = s.intern();

    以上代碼段的功能實(shí)現(xiàn)可以簡(jiǎn)單的看成如下代碼段:

    String s = "Hello";

    你一定又開(kāi)始疑惑了?那么你可以先看第二個(gè)代碼段。第二個(gè)代碼段的意思就是從String緩沖池內(nèi)取出一個(gè)與其值相同的String對(duì)象的引用賦值給s。如果String緩沖池內(nèi)沒(méi)有與其相同值的String對(duì)象存在,則在其內(nèi)為此創(chuàng)建一個(gè)新的String對(duì)象。那么第一段代碼的意思又是什么呢?我們知道通過(guò)new關(guān)鍵字所創(chuàng)建出的對(duì)象,虛擬機(jī)會(huì)為它分配一塊新的內(nèi)存堆。如果平凡地創(chuàng)建相同內(nèi)容的對(duì)象,虛擬機(jī)同樣會(huì)為此分配許多新的內(nèi)存堆,雖然它們的內(nèi)容是完全相同的。拿String對(duì)象來(lái)說(shuō),如果連續(xù)創(chuàng)建10個(gè)相同內(nèi)容的String對(duì)象(new String("Hello")),那么虛擬機(jī)將為此分配10塊獨(dú)立的內(nèi)存堆。假設(shè)所創(chuàng)建的String對(duì)象的字符串內(nèi)容十分大,假設(shè)一個(gè)Stirng對(duì)象封裝了1M大小的字符串內(nèi)容,那么如果我們創(chuàng)建10個(gè)此相同String對(duì)象的話,我們將會(huì)毫無(wú)意義的浪費(fèi)9M的內(nèi)存空間。我們知道String是final類,它所封裝的是字符串常量,因此String對(duì)象在創(chuàng)建后其內(nèi)部(字符串)值不能改變,也因此String對(duì)象可以被共享。所以對(duì)于剛才提到的假設(shè),我們所創(chuàng)建的10個(gè)相同內(nèi)容的String對(duì)象,其實(shí)我們只需為此創(chuàng)建一個(gè)String對(duì)象,然后被其它String變量所共享。要實(shí)現(xiàn)這種機(jī)制,唯一的、簡(jiǎn)單的方法就是使用String緩沖池,因?yàn)镾tring緩沖池內(nèi)不會(huì)存在相同內(nèi)容的String對(duì)象。而intern()方法就是使用這種機(jī)制的途徑。在一個(gè)已實(shí)例化的String對(duì)象上調(diào)用intern()方法后,虛擬機(jī)會(huì)在String緩沖池內(nèi)尋找與此Stirng對(duì)象所封裝的字符串內(nèi)容相同值的String對(duì)象,然后把引用賦值給引用原來(lái)的那個(gè)String對(duì)象的String類型變量。如果String緩沖池內(nèi)沒(méi)有與此String對(duì)象所封裝的字符串內(nèi)容相同值的String對(duì)象存在,那么虛擬機(jī)會(huì)為此創(chuàng)建一個(gè)新的String對(duì)象,并把其引用賦值給引用原來(lái)的那個(gè)String對(duì)象的String類型變量。這樣就達(dá)到了共享同一個(gè)String對(duì)象的目的,而原先那個(gè)通過(guò)new關(guān)鍵字所創(chuàng)建出的String對(duì)象將被拋棄并被垃圾回收器回收掉。這樣不但降低了內(nèi)存的使用消耗,提高了性能,而且在String對(duì)象的比較上也同樣更方便了,因?yàn)橄嗤腟tring對(duì)象將被共享,所以要判斷兩個(gè)String對(duì)象是否相同,則只需要使用"=="來(lái)比較,而無(wú)需再使用equals()方法來(lái)比較,這樣不但使用起來(lái)更方便,而且也提高了性能,因?yàn)镾tring對(duì)象的equals()方法將會(huì)對(duì)字符串內(nèi)容拆解,然后逐個(gè)進(jìn)行比較,如果字符串內(nèi)容十分大的話,那么這個(gè)比較動(dòng)作則大大降低了性能。

    說(shuō)到此,大家可能對(duì)具體應(yīng)用還有點(diǎn)模糊,那么我來(lái)舉個(gè)簡(jiǎn)單的示例,以便闡述以上概念:

    假設(shè)有一個(gè)類,它有一個(gè)接收消息的方法,這個(gè)方法記錄用戶傳來(lái)的消息(假設(shè)消息內(nèi)容可能較大,并且重復(fù)率較高),并且把消息按接收順序記錄在一個(gè)列表中。我想有些朋友會(huì)這樣設(shè)計(jì):

    import java.util.*;

    public class Messages {

    ArrayList messages = new ArrayList();

    public void record(String msg) {
    messages.add(msg);
    }

    public List getMessages() {
    return messages;
    }
    }

    這種設(shè)計(jì)方案好嗎?假設(shè)我們重復(fù)的發(fā)送給record()方法同一個(gè)消息(消息來(lái)自不同的用戶,所以可以視每個(gè)消息為一個(gè)new String("...")),并且消息內(nèi)容較大,那么這個(gè)設(shè)計(jì)將會(huì)大大浪費(fèi)內(nèi)存空間,因?yàn)橄⒘斜碇杏涗浀亩际切聞?chuàng)建的、獨(dú)立的String對(duì)象,雖然它們的內(nèi)容都相同。那么怎么樣可以對(duì)其進(jìn)行優(yōu)化呢,其實(shí)很簡(jiǎn)單,請(qǐng)看如下優(yōu)化后的示例:

    import java.util.*;

    public class Messages {

    ArrayList messages = new ArrayList();

    public void record(String msg) {
    messages.add(msg.intern());
    }

    public List getMessages() {
    return messages;
    }
    }

    正如你所看到的,原先record()方法中的messages.add(msg);代碼段變成了messages.add(msg.intern());,僅僅對(duì)msg參數(shù)調(diào)用了intern()方法,這樣將對(duì)重復(fù)的消息進(jìn)行共享機(jī)制,從而降低了內(nèi)存消耗,提高了性能。

    這個(gè)例子的確有點(diǎn)牽強(qiáng),但是這里只是為了闡述以上概念!

    至此,String對(duì)象的迷霧都被消除了,大家只要牢記這些概念,以后再?gòu)?fù)雜的String應(yīng)用都可以建立在此基礎(chǔ)上來(lái)進(jìn)行分析。

    posted on 2007-02-04 20:13 高天賜 閱讀(271) 評(píng)論(1)  編輯  收藏

    FeedBack:
    # re: String討論[未登錄](méi)
    2008-05-07 22:26 | jack
    好,非常好,
    其實(shí)java api上說(shuō)的有點(diǎn)錯(cuò)誤,他說(shuō)是:
    When the intern method is invoked, if the pool already contains a string equal to this <code>String</code> object as determined by the {@link #equals(Object)} method, then the string from the pool is returned. Otherwise, this <code>String</code> object is added to the pool and a reference to this <code>String</code> object is returned.

    不應(yīng)該是this <code>String</code> object is added to the pool
    應(yīng)該是: a new String object value equals the String object is created and added to the pool  回復(fù)  更多評(píng)論
      

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 无码人妻久久一区二区三区免费丨| 国产免费一区二区三区不卡 | 亚洲处破女AV日韩精品| 免费无码AV一区二区| 免费一看一级毛片| 免费无码一区二区| 国产亚洲老熟女视频| 黄色片免费在线观看| 婷婷亚洲综合五月天小说| 最近2019免费中文字幕6| 亚洲精品第一综合99久久| 日韩免费精品视频| 亚洲乱妇老熟女爽到高潮的片 | 亚洲午夜精品一级在线播放放| 一级毛片aa高清免费观看| 亚洲熟妇中文字幕五十中出| 在线毛片片免费观看| 亚洲制服在线观看| 国产区卡一卡二卡三乱码免费| www.av在线免费观看| 亚洲AV无码不卡无码| 国产精品视频免费观看| 国产精品亚洲专区无码唯爱网| 国产乱辈通伦影片在线播放亚洲| 野花香在线视频免费观看大全| 亚洲综合久久成人69| 国产免费人视频在线观看免费| a级大片免费观看| 亚洲真人无码永久在线观看| 亚洲天堂中文字幕在线| 国产精品色拉拉免费看| 怡红院亚洲红怡院在线观看| 国产亚洲日韩一区二区三区| 久久精品国产免费观看| 日韩在线视频线视频免费网站| 亚洲免费在线视频| 国产精品免费视频播放器| 免费黄色电影在线观看| 亚洲AV性色在线观看| 久久亚洲精品成人av无码网站| 在线日韩av永久免费观看|