Java面試題之Java基礎部分 31-40題

31String s = "Hello";s = s + " world!";這兩行代碼執行後,原始的String對象中的內容到底變了沒有?

   沒有。因爲String被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內容是 "Hello",然後我們對s進行了+操作,那麼s所指向的那個對象是否發生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個 String對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是s這個引用變量不再指向它了。

    通過上面的說明,我們很容易導出另一個結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那麼使用String來代表字符串的話會引起很大的內存開銷。因爲 String對象建立之後不能再改變,所以對於每一個不同的字符串,都需要一個String對象來表示。這時,應該考慮使用StringBuffer類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。並且,這兩種類的對象轉換十分容易。 同時,我們還可以知道,如果要使用內容相同的字符串,不必每次都new一個String。例如我們要在構造器中對一個名叫sString引用變量進行初始化,把它設置爲初始值,應當這樣做:

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類故不可以繼承。

 

33String s = new String("xyz");創建了幾個String Object?二者之間有什麼區別?

兩個或一個,”xyz”對應一個對象,這個對象放在字符串常量緩衝區,常量”xyz”不管出現多少遍,都是緩衝區中的那一個。New String每寫一遍,就創建一個新的對象,它一句那個常量”xyz”對象的內容來創建出一個新String對象。如果以前就用過’xyz’,這句代表就不會創建”xyz”自己了,直接從緩衝區拿。

 

34、StringStringBuffer的區別

(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

4String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,所以,將StringBuffer對象存儲進Java集合類中時會出現問題。

 

【擴展】StringStringBufferStringBuilder區別

String是字符串,它是不可以改變的。

StringBuffer是一個緩衝區,它相當於一個可變的字符串。它是線程同步的

StringBuilderStringBuffer應用一樣,但是是線程不安全的,它的效率高。

 

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語句後執行,所以,返回的結果是2return並不是讓函數馬上返回,而是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語句都執行並且最終返回到調用者那裏的是finallyreturn的值;而如果finally中沒有return,則理所當然的返回的是try或者catchreturn的值,但是finally中的代碼是必須要執行的,而且是在return前執行,除非碰到exit()

 

40final, finally, finalize的區別。

1final 用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。

內部類要訪問局部變量,局部變量必須定義成final類型,例如,一段代碼……

2finally是異常處理語句結構的一部分,表示總是執行。

3finalizeObject類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,例如關閉文件等。JVM不保證此方法總被調用

發佈了116 篇原創文章 · 獲贊 34 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章