電子書下載地址: http://wiki.jikexueyuan.com/project/java-interview-bible/
1. 下面程序的運行結(jié)果是()
String str1 = "hello";
String str2 = "he" + new String("llo");
System.err.println(str1 == str2);
答案:false
解析:因為 str2 中的 llo 是新申請的內(nèi)存塊,而 == 判斷的是對象的地址而非值,所以不一樣。如果是String str2 = str1
,那么就是 true 了。
2. 下面代碼的運行結(jié)果為?
import java.io.*;
import java.util.*;
public class foo{
public static void main (String[] args){
String s;
System.out.println("s=" + s);
}
}
A. 代碼得到編譯,并輸出 “s=”
B. 代碼得到編譯,并輸出 “s=null”
C. 由于 String s 沒有初始化,代碼不能編譯通過
D. 代碼得到編譯,但捕獲到 NullPointException異常
答案:C
解析:開始以為會輸出 null 什么的,運行后才發(fā)現(xiàn) Java 中所有定義的基本類型或?qū)ο蠖急仨毘跏蓟拍茌敵鲋怠?/p>
3. String 是最基本的數(shù)據(jù)類型嗎?
答:不是。Java 中的基本數(shù)據(jù)類型只有 8 個:byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type)和枚舉類型(enumeration type),剩下的都是引用類型(reference type)。
4. 數(shù)組有沒有 length() 方法? String 有沒有 length() 方法?
答:數(shù)組沒有 length()方法,有 length 的屬性。String 有 length()方法。JavaScript 中,獲得字符串的長度是通過 length 屬性得到的,這一點容易和 Java 混淆。
5. 是否可以繼承 String 類?
答:String 類是 final 類,不可以被繼承。
補充:繼承 String 本身就是一個錯誤的行為,對 String 類型最好的重用方式是關(guān)聯(lián)(HAS-A)而不是繼承(IS-A)。
6. String 和StringBuilder、StringBuffer 的區(qū)別?
答:Java 平臺提供了兩種類型的字符串:String 和StringBuffer / StringBuilder,它們可以儲存和操作字符串。其中 String 是只讀字符串,也就意味著 String 引用的字符串內(nèi)容是不能被改變的。而 StringBuffer 和 StringBuilder 類表示的字符串對象可以直接進行修改。StringBuilder 是 JDK 1.5 中引入的,它和 StringBuffer 的方法完全相同,區(qū)別在于它是在單線程環(huán)境下使用的,因為它的所有方面都沒有被 synchronized 修飾,因此它的效率也比 StringBuffer 略高。
有一個面試題問:有沒有哪種情況用 + 做字符串連接比調(diào)用 StringBuffer / StringBuilder 對象的 append 方法性能更好?如果連接后得到的字符串在靜態(tài)存儲區(qū)中是早已存在的,那么用+做字符串連接是優(yōu)于 StringBuffer / StringBuilder 的 append 方法的。
7. String s=new String(“xyz”);創(chuàng)建了幾個字符串對象?
答:兩個對象,一個是靜態(tài)存儲區(qū)的"xyz",一個是用new創(chuàng)建在堆上的對象。
8. 將字符 “12345” 轉(zhuǎn)換成 long 型
解答: String s=”12345″;
long num=Long.valueOf(s).longValue();
9. 為了顯示 myStr = 23 這樣的結(jié)果,寫出在控制臺輸入的命令
public class MyClass {
public static void main(String args[]) {
String s1 = args[0];
String s2 = args[1];
String myStr = args[2];
System.out.printin(“myStr =” + s2 + myStr);
}
}
答:java MyClass 1 2 3 4
10. String s = "Hello";s = s + " world!”;
這兩行代碼執(zhí)行后,原始的 String 對象中的內(nèi)容到底變了沒有?
沒有。因為 String 被設(shè)計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s 原先指向一個 String 對象,內(nèi)容是 "Hello",然后我們對 s 進行了+操作,那么 s 所指向的那個對象是否發(fā)生了改變呢?答案是沒有。這時, s 不指向原來那個對象了,而指向了另一個 String 對象,內(nèi)容為 "Hello world!",原來那個對象還存在于內(nèi)存之中,只是 s 這個引用變量不再指向它了。
通過上面的說明,我們很容易導(dǎo)出另一個結(jié)論,如果經(jīng)常對字符串進行各種各樣的修改,或者說,不可預(yù)見的修改,那么使用 String 來代表字符串的話會引起很大的內(nèi)存開銷。因為 String 對象建立之后不能再改變,所以對于每一個不同的字符串,都需要一個 String 對象來表示。這時,應(yīng)該考慮使用 StringBuffer 類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。并且,這兩種類的對象轉(zhuǎn)換十分容易。
同時,我們還可以知道,如果要使用內(nèi)容相同的字符串,不必每次都 new 一個 String。例如我們要在構(gòu)造器中對一個名叫 s 的 String 引用變量進行初始化,把它設(shè)置為初始值,應(yīng)當(dāng)這樣做:
public class Demo {
private String s;
...
public Demo {
s = "Initial Value";
}
...
}
而非
s = new String("Initial Value”);
后者每次都會調(diào)用構(gòu)造器,生成新對象,性能低下且內(nèi)存開銷大,并且沒有意義,因為 String 對象不可改變,所以對于內(nèi)容相同的字符串,只要一個 String 對象來表示就可以了。也就說,多次調(diào)用上面的構(gòu)造器創(chuàng)建多個對象,他們的 String 類型屬性 s 都指向同一個對象。
上面的結(jié)論還基于這樣一個事實:對于字符串常量,如果內(nèi)容相同,Java 認為它們代表同一個 String 對象。而用關(guān)鍵字 new 調(diào)用構(gòu)造器,總是會創(chuàng)建一個新的對象,無論內(nèi)容是否相同。
至于為什么要把 String 類設(shè)計成不可變類,是它的用途決定的。其實不只 String,很多 Java 標(biāo)準(zhǔn)類庫中的類都是不可變的。在開發(fā)一個系統(tǒng)的時候,我們有時候也需要設(shè)計不可變類,來傳遞一組相關(guān)的值,這也是面向?qū)ο笏枷氲捏w現(xiàn)。不可變類有一些優(yōu)點,比如因為它的對象是只讀的,所以多線程并發(fā)訪問也不會有任何問題。當(dāng)然也有一些缺點,比如每個不同的狀態(tài)都要一個對象來代表,可能會造成性能上的問題。所以 Java 標(biāo)準(zhǔn)類庫還提供了一個可變版本,即 StringBuffer。
11. 如何把一段逗號分割的字符串轉(zhuǎn)換成一個數(shù)組?
如果不查 jdk api,我很難寫出來!我可以說說我的思路:
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();}
12. 下面這條語句一共創(chuàng)建了多少個對象:String s=“a”+”b”+”c”+”d”;
答:對于如下代碼:
String s1 = "a";
String s2 = s1 + "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");
第一條語句打印的結(jié)果為 false ,第二條語句打印的結(jié)果為 true,這說明 Javac 編譯可以對字符串常量直接相加的表達式進行優(yōu)化,不必要等到運行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結(jié)果。
題目中的第一行代碼被編譯器在編譯時優(yōu)化后,相當(dāng)于直接定義了一個”abcd”的字符串,所以,上面的代碼應(yīng)該只創(chuàng)建了一個 String 對象。寫如下兩行代碼,
String s ="a" + "b" + "c" + "d";
System.out.println(s== "abcd");
最終打印的結(jié)果應(yīng)該為 true。
13. String 和 StringBuffer 的區(qū)別?
答:JAVA 平臺提供了兩個類:String 和 StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數(shù)據(jù)。這個 String 類提供了數(shù)值不可改變的字符串。而這個 StringBuffer 類提供的字符串進行修改。當(dāng)你知道字符數(shù)據(jù)要改變 的時候你就可以使用 StringBuffer。典型地,你可以使用 StringBuffers 來動態(tài)構(gòu)造字符數(shù)據(jù)。
14. String, StringBuffer StringBuilder的區(qū)別。
答:
String 的長度是不可變的;
StringBuffer的長度是可變的,如果你對字符串中的內(nèi)容經(jīng)常進行操作,特別是內(nèi)容要修改時,那么使用 StringBuffer,如果最后需要 String,那么使用 StringBuffer 的 toString() 方法;線程安全;
StringBuilder 是從 JDK 5 開始,為StringBuffer該類補充了一個單個線程使用的等價類;通常應(yīng)該優(yōu)先使用 StringBuilder 類,因為它支持所有相同的操作,但由于它不執(zhí)行同步,所以速度更快。