31、String s = "Hello";s = s + " world!";這兩行代碼執行後,原始的String對象中的內容到底變了沒有?
沒有。因爲String被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內容是 "Hello",然後我們對s進行了+操作,那麼s所指向的那個對象是否發生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個 String對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是s這個引用變量不再指向它了。
通過上面的說明,我們很容易導出另一個結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那麼使用String來代表字符串的話會引起很大的內存開銷。因爲 String對象建立之後不能再改變,所以對於每一個不同的字符串,都需要一個String對象來表示。這時,應該考慮使用StringBuffer類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。並且,這兩種類的對象轉換十分容易。 同時,我們還可以知道,如果要使用內容相同的字符串,不必每次都new一個String。例如我們要在構造器中對一個名叫s的String引用變量進行初始化,把它設置爲初始值,應當這樣做:
public class Demo
{
private String s;
...
public Demo
{
s = "Initial Value";
}
...
}
而非 s = new String("Initial Value"); 後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,並且沒有意義,因爲String對象不可改變,所以對於內容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調用上面的構造器創建多個對象,他們的String類型屬性s都指向同一個對象。 上面的結論還基於這樣一個事實:對於字符串常量,如果內容相同,Java認爲它們代表同一個String對象。而用關鍵字new調用構造器,總是會創建一個新的對象,無論內容是否相同。
至於爲什麼要把String類設計成不可變類,是它的用途決定的。其實不只String,很多Java標準類庫中的類都是不可變的。在開發一個系統的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。不可變類有一些優點,比如因爲它的對象是隻讀的,所以多線程併發訪問也不會有任何問題。當然也有一些缺點,比如每個不同的狀態都要一個對象來代表,可能會造成性能上的問題。所以Java標準類庫還提供了一個可變版本,即 StringBuffer。
32、是否可以繼承String類?
String類是final類故不可以繼承。
33、String s = new String("xyz");創建了幾個String Object?二者之間有什麼區別?
兩個或一個,”xyz”對應一個對象,這個對象放在字符串常量緩衝區,常量”xyz”不管出現多少遍,都是緩衝區中的那一個。New String每寫一遍,就創建一個新的對象,它一句那個常量”xyz”對象的內容來創建出一個新String對象。如果以前就用過’xyz’,這句代表就不會創建”xyz”自己了,直接從緩衝區拿。
34、String和StringBuffer的區別
(1)String專門定義不變字符串,而StingBuffer用來定義可變字符串
(2)兩者在性能上的區別:
String比較適合短的字符串,當多個字符串聯合時要先轉爲StringBuffer,再聯合,速度慢;StingBuffer適合動態增加的字符串,可以將多個字符串值直接聯合,效率高。
StringBuffer sbf = new StringBuffer();
for(int i=0;i<100;i++)
{
sbf.append(i);
}
上面的代碼效率很高,因爲只創建了一個StringBuffer對象,而下面的代碼效率很低,因爲創建了101個對象。
String str = new String();
for(int i=0;i<100;i++)
{
str = str + i;
}
(3)String實現了equals方法,new String(“abc”).equals(newString(“abc”)的結果爲true,而StringBuffer沒有實現equals方法,所以,
new StringBuffer(“abc”).equals(newStringBuffer(“abc”)的結果爲false。
(4)String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,所以,將StringBuffer對象存儲進Java集合類中時會出現問題。
【擴展】String與StringBuffer和StringBuilder區別
String是字符串,它是不可以改變的。
StringBuffer是一個緩衝區,它相當於一個可變的字符串。它是線程同步的
StringBuilder與StringBuffer應用一樣,但是是線程不安全的,它的效率高。
35、如何把一段逗號分割的字符串轉換成一個數組?
(1) 用正則表達式,代碼大概爲:String [] result = orgStr.split(“,”);
(2)用 StingTokenizer ,代碼爲:StringTokenizer tokener = StringTokenizer(orgStr,”,”);
String [] result =new String[tokener .countTokens()];
int i=0;
while(tokener.hasNext(){result[i++]=toker.nextToken();}
36、數組有沒有length()這個方法? String有沒有length()這個方法?
數組沒有length()這個方法,有length的屬性。String有有length()這個方法。
37、下面這條語句一共創建了多少個對象:String s="a"+"b"+"c"+"d";
只創建了一個String對象。javac編譯可以對字符串常量直接相加的表達式進行優化,不必要等到運行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。
答:對於如下代碼:
String s1 = "a";
String s2 = s1 + "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");
第一條語句打印的結果爲false,第二條語句打印的結果爲true,這說明javac編譯可以對字符串常量直接相加的表達式進行優化,不必要等到運行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。
題目中的第一行代碼被編譯器在編譯時優化後,相當於直接定義了一個”abcd”的字符串,所以,上面的代碼應該只創建了一個String對象。寫如下兩行代碼,
String s ="a" + "b" + "c" + "d";
System.out.println(s== "abcd");
最終打印的結果應該爲true。
38、try {}裏有一個return語句,那麼緊跟在這個try後的finally {}裏的code會不會被執行,什麼時候被執行,在return前還是後?
會執行,在return 前執行。
39、下面的程序代碼輸出的結果是多少?
public class smallT
{
public static void main(String args[])
{
smallT t = new smallT();
int b = t.get();
System.out.println(b);
}
public int get()
{
try
{
return 1 ;
}
finally
{
return 2 ;
}
}
}
返回的結果是2。
可以通過下面一個例子程序來幫助我解釋這個答案,從下面例子的運行結果中可以發現,try中的return語句調用的函數先於finally中調用的函數執行,也就是說return語句先執行,finally語句後執行,所以,返回的結果是2。return並不是讓函數馬上返回,而是return語句執行後,將把返回結果放置進函數棧中,此時函數並不是馬上返回,它要執行finally語句後才真正開始返回。
在講解答案時可以用下面的程序來幫助分析:
public classTest {
public static voidmain(String[] args) {
System.out.println(newTest().test());
}
int test()
{ try { return func1();}
finally{ return func2();}
}
int func1()
{ System.out.println("func1");
return 1;
}
int func2()
{ System.out.println("func2");
return 2;
}
}
-----------執行結果-----------------
func1
func2
2
【結論】 根據java規範:在try-catch-finally中,如果try-finally或者catch-finally中都有return,則兩個return語句都執行並且最終返回到調用者那裏的是finally中return的值;而如果finally中沒有return,則理所當然的返回的是try或者catch中return的值,但是finally中的代碼是必須要執行的,而且是在return前執行,除非碰到exit()。
40、final, finally, finalize的區別。
(1)final 用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。
內部類要訪問局部變量,局部變量必須定義成final類型,例如,一段代碼……
(2)finally是異常處理語句結構的一部分,表示總是執行。
(3)finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,例如關閉文件等。JVM不保證此方法總被調用