首先,讓我們來看一下下邊這兩種定義String的區(qū)別。 Stringstr1 ='abc';Stringstr2 =); 那么,它們兩個在內(nèi)存中是怎么分配的呢。 str1和str2是兩個對象的引用,存放在Java棧中。第一條語句沒有在堆中分配內(nèi)存,而是將“abc”保存在常量池中。對于第二條語句,同樣會在常量池中保存一個“abcd”的字符串,當new時,會拷貝一份該字符串存放到堆中,于是str2指向了堆中的那個“abcd”字符串。同理,如果我們再定義一句String str3 = “abc”;那么,棧中的引用str3會指向跟str1相同的那個常量池中的”abc”。 接下來,讓我們通過幾段代碼來分析一下String。 1、 publicstaticvoidmain(String args) { String str1 ='abc'; String str2 ='abc'; System.out.println(str1 == str2);// true} 分析:這里結(jié)果為true。當程序加載String str1 = “abc”; 這句代碼時,會去常量池中檢查有沒有”abc”這個對象,如果沒有,則在常量池中創(chuàng)建一個”abc”對象。同樣,當加載String str2 = “abc”; 這句代碼時,因為常量池中已經(jīng)存在了”abc”這個對象,則str2直接指向常量池中的”abc”對象,它們兩個指向的是同一個常量池中的對象,所以輸出為true。 2、 publicstaticvoidmain(String args) { String str1 ='abc'; String str2 =newString('abc'); String str3 =newString('abc'); System.out.println(str1 == str2);// falseSystem.out.println(str2 == str3);// false} 分析:當程序加載String str1 = “abc”;這句的時候,在常量池里會創(chuàng)建”abc”這個對象,str1指向常量池中的”abc”對象。當程序加載String str2 = new String(“abc”);這句的時候,因為常量池里已經(jīng)有了”abc”這個對象,所以在常量池中不新建對象,但是在java堆中會新建一個”abc”對象,str2指向Java堆中新建的”abc”對象。當程序加載String str3 = new String(“abc”);這句的時候,同樣因為常量池中已經(jīng)有”abc”這個對象,所以不在常量池中新建”abc”對象,但是也會在Java堆中新建一個”abc”對象,str3指向Java堆中新建的這個”abc”對象,注意,這個”abc”對象跟str2指向的”abc”對象不是同一個,str1、str2和str3指向的都是不同的對象,所以輸出結(jié)果都為false。 3、 publicstaticvoidmain(String args) { String str1 ='; System.out.println(str1 =='he'+');// true} 分析:這里輸出為true?!県e” + “l(fā)lo” 兩個雙引號形式的字符串常量相加, 在編譯的時候直接會被轉(zhuǎn)為一個字符串常量”hello”并保存在常量池中。 4、 publicstaticvoidmain(String args) { String str1 ='hello'; String str2 ='he'; System.out.println(str1 == str2 +'llo');// false} 分析:這里輸出為false。str2 + “llo” 字符串變量和字符串常量相加的時候,內(nèi)部是使用StringBuilder類的append方法和toString方法來實現(xiàn)的。而StringBuilder類toString方法返回的字符串是通過構(gòu)造函數(shù)創(chuàng)建的。所以生成的”hello”對象是在JAVA堆里。 5、 publicstaticvoidmain(String args) { String str1 ='hello'; String str2 =newString('hello'); System.out.println(str1 == str2.intern);// true} 分析:這里輸出為true。String的intern方法是擴充常量池的一個方法,當String實例str2調(diào)用intern方法時,Java會在常量池中查找是否有相同Unicode的字符串常量對象,如果有,則返回其引用,如果沒有,則在常量池中增加一個Unicode等于str2的字符串常量對象并返回它的引用。這里str2.intern方法返回的是指向常量池中”hello”的引用,所以輸出為true。 6、 publicstaticvoidmain(String args) { String str1 ='hello'; str1.concat(' world'); System.out.println(str1);// hello} 分析:這里輸出為”hello”。因為String是不可變(final)的,所以輸出為”hello”。如果想可變,可以使用StringBuilder或StringBuffer類,或者定義一個新的變量接收一下方法的返回值String str2 = str1.concat(” world”);。 通過上邊幾個例子,我們應(yīng)該能對Java中的字符串String有了一個很好的了解。下邊來介紹一些在筆試面試中,經(jīng)常遇到的問題。 1、String s = new String(“xyz”); 創(chuàng)建了幾個String Object? 答案是1個或2個。如果之前在常量池中已經(jīng)創(chuàng)建過'xyz'對象的話,那么只會在Java堆中創(chuàng)建一個'xyz'對象, 如果常量池中沒有的話,也會在常量池中創(chuàng)建一個'對象,所以說是1個或2個。 2、是否可以繼承String類? String類是final類故不可以被繼承。 3、數(shù)組有沒有l(wèi)ength這個方法? String有沒有l(wèi)ength這個方法? 數(shù)組沒有length這個方法,有length屬性。String有length這個方法。 4、Java中判斷字符串值是否相等是用”==”還是”是判斷兩個字符串的地址是否相同。 5、Java的String,StringBuffer,StringBuilder有什么區(qū)別? 6、下面這段代碼的運行結(jié)果是什么? 7、下面這段代碼的運行結(jié)果是什么? |
|