• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Merlin

            Life was like a box of chocolates. You never know what you're gonna get.

               :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              34 隨筆 :: 0 文章 :: 40 評論 :: 0 Trackbacks
            近期到CSDN論壇看看一些網(wǎng)友貼的面試題,其中關(guān)于String的問題常常被提及。我一直以為自己很清楚這個(gè)東西了,其實(shí)深究起來,發(fā)現(xiàn)自己并不那么清楚,會犯一些錯誤;同時(shí)也產(chǎn)生了一些聯(lián)想。小結(jié)一下。

            1、"abc"與new String("abc");
            ????經(jīng)常會問到的面試題:String s = new String("abc");創(chuàng)建了幾個(gè)String Object?【如這里創(chuàng)建了多少對象? 和一道小小的面試題 】

            ????這個(gè)問題比較簡單,涉及的知識點(diǎn)包括:

            引用變量與對象的區(qū)別;
            字符串文字"abc"是一個(gè)String對象;
            文字池[pool of literal strings]和堆[heap]中的字符串對象。
            ????一、引用變量與對象:除了一些早期的Java書籍和現(xiàn)在的垃圾書籍,人們都可以從中比較清楚地學(xué)習(xí)到兩者的區(qū)別。A aa;語句聲明一個(gè)類A的引用變量aa[我常常稱之為句柄],而對象一般通過new創(chuàng)建。所以題目中s僅僅是一個(gè)引用變量,它不是對象。[ref 句柄、引用與對象]

            ????二、Java中所有的字符串文字[字符串常量]都是一個(gè)String的對象。有人[特別是C程序員]在一些場合喜歡把字符串"當(dāng)作/看成"字符數(shù)組,這也沒有辦法,因?yàn)樽址c字符數(shù)組存在一些內(nèi)在的聯(lián)系。事實(shí)上,它與字符數(shù)組是兩種完全不同的對象。

            ????????System.out.println("Hello".length());
            ????????char[] cc={'H','i'};
            ????????System.out.println(cc.length);

            ????三、字符串對象的創(chuàng)建:由于字符串對象的大量使用[它是一個(gè)對象,一般而言對象總是在heap分配內(nèi)存],Java中為了節(jié)省內(nèi)存空間和運(yùn)行時(shí)間[如比較字符串時(shí),==比equals()快],在編譯階段就把所有的字符串文字放到一個(gè)文字池[pool of literal strings]中,而運(yùn)行時(shí)文字池成為常量池的一部分。文字池的好處,就是該池中所有相同的字符串常量被合并,只占用一個(gè)空間。我們知道,對兩個(gè)引用變量,使用==判斷它們的值[引用]是否相等,即指向同一個(gè)對象:

            				String s1 = "abc" ;
            String s2 = "abc" ;
            if( s1 == s2 )
            ????System.out.println("s1,s2 refer to the same object");
            else???? System.out.println("trouble");


            ????這里的輸出顯示,兩個(gè)字符串文字保存為一個(gè)對象。就是說,上面的代碼只在pool中創(chuàng)建了一個(gè)String對象。

            ????現(xiàn)在看String s = new String("abc");語句,這里"abc"本身就是pool中的一個(gè)對象,而在運(yùn)行時(shí)執(zhí)行new String()時(shí),將pool中的對象復(fù)制一份放到heap中,并且把heap中的這個(gè)對象的引用交給s持有。ok,這條語句就創(chuàng)建了2個(gè)String對象。

            				String s1 = new String("abc") ;
            String s2 = new String("abc") ;
            if( s1 == s2 ){ //不會執(zhí)行的語句}


            ????這時(shí)用==判斷就可知,雖然兩個(gè)對象的"內(nèi)容"相同[equals()判斷],但兩個(gè)引用變量所持有的引用不同,

            ????BTW:上面的代碼創(chuàng)建了幾個(gè)String Object? [三個(gè),pool中一個(gè),heap中2個(gè)。]
            ????[Java2 認(rèn)證考試學(xué)習(xí)指南 (第4版)( 英文版)p197-199有圖解。]


            2、字符串的+運(yùn)算和字符串轉(zhuǎn)換
            ????字符串轉(zhuǎn)換和串接是很基礎(chǔ)的內(nèi)容,因此我以為這個(gè)問題簡直就是送分題。事實(shí)上,我自己就答錯了。

            String str = new String("jf"); // jf是接分
            str = 1+2+str+3+4;
            一共創(chuàng)建了多少String的對象?[我開始的答案:5個(gè)。jf、new、3jf、3jf3、3jf34]

            ????首先看JLS的有關(guān)論述:

            ????一、字符串轉(zhuǎn)換的環(huán)境[JLS 5.4 String Conversion]

            ????字符串轉(zhuǎn)換環(huán)境僅僅指使用雙元的+運(yùn)算符的情況,其中一個(gè)操作數(shù)是一個(gè)String對象。在這一特定情形下,另一操作數(shù)轉(zhuǎn)換成String,表達(dá)式的結(jié)果是這兩個(gè)String的串接。

            ????二、串接運(yùn)算符[JLS 15.18.1 String Concatenation Operator + ]

            ????如果一個(gè)操作數(shù)/表達(dá)式是String類型,則另一個(gè)操作數(shù)在運(yùn)行時(shí)轉(zhuǎn)換成一個(gè)String對象,并兩者串接。此時(shí),任何類型都可以轉(zhuǎn)換成String。[這里,我漏掉了"3"和"4"]

            如果是基本數(shù)據(jù)類型,則如同首先轉(zhuǎn)換成其包裝類對象,如int x視為轉(zhuǎn)換成Integer(x)。
            現(xiàn)在就全部統(tǒng)一到引用類型向String的轉(zhuǎn)換了。這種轉(zhuǎn)換如同[as if]調(diào)用該對象的無參數(shù)toString方法。[如果是null則轉(zhuǎn)換成"null"]。因?yàn)閠oString方法在Object中定義,故所有的類都有該方法,而且Boolean, Character, Integer, Long, Float, Double, and String改寫了該方法。
            關(guān)于+是串接還是加法,由操作數(shù)決定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中舉的一個(gè)jocular little example,真的很無趣。]
            ????下面的例子測試了改寫toString方法的情況.。

            				class A{
            ????int i = 10;
            ????public static void main(String []args){
            ????????String str = new String("jf");
            ????????str += new A();
            ????????System.out.print(str);
            ????}

            ????public String toString(){
            ????????return " a.i ="+i+"\n";
            ????}
            }


            三、字符串轉(zhuǎn)換的優(yōu)化

            按照上述說法,str = 1+2+str+3+4;語句似乎應(yīng)該就應(yīng)該生成5個(gè)String對象:

            1+2 =3,then 3→Integer(3)→"3" in pool? [假設(shè)如此]
            "3"+str(in heap) = "3jf"???? (in heap)
            "3jf" +3 ,first 3→Integer(3)→"3" in pool? [則不創(chuàng)建] then "3jf3"
            "3jf3"+4 create "4"??in pool
            then "3jf34"

            ????這里我并不清楚3、4轉(zhuǎn)換成字符串后是否在池中,所以上述結(jié)果仍然是猜測。

            ????為了減少創(chuàng)建中間過渡性的字符串對象,提高反復(fù)進(jìn)行串接運(yùn)算時(shí)的性能,a Java compiler可以使用StringBuffer或者類似的技術(shù),或者把轉(zhuǎn)換與串接合并成一步。例如:對于 a + b + c ,Java編譯器就可以將它視為[as if]

            ????new StringBuffer().append(a).append(b).append(c).toString();

            ????注意,對于基本類型和引用類型,在append(a)過程中仍然要先將參數(shù)轉(zhuǎn)換,從這個(gè)觀點(diǎn)看,str = 1+2+str+3+4;創(chuàng)建的字符串可能是"3"、"4"和"3jf34"[以及一個(gè)StringBuffer對象]。

            ????現(xiàn)在我仍然不知道怎么回答str = 1+2+str+3+4;創(chuàng)建了多少String的對象,。或許,這個(gè)問題不需要過于研究,至少SCJP不會考它。

            3、這又不同:str = "3"+"jf"+"3"+"4";
            ????如果是一個(gè)完全由字符串文字組成的表達(dá)式,則在編譯時(shí),已經(jīng)被優(yōu)化而不會在運(yùn)行時(shí)創(chuàng)建中間字符串。測試代碼如下:

            				String str1 ="3jf34";
            ????????String str2 ="3"+"jf"+"3"+"4";
            ????????if(str1 == str2) {
            ????????????System.out.println("str1 == str2");
            ????????}else {
            ????????????System.out.println("think again");
            ????????}
            ????????if(str2.equals(str1))
            ????????????System.out.println("yet str2.equals(str1)");


            ????可見,str1與str2指向同一個(gè)對象,這個(gè)對象在pool中。所有遵循Java Language Spec的編譯器都必須在編譯時(shí)對constant expressions 進(jìn)行簡化。JLS規(guī)定:Strings computed by constant expressions (&yacute;15.28) are computed at compile time and then treated as if they were literals.

            ????對于String str2 ="3"+"jf"+"3"+"4";我們說僅僅創(chuàng)建一個(gè)對象。注意,“創(chuàng)建多少對象”的討論是說運(yùn)行時(shí)創(chuàng)建多少對象。

            ????BTW:編譯時(shí)優(yōu)化

            				????String x = "aaa " + "bbb ";
            ????if (false) {
            ????????x = x + "ccc ";
            ????}
            ????x +=??"ddd ";

            ????等價(jià)于:

            ????String x = "aaa bbb ";
            ????x = x + "ddd ";
            //這個(gè)地方我自己進(jìn)行了編譯,不過和他的結(jié)論不一樣,好像當(dāng)用x+="ddd"的時(shí)候和直接的x="aaa"+"bbb"+"ddd" 不同,但是具體為什么我也不清楚,正在研究中。。。

            4、不變類
            ????String對象是不可改變的(immutable)。有人對str = 1+2+str+3+4;語句提出疑問,怎么str的內(nèi)容可以改變?其實(shí)仍然是因?yàn)椴磺宄阂米兞颗c對象的區(qū)別。str僅僅是引用變量,它的值——它持有的引用可以改變。你不停地創(chuàng)建新對象,我就不斷地改變指向。[參考TIJ的Read-only classes。]

            ????不變類的關(guān)鍵是,對于對象的所有操作都不可能改變原來的對象[只要需要,就返回一個(gè)改變了的新對象]。這就保證了對象不可改變。為什么要將一個(gè)類設(shè)計(jì)成不變類?有一個(gè)OOD設(shè)計(jì)的原則:Law of Demeter。其廣義解讀是:

            ????使用不變類。只要有可能,類應(yīng)當(dāng)設(shè)計(jì)為不變類。
            posted on 2006-07-11 22:29 Merlin 閱讀(389) 評論(0)  編輯 收藏 引用 所屬分類: java基礎(chǔ)篇
            日本三级久久网| 欧美一区二区三区久久综合| 久久夜色精品国产欧美乱| 午夜精品久久久久久| 久久精品国产一区二区 | 伊人久久大香线蕉AV色婷婷色| 精品久久人人爽天天玩人人妻 | 国产综合精品久久亚洲| 久久国产精品-国产精品| 久久综合狠狠色综合伊人| 精品久久久久久中文字幕人妻最新| 777午夜精品久久av蜜臀| 亚洲午夜久久久影院| 一本一本久久a久久综合精品蜜桃| 亚洲精品无码专区久久久| 精品久久久久久无码中文字幕一区| 国产精品一久久香蕉产线看| 久久精品国内一区二区三区| 久久高潮一级毛片免费| 少妇人妻综合久久中文字幕| 久久久久久毛片免费播放| 久久精品9988| 伊人热热久久原色播放www| 亚洲AV日韩精品久久久久久 | 天天做夜夜做久久做狠狠| 欧美精品国产综合久久| 91视频国产91久久久| 久久久综合香蕉尹人综合网| 一本久久a久久精品vr综合| 久久se精品一区精品二区| 亚洲午夜无码久久久久小说| 久久天天躁狠狠躁夜夜avapp| 亚洲国产精久久久久久久| 久久久一本精品99久久精品88| 国产日产久久高清欧美一区| 国内精品久久久久影院亚洲| 午夜不卡888久久| 性色欲网站人妻丰满中文久久不卡| 国内精品久久久久久久久| 久久ww精品w免费人成| 中文字幕久久亚洲一区|