Java笔试题
精選30道Java筆試題解答
都是一些非常非常基礎(chǔ)的題,是我最近參加各大IT公司筆試后靠記憶記下來的,經(jīng)過整理獻(xiàn)給與我一樣參加各大IT校園招聘的同學(xué)們,純考Java基礎(chǔ)功底,老手們就不用進(jìn)來了,免得笑話我們這些未出校門的孩紙們,但是IT公司就喜歡考這些基礎(chǔ)的東西,所以為了能進(jìn)大公司就~~~當(dāng)復(fù)習(xí)期末考吧。花了不少時間整理,在整理過程中也學(xué)到了很多東西,請大家認(rèn)真對待每一題~~~
下面都是我自己的答案非官方,僅供參考,如果有疑問或錯誤請一定要提出來,大家一起進(jìn)步啦~~~
1. 下面哪些是Thread類的方法()
A start() B run() C exit() D getPriority()
答案:ABD
解析:看Java API docs吧:http://docs.oracle.com/javase/7/docs/api/,exit()是System類的方法,如System.exit(0)。
2. 下面關(guān)于java.lang.Exception類的說法正確的是()
A 繼承自Throwable B Serialable CD 不記得,反正不正確
答案:A
解析:Java異常的基類為java.lang.Throwable,java.lang.Error和java.lang.Exception繼承 Throwable,RuntimeException和其它的Exception等繼承Exception,具體的RuntimeException繼承RuntimeException。
擴(kuò)展:錯誤和異常的區(qū)別(Error vs Exception)
1)java.lang.Error: Throwable的子類,用于標(biāo)記嚴(yán)重錯誤。合理的應(yīng)用程序不應(yīng)該去try/catch這種錯誤。絕大多數(shù)的錯誤都是非正常的,就根本不該出現(xiàn)的。
java.lang.Exception: Throwable的子類,用于指示一種合理的程序想去catch的條件。即它僅僅是一種程序運(yùn)行條件,而非嚴(yán)重錯誤,并且鼓勵用戶程序去catch它。
2) Error和RuntimeException 及其子類都是未檢查的異常(unchecked exceptions),而所有其他的Exception類都是檢查了的異常(checked exceptions).
checked exceptions:通常是從一個可以恢復(fù)的程序中拋出來的,并且最好能夠從這種異常中使用程序恢復(fù)。比如FileNotFoundException, ParseException等。檢查了的異常發(fā)生在編譯階段,必須要使用try…catch(或者throws)否則編譯不通過。
unchecked exceptions:通常是如果一切正常的話本不該發(fā)生的異常,但是的確發(fā)生了。發(fā)生在運(yùn)行期,具有不確定性,主要是由于程序的邏輯問題所引起的。比如ArrayIndexOutOfBoundException, ClassCastException等。從語言本身的角度講,程序不該去catch這類異常,雖然能夠從諸如RuntimeException這樣的異常中catch并恢復(fù),但是并不鼓勵終端程序員這么做,因為完全沒要必要。因為這類錯誤本身就是bug,應(yīng)該被修復(fù),出現(xiàn)此類錯誤時程序就應(yīng)該立即停止執(zhí)行。 因此,面對Errors和unchecked exceptions應(yīng)該讓程序自動終止執(zhí)行,程序員不該做諸如try/catch這樣的事情,而是應(yīng)該查明原因,修改代碼邏輯。
RuntimeException:RuntimeException體系包括錯誤的類型轉(zhuǎn)換、數(shù)組越界訪問和試圖訪問空指針等等。
處理RuntimeException的原則是:如果出現(xiàn) RuntimeException,那么一定是程序員的錯誤。例如,可以通過檢查數(shù)組下標(biāo)和數(shù)組邊界來避免數(shù)組越界訪問異常。其他(IOException等等)checked異常一般是外部錯誤,例如試圖從文件尾后讀取數(shù)據(jù)等,這并不是程序本身的錯誤,而是在應(yīng)用環(huán)境中出現(xiàn)的外部錯誤。
3. 下面程序的運(yùn)行結(jié)果是()
String str1 = "hello";
String str2 = "he" + new String("llo");
System.err.println(str1 == str2);
答案:false
解析:因為str2中的llo是新申請的內(nèi)存塊,而==判斷的是對象的地址而非值,所以不一樣。如果是String str2 = str1,那么就是true了。
4.下列說法正確的有()
A. class中的constructor不可省略
B. constructor必須與class同名,但方法不能與class同名
C. constructor在一個對象被new時執(zhí)行
D.一個class只能定義一個constructor
答案:C
解析:這里可能會有誤區(qū),其實(shí)普通的類方法是可以和類名同名的,和構(gòu)造方法唯一的區(qū)分就是,構(gòu)造方法沒有返回值。
5. 具體選項不記得,但用到的知識如下:
String []a = new String[10];
則:a[0]~a[9] = null
a.length = 10
如果是int []a = new int[10];
則:a[0]~a[9] = 0
a.length = 10
6. 下面程序的運(yùn)行結(jié)果:()
public static void main(String args[]) {
Thread t = new Thread() {
public void run() {
pong();
}
};
t.run();
System.out.print("ping");
}
static void pong() {
System.out.print("pong");
}
A pingpong B pongping C pingpong和pongping都有可能 D 都不輸出
答案:B
解析:這里考的是Thread類中start()和run()方法的區(qū)別了。start()用來啟動一個線程,當(dāng)調(diào)用start方法后,系統(tǒng)才會開啟一個新的線程,進(jìn)而調(diào)用run()方法來執(zhí)行任務(wù),而單獨(dú)的調(diào)用run()就跟調(diào)用普通方法是一樣的,已經(jīng)失去線程的特性了。因此在啟動一個線程的時候一定要使用start()而不是run()。
7. 下列屬于關(guān)系型數(shù)據(jù)庫的是()
A. Oracle B MySql C IMS D MongoDB
答案:AB
解答:IMS(Information Management System)數(shù)據(jù)庫是IBM公司開發(fā)的兩種數(shù)據(jù)庫類型之一;
一種是關(guān)系數(shù)據(jù)庫,典型代表產(chǎn)品:DB2;
另一種則是層次數(shù)據(jù)庫,代表產(chǎn)品:IMS層次數(shù)據(jù)庫。
非關(guān)系型數(shù)據(jù)庫有MongoDB、memcachedb、Redis等。
8. GC線程是否為守護(hù)線程?()
答案:是
解析:線程分為守護(hù)線程和非守護(hù)線程(即用戶線程)。
只要當(dāng)前JVM實(shí)例中尚存在任何一個非守護(hù)線程沒有結(jié)束,守護(hù)線程就全部工作;只有當(dāng)最后一個非守護(hù)線程結(jié)束時,守護(hù)線程隨著JVM一同結(jié)束工作。
守護(hù)線程最典型的應(yīng)用就是 GC (垃圾回收器)
9. volatile關(guān)鍵字是否能保證線程安全?()
答案:不能
解析:volatile關(guān)鍵字用在多線程同步中,可保證讀取的可見性,JVM只是保證從主內(nèi)存加載到線程工作內(nèi)存的值是最新的讀取值,而非cache中。但多個線程對
volatile的寫操作,無法保證線程安全。例如假如線程1,線程2 在進(jìn)行read,load 操作中,發(fā)現(xiàn)主內(nèi)存中count的值都是5,那么都會加載這個最新的值,在線程1堆count進(jìn)行修改之后,會write到主內(nèi)存中,主內(nèi)存中的count變量就會變?yōu)?;線程2由于已經(jīng)進(jìn)行read,load操作,在進(jìn)行運(yùn)算之后,也會更新主內(nèi)存count的變量值為6;導(dǎo)致兩個線程及時用volatile關(guān)鍵字修改之后,還是會存在并發(fā)的情況。
10. 下列說法正確的是()
A LinkedList繼承自List
B AbstractSet繼承自Set
C HashSet繼承自AbstractSet
D WeakMap繼承自HashMap
答案:AC
解析:下面是一張下載的Java中的集合類型的繼承關(guān)系圖,一目了然。
11. 存在使i + 1 < i的數(shù)嗎()
答案:存在
解析:如果i為int型,那么當(dāng)i為int能表示的最大整數(shù)時,i+1就溢出變成負(fù)數(shù)了,此時不就<i了嗎。
擴(kuò)展:存在使i > j || i <= j不成立的數(shù)嗎()
答案:存在
解析:比如Double.NaN或Float.NaN,感謝@BuilderQiu網(wǎng)友指出。
12. 0.6332的數(shù)據(jù)類型是()
A float B double C Float D Double
答案:B
解析:默認(rèn)為double型,如果為float型需要加上f顯示說明,即0.6332f
13. 下面哪個流類屬于面向字符的輸入流( )
ABufferedWriter BFileInputStream CObjectInputStream D InputStreamReader
答案:D
解析:Java的IO操作中有面向字節(jié)(Byte)和面向字符(Character)兩種方式。
面向字節(jié)的操作為以8位為單位對二進(jìn)制的數(shù)據(jù)進(jìn)行操作,對數(shù)據(jù)不進(jìn)行轉(zhuǎn)換,這些類都是InputStream和OutputStream的子類。
面向字符的操作為以字符為單位對數(shù)據(jù)進(jìn)行操作,在讀的時候?qū)⒍M(jìn)制數(shù)據(jù)轉(zhuǎn)為字符,在寫的時候?qū)⒆址D(zhuǎn)為二進(jìn)制數(shù)據(jù),這些類都是Reader和Writer的子類。
總結(jié):以InputStream(輸入)/OutputStream(輸出)為后綴的是字節(jié)流;
以Reader(輸入)/Writer(輸出)為后綴的是字符流。
擴(kuò)展:Java流類圖結(jié)構(gòu),一目了然,解決大部分選擇題:
14. Java接口的修飾符可以為()
A private B protected C final D abstract
答案:CD
解析:接口很重要,為了說明情況,這里稍微啰嗦點(diǎn):
(1)接口用于描述系統(tǒng)對外提供的所有服務(wù),因此接口中的成員常量和方法都必須是公開(public)類型的,確保外部使用者能訪問它們;
(2)接口僅僅描述系統(tǒng)能做什么,但不指明如何去做,所以接口中的方法都是抽象(abstract)方法;
(3)接口不涉及和任何具體實(shí)例相關(guān)的細(xì)節(jié),因此接口沒有構(gòu)造方法,不能被實(shí)例化,沒有實(shí)例變量,只有靜態(tài)(static)變量;
(4)接口的中的變量是所有實(shí)現(xiàn)類共有的,既然共有,肯定是不變的東西,因為變化的東西也不能夠算共有。所以變量是不可變(final)類型,也就是常量了。
(5)接口中不可以定義變量?如果接口可以定義變量,但是接口中的方法又都是抽象的,在接口中無法通過行為來修改屬性。有的人會說了,沒有關(guān)系,可以通過 實(shí)現(xiàn)接口的對象的行為來修改接口中的屬性。這當(dāng)然沒有問題,但是考慮這樣的情況。如果接口 A 中有一個public 訪問權(quán)限的靜態(tài)變量 a。按照 Java 的語義,我們可以不通過實(shí)現(xiàn)接口的對象來訪問變量 a,通過 A.a = xxx; 就可以改變接口中的變量 a 的值了。正如抽象類中是可以這樣做的,那么實(shí)現(xiàn)接口 A 的所有對象也都會自動擁有這一改變后的 a 的值了,也就是說一個地方改變了 a,所有這些對象中 a 的值也都跟著變了。這和抽象類有什么區(qū)別呢,怎么體現(xiàn)接口更高的抽象級別呢,怎么體現(xiàn)接口提供的統(tǒng)一的協(xié)議呢,那還要接口這種抽象來做什么呢?所以接口中 不能出現(xiàn)變量,如果有變量,就和接口提供的統(tǒng)一的抽象這種思想是抵觸的。所以接口中的屬性必然是常量,只能讀不能改,這樣才能為實(shí)現(xiàn)接口的對象提供一個統(tǒng) 一的屬性。
通俗的講,你認(rèn)為是要變化的東西,就放在你自己的實(shí)現(xiàn)中,不能放在接口中去,接口只是對一類事物的屬性和行為更高層次的抽象。對修改關(guān)閉,對擴(kuò)展(不同的實(shí)現(xiàn) implements)開放,接口是對開閉原則的一種體現(xiàn)。
所以:
接口的方法默認(rèn)是public abstract;
接口中不可以定義變量即只能定義常量(加上final修飾就會變成常量)。所以接口的屬性默認(rèn)是public static final 常量,且必須賦初值。
注意:final和abstract不能同時出現(xiàn)。
15. 不通過構(gòu)造函數(shù)也能創(chuàng)建對象嗎()
A 是 B 否
答案:A
解析:Java創(chuàng)建對象的幾種方式(重要):
(1) 用new語句創(chuàng)建對象,這是最常見的創(chuàng)建對象的方法。
(2) 運(yùn)用反射手段,調(diào)用java.lang.Class或者java.lang.reflect.Constructor類的newInstance()實(shí)例方法。
(3) 調(diào)用對象的clone()方法。
(4) 運(yùn)用反序列化手段,調(diào)用java.io.ObjectInputStream對象的 readObject()方法。
(1)和(2)都會明確的顯式的調(diào)用構(gòu)造函數(shù) ;(3)是在內(nèi)存上對已有對象的影印,所以不會調(diào)用構(gòu)造函數(shù) ;(4)是從文件中還原類的對象,也不會調(diào)用構(gòu)造函數(shù)。
16. ArrayList list = new ArrayList(20);中的list擴(kuò)充幾次()
A 0 B 1 C 2 D 3
答案:A
解析:這里有點(diǎn)迷惑人,大家都知道默認(rèn)ArrayList的長度是10個,所以如果你要往list里添加20個元素肯定要擴(kuò)充一次(擴(kuò)充為原來的1.5倍),但是這里顯示指明了需要多少空間,所以就一次性為你分配這么多空間,也就是不需要擴(kuò)充了。
17. 下面哪些是對稱加密算法()
A DES B AES C DSA D RSA
答案:AB
解析:常用的對稱加密算法有:DES、3DES、RC2、RC4、AES
常用的非對稱加密算法有:RSA、DSA、ECC
使用單向散列函數(shù)的加密算法:MD5、SHA
18.新建一個流對象,下面哪個選項的代碼是錯誤的?()
A)new BufferedWriter(new FileWriter("a.txt"));
B)new BufferedReader(new FileInputStream("a.dat"));
C)new GZIPOutputStream(new FileOutputStream("a.zip"));
D)new ObjectInputStream(new FileInputStream("a.dat"));
答案:B
解析:請記得13題的那個圖嗎?Reader只能用FileReader進(jìn)行實(shí)例化。
19. 下面程序能正常運(yùn)行嗎()
public class NULL {
public static void haha(){
System.out.println("haha");
}
public static void main(String[] args) {
((NULL)null).haha();
}
}
答案:能正常運(yùn)行
解析:輸出為haha,因為null值可以強(qiáng)制轉(zhuǎn)換為任何java類類型,(String)null也是合法的。但null強(qiáng)制轉(zhuǎn)換后是無效對象,其返回值還是為null,而static方法的調(diào)用是和類名綁定的,不借助對象進(jìn)行訪問所以能正確輸出。反過來,沒有static修飾就只能用對象進(jìn)行訪問,使用null調(diào)用對象肯定會報空指針錯了。這里和C++很類似。這里感謝@Florian網(wǎng)友解答。
20. 下面程序的運(yùn)行結(jié)果是什么()
class HelloA {
public HelloA() {
System.out.println("HelloA");
}
{ System.out.println("I'm A class"); }
static { System.out.println("static A"); }
}
public class HelloB extends HelloA {
public HelloB() {
System.out.println("HelloB");
}
{ System.out.println("I'm B class"); }
static { System.out.println("static B"); }
public static void main(String[] args) {
new HelloB();
}
}
答案:
static A static B I'm A class HelloA I'm B class HelloB
解析:說實(shí)話我覺得這題很好,考查靜態(tài)語句塊、構(gòu)造語句塊(就是只有大括號的那塊)以及構(gòu)造函數(shù)的執(zhí)行順序。
對象的初始化順序:(1)類加載之后,按從上到下(從父類到子類)執(zhí)行被static修飾的語句;(2)當(dāng)static語句執(zhí)行完之后,再執(zhí)行main方法;(3)如果有語句new了自身的對象,將從上到下執(zhí)行構(gòu)造代碼塊、構(gòu)造器(兩者可以說綁定在一起)。
下面稍微修改下上面的代碼,以便更清晰的說明情況:
View Code
此時輸出結(jié)果為:
static A static B -------main start------- I'm A class HelloA I'm B class HelloB I'm A class HelloA I'm B class HelloB -------main end-------
21.getCustomerInfo()方法如下,try中可以捕獲三種類型的異常,如果在該方法運(yùn)行中產(chǎn)生了一個IOException,將會輸出什么結(jié)果()
public void getCustomerInfo() {
try {
// do something that may cause an Exception
} catch (java.io.FileNotFoundException ex) {
System.out.print("FileNotFoundException!");
} catch (java.io.IOException ex) {
System.out.print("IOException!");
} catch (java.lang.Exception ex) {
System.out.print("Exception!");
}
}
AIOException!
BIOException!Exception!
CFileNotFoundException!IOException!
DFileNotFoundException!IOException!Exception!
答案:A
解析:考察多個catch語句塊的執(zhí)行順序。當(dāng)用多個catch語句時,catch語句塊在次序上有先后之分。從最前面的catch語句塊依次先后進(jìn)行異常類型匹配,這樣如果父異常在子異常類之前,那么首先匹配的將是父異常類,子異常類將不會獲得匹配的機(jī)會,也即子異常類型所在的catch語句塊將是不可到達(dá)的語句。所以,一般將父類異常類即Exception老大放在catch語句塊的最后一個。
22. 下面代碼的運(yùn)行結(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什么的,運(yùn)行后才發(fā)現(xiàn)Java中所有定義的基本類型或?qū)ο蠖急仨毘跏蓟拍茌敵鲋怠?/p>
23. System.out.println("5" + 2);的輸出結(jié)果應(yīng)該是()。
A52 B7 C2 D5
答案:A
解析:沒啥好說的,Java會自動將2轉(zhuǎn)換為字符串。
24.指出下列程序運(yùn)行的結(jié)果()
public class Example {
String str = new String("good");
char[] ch = { 'a', 'b', 'c' };
public static void main(String args[]) {
Example ex = new Example();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + " and ");
System.out.print(ex.ch);
}
public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'g';
}
}
A、good and abc
B、good and gbc
C、test ok and abc
D、test ok and gbc
答案:B
解析:大家可能以為Java中String和數(shù)組都是對象所以肯定是對象引用,然后就會選D,其實(shí)這是個很大的誤區(qū):因為在java里沒有引用傳遞,只有值傳遞
這個值指的是實(shí)參的地址的拷貝,得到這個拷貝地址后,你可以通過它修改這個地址的內(nèi)容(引用不變),因為此時這個內(nèi)容的地址和原地址是同一地址,
但是你不能改變這個地址本身使其重新引用其它的對象,也就是值傳遞,可能說的不是很清楚,下面給出一個完整的能說明情況的例子吧:
View Code
程序有些啰嗦,但能反映問題,該程序運(yùn)行結(jié)果為:
對象交換前:p1 = Alexia female 對象交換前:p2 = Edward male 對象交換后:p1 = Alexia female 對象交換后:p2 = Edward male 對象數(shù)組交換前:arraya[0] = Alexia female, arraya[1] = Edward male 對象數(shù)組交換前:arrayb[0] = jmwang female, arrayb[1] = hwu male 對象數(shù)組交換后:arraya[0] = Alexia female, arraya[1] = Edward male 對象數(shù)組交換后:arrayb[0] = jmwang female, arrayb[1] = hwu male 基本類型數(shù)組交換前:a[0] = 0, a[1] = 1 基本類型數(shù)組交換前:b[0] = 1, b[1] = 2 基本類型數(shù)組交換后:a[0] = 0, a[1] = 1 基本類型數(shù)組交換后:b[0] = 1, b[1] = 2 對象數(shù)組內(nèi)容交換并改變后:arraya[1] = wjl male 對象數(shù)組內(nèi)容交換并改變后:arrayb[1] = Edward male 基本類型數(shù)組內(nèi)容交換并改變后:a[1] = 5 基本類型數(shù)組內(nèi)容交換并改變后:b[1] = 1
說明:不管是對象、基本類型還是對象數(shù)組、基本類型數(shù)組,在函數(shù)中都不能改變其實(shí)際地址但能改變其中的內(nèi)容。
25.要從文件"file.dat"中讀出第10個字節(jié)到變量c中,下列哪個方法適合?()
AFileInputStream in=new FileInputStream("file.dat"); in.skip(9); int c=in.read();
BFileInputStream in=new FileInputStream("file.dat"); in.skip(10); int c=in.read();
CFileInputStream in=new FileInputStream("file.dat"); int c=in.read();
DRandomAccessFile in=new RandomAccessFile("file.dat"); in.skip(9); int c=in.readByte();
答案:A?D?
解析:long skip(long n)作用是跳過n個字節(jié)不讀,主要用在包裝流中的,因為一般流(如FileInputStream)只能順序一個一個的讀不能跳躍讀,但是包裝流可以用skip方法跳躍讀取。那么什么是包裝流呢?各種字節(jié)節(jié)點(diǎn)流類,它們都只具有讀寫字節(jié)內(nèi)容的方法,以FileInputStream與FileOutputStream為例,它們只能在文件中讀取或者向文件中寫入字節(jié),在實(shí)際應(yīng)用中我們往往需要在文件中讀取或者寫入各種類型的數(shù)據(jù),就必須先將其他類型的數(shù)據(jù)轉(zhuǎn)換成字節(jié)數(shù)組后寫入文件,或者從文件中讀取到的字節(jié)數(shù)組轉(zhuǎn)換成其他數(shù)據(jù)類型,想想都很麻煩!!因此想通過FileOutputStream將一個浮點(diǎn)小數(shù)寫入到文件中或?qū)⒁粋€整數(shù)寫入到文件時是非常困難的。這時就需要包裝類DataInputStream/DataOutputStream,它提供了往各種輸入輸出流對象中讀入或?qū)懭敫鞣N類型的數(shù)據(jù)的方法。
DataInputStream/DataOutputStream并沒有對應(yīng)到任何具體的流設(shè)備,一定要給它傳遞一個對應(yīng)具體流設(shè)備的輸入或輸出流對象,完成類似DataInputStream/DataOutputStream功能的類就是一個包裝類,也叫過濾流類或處理流類。它對InputOutStream/OutputStream流類進(jìn)行了包裝,使編程人員使用起來更方便。其中DataInputStream包裝類的構(gòu)造函數(shù)語法:public DataInputStream(InputStream in)。包裝類也可以包裝另外一個包裝類。
首先BC肯定 是錯的,那A正確嗎?按上面的解析應(yīng)該也不對,但我試了下,發(fā)現(xiàn)A也是正確的,與網(wǎng)上解析的資料有些出入,下面是我的code:
View Code
那么D呢,RandomAccessFile是IO包的類,但是其自成一派,從Object直接繼承而來。可以對文件進(jìn)行讀取和寫入。支持文件的隨機(jī)訪問,即可以隨機(jī)讀取文件中的某個位置內(nèi)容,這么說RandomAccessFile肯定可以達(dá)到題目的要求,但是選項有些錯誤,比如RandomAccessFile的初始化是兩個參數(shù)而非一個參數(shù),采用的跳躍讀取方法是skipBytes()而非skip(),即正確的寫法是:
RandomAccessFile in = new RandomAccessFile("file.dat", "r");
in.skipBytes(9);
int c = in.readByte();
這樣也能讀到第十個字節(jié),也就是A和D都能讀到第十個字節(jié),那么到底該選哪個呢?A和D有啥不同嗎?求大神解答~~~
26.下列哪種異常是檢查型異常,需要在編寫程序時聲明()
ANullPointerException BClassCastException CFileNotFoundException D IndexOutOfBoundsException
答案:C
解析:看第2題的解析。
27. 下面的方法,當(dāng)輸入為2的時候返回值是多少?()
public static int getValue(int i) {
int result = 0;
switch (i) {
case 1:
result = result + i;
case 2:
result = result + i * 2;
case 3:
result = result + i * 3;
}
return result;
}
A0 B2 C4 D10
答案:D
解析:注意這里case后面沒有加break,所以從case 2開始一直往下運(yùn)行。
28.選項中哪一行代碼可以替換題目中//add code here而不產(chǎn)生編譯錯誤?()
public abstract class MyClass {
public int constInt = 5;
//add code here
public void method() {
}
}
Apublic abstract void method(int a);
B constInt = constInt + 5;
Cpublic int method();
Dpublic abstract void anotherMethod() {}
答案:A
解析:考察抽象類的使用。
抽象類遵循的原則:
(1)abstract關(guān)鍵字只能修飾類和方法,不能修飾字段。
(2)抽象類不能被實(shí)例化(無法使用new關(guān)鍵字創(chuàng)建對象實(shí)例),只能被繼承。
(3)抽象類可以包含屬性,方法,構(gòu)造方法,初始化塊,內(nèi)部類,枚舉類,和普通類一樣,普通方法一定要實(shí)現(xiàn),變量可以初始化或不初始化但不能初始化后在抽象類中重新賦值或操作該變量(只能在子類中改變該變量)。
(4)抽象類中的抽象方法(加了abstract關(guān)鍵字的方法)不能實(shí)現(xiàn)。
(5)含有抽象方法的類必須定義成抽象類。
擴(kuò)展:抽象類和接口的區(qū)別,做個總結(jié)吧:
(1)接口是公開的,里面不能有私有的方法或變量,是用于讓別人使用的,而抽象類是可以有私有方法或私有變量的。
(2)abstract class 在 Java 語言中表示的是一種繼承關(guān)系,一個類只能使用一次繼承關(guān)系。但是,一個類卻可以實(shí)現(xiàn)多個interface,實(shí)現(xiàn)多重繼承。接口還有標(biāo)識(里面沒有任何方法,如Remote接口)和數(shù)據(jù)共享(里面的變量全是常量)的作用。
(3)在abstract class 中可以有自己的數(shù)據(jù)成員,也可以有非abstarct的成員方法,而在interface中,只能夠有靜態(tài)的不能被修改的數(shù)據(jù)成員(也就是必須是 static final的,不過在 interface中一般不定義數(shù)據(jù)成員),所有的成員方法默認(rèn)都是 public abstract 類型的。
(4)abstract class和interface所反映出的設(shè)計理念不同。其實(shí)abstract class表示的是"is-a"關(guān)系,interface表示的是"has-a"關(guān)系。
(5)實(shí)現(xiàn)接口的一定要實(shí)現(xiàn)接口里定義的所有方法,而實(shí)現(xiàn)抽象類可以有選擇地重寫需要用到的方法,一般的應(yīng)用里,最頂級的是接口,然后是抽象類實(shí)現(xiàn)接口,最后才到具體類實(shí)現(xiàn)。抽象類中可以有非抽象方法。接口中則不能有實(shí)現(xiàn)方法。
(6)接口中定義的變量默認(rèn)是public static final 型,且必須給其初值,所以實(shí)現(xiàn)類中不能重新定義,也不能改變其值。抽象類中的變量默認(rèn)是 friendly 型,其值可以在子類中重新定義,也可以在子類中重新賦值。
29. 閱讀Shape和Circle兩個類的定義。在序列化一個Circle的對象circle到文件時,下面哪個字段會被保存到文件中?( )
class Shape {
public String name;
}
class Circle extends Shape implements Serializable{
private float radius;
transient int color;
public static String type = "Circle";
}
Aname
Bradius
Ccolor
Dtype
答案:B
解析:這里有詳細(xì)的解釋:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
30.下面是People和Child類的定義和構(gòu)造方法,每個構(gòu)造方法都輸出編號。在執(zhí)行new Child("mike")的時候都有哪些構(gòu)造方法被順序調(diào)用?請選擇輸出結(jié)果( )
class People {
String name;
public People() {
System.out.print(1);
}
public People(String name) {
System.out.print(2);
this.name = name;
}
}
class Child extends People {
People father;
public Child(String name) {
System.out.print(3);
this.name = name;
father = new People(name + ":F");
}
public Child() {
System.out.print(4);
}
}
A312 B 32 C 432 D 132
答案:D
解析:考察的又是父類與子類的構(gòu)造函數(shù)調(diào)用次序。在Java中,子類的構(gòu)造過程中必須調(diào)用其父類的構(gòu)造函數(shù),是因為有繼承關(guān)系存在時,子類要把父類的內(nèi)容繼承下來。但如果父類有多個構(gòu)造函數(shù)時,該如何選擇調(diào)用呢?
第一個規(guī)則:子類的構(gòu)造過程中,必須調(diào)用其父類的構(gòu)造方法。一個類,如果我們不寫構(gòu)造方法,那么編譯器會幫我們加上一個默認(rèn)的構(gòu)造方法(就是沒有參數(shù)的構(gòu)造方法),但是如果你自己寫了構(gòu)造方法,那么編譯器就不會給你添加了,所以有時候當(dāng)你new一個子類對象的時候,肯定調(diào)用了子類的構(gòu)造方法,但是如果在子類構(gòu)造方法中我們并沒有顯示的調(diào)用基類的構(gòu)造方法,如:super();這樣就會調(diào)用父類沒有參數(shù)的構(gòu)造方法。
第二個規(guī)則:如果子類的構(gòu)造方法中既沒有顯示的調(diào)用基類構(gòu)造方法,而基類中又沒有無參的構(gòu)造方法,則編譯出錯,所以,通常我們需要顯示的:super(參數(shù)列表),來調(diào)用父類有參數(shù)的構(gòu)造函數(shù),此時無參的構(gòu)造函數(shù)就不會被調(diào)用。
總之,一句話:子類沒有顯示調(diào)用父類構(gòu)造函數(shù),不管子類構(gòu)造函數(shù)是否帶參數(shù)都默認(rèn)調(diào)用父類無參的構(gòu)造函數(shù),若父類沒有則編譯出錯。
最后,給大家出個思考題:下面程序的運(yùn)行結(jié)果是什么?
public class Dervied extends Base {
private String name = "dervied";
public Dervied() {
tellName();
printName();
}
public void tellName() {
System.out.println("Dervied tell name: " + name);
}
public void printName() {
System.out.println("Dervied print name: " + name);
}
public static void main(String[] args){
new Dervied();
}
}
class Base {
private String name = "base";
public Base() {
tellName();
printName();
}
public void tellName() {
System.out.println("Base tell name: " + name);
}
public void printName() {
System.out.println("Base print name: " + name);
}
}
以下是自己總結(jié)的一些Java常見的基礎(chǔ)知識題,答案僅供參考,如有異議請指出。一直保持更新狀態(tài)。
1.什么是Java虛擬機(jī)?為什么Java被稱作是“平臺無關(guān)的編程語言”?
Java虛擬機(jī)是一個可以執(zhí)行Java字節(jié)碼的虛擬機(jī)進(jìn)程。Java源文件被編譯成能被Java虛擬機(jī)執(zhí)行的字節(jié)碼文件。
2.“static”關(guān)鍵字是什么意思?Java中是否可以覆蓋(override)一個private或者是static的方法?
“static”關(guān)鍵字表明一個成員變量或者是成員方法可以在沒有所屬的類的實(shí)例變量的情況下被訪問。
Java中static方法不能被覆蓋,因為方法覆蓋是基于運(yùn)行時動態(tài)綁定的,而static方法是編譯時靜態(tài)綁定的。static方法跟類的任何實(shí)例都不相關(guān),所以概念上不適用。
3.是否可以在static環(huán)境中訪問非static變量?
static變量在Java中是屬于類的,它在所有的實(shí)例中的值是一樣的。當(dāng)類被Java虛擬機(jī)載入的時候,會對static變量進(jìn)行初始化。如果你的代碼嘗試不用實(shí)例來訪問非static的變量,編譯器會報錯,因為這些變量還沒有被創(chuàng)建出來,還沒有跟任何實(shí)例關(guān)聯(lián)上。
4.Java支持的數(shù)據(jù)類型有哪些?什么是自動拆裝箱?
Java語言支持的8中基本數(shù)據(jù)類型是:
? byte
? short
? int
? long
? float
? double
? boolean
? char
自動裝箱是Java編譯器在基本數(shù)據(jù)類型和對應(yīng)的對象包裝類型之間做的一個轉(zhuǎn)化。比如:把int轉(zhuǎn)化成Integer,double轉(zhuǎn)化成double,等等。反之就是自動拆箱。
5.Overload和Override的區(qū)別。Overloaded的方法是否可以改變返回值的類型?
方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)。重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn),重載O verloading是一個類中多態(tài)性的一種表現(xiàn)。如果在子類中定義某方法與其父類有相同的名稱和參數(shù),我們說該方法被重寫(Overriding)。子類的對象使用這個方法時,將調(diào)用子類中的定義,對它而言,父類中的定義如同被”屏蔽”了。如果在一個類中定義了多個同名的方法,它們或有不同的參數(shù)個數(shù)或有不同的參數(shù)類型,則稱為方法的重載(Overloading)。Overloaded的方法是可以改變返回值的類型。
6.Java支持多繼承么?
不支持,Java不支持多繼承。每個類都只能繼承一個類,但是可以實(shí)現(xiàn)多個接口。
7.接口和抽象類的區(qū)別是什么?
Java提供和支持創(chuàng)建抽象類和接口。它們的實(shí)現(xiàn)有共同點(diǎn),不同點(diǎn)在于:
? 接口中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。
? 類可以實(shí)現(xiàn)很多個接口,但是只能繼承一個抽象類
? 類如果要實(shí)現(xiàn)一個接口,它必須要實(shí)現(xiàn)接口聲明的所有方法。但是,類可以不實(shí)現(xiàn)抽象類聲明的所有方法,當(dāng)然,在這種情況下,類也必須得聲明成是抽象的。
? 抽象類可以在不提供接口方法實(shí)現(xiàn)的情況下實(shí)現(xiàn)接口。
? Java接口中聲明的變量默認(rèn)都是final的。抽象類可以包含非final的變量。
?Java接口中的成員函數(shù)默認(rèn)是public的。抽象類的成員函數(shù)可以是private,protected或者是public。
? 接口是絕對抽象的,不可以被實(shí)例化。抽象類也不可以被實(shí)例化,但是,如果它包含main方法的話是可以被調(diào)用的。
也可以參考JDK8中抽象類和接口的區(qū)別
8.什么是值傳遞和引用傳遞?
對象被值傳遞,意味著傳遞了對象的一個副本。因此,就算是改變了對象副本,也不會影響源對象的值。
對象被引用傳遞,意味著傳遞的并不是實(shí)際的對象,而是對象的引用。因此,外部對引用對象所做的改變會反映到所有的對象上。
9.創(chuàng)建線程有幾種不同的方式?你喜歡哪一種?為什么?
有三種方式可以用來創(chuàng)建線程:
? 繼承Thread類
? 實(shí)現(xiàn)Runnable接口
? 應(yīng)用程序可以使用Executor框架來創(chuàng)建線程池
實(shí)現(xiàn)Runnable接口這種方式更受歡迎,因為這不需要繼承Thread類。在應(yīng)用設(shè)計中已經(jīng)繼承了別的對象的情況下,這需要多繼承(而Java不支持多繼承),只能實(shí)現(xiàn)接口。同時,線程池也是非常高效的,很容易實(shí)現(xiàn)和使用。
10.同步方法和同步代碼塊的區(qū)別是什么?
在Java語言中,每一個對象有一把鎖。線程可以使用synchronized關(guān)鍵字來獲取對象上的鎖。synchronized關(guān)鍵字可應(yīng)用在方法級別(粗粒度鎖:這里的鎖對象可以是This)或者是代碼塊級別(細(xì)粒度鎖:這里的鎖對象就是任意對象)。
11.什么是死鎖(deadlock)?
兩個進(jìn)程都在等待對方執(zhí)行完畢才能繼續(xù)往下執(zhí)行的時候就發(fā)生了死鎖。結(jié)果就是兩個進(jìn)程都陷入了無限的等待中。
代碼表示:
代碼描述:
public class DieLockDemo {
public static void main(String[] args) {
DieLock dl1 = new DieLock(true);
DieLock dl2 = new DieLock(false);
dl1.start();
dl2.start();
}
}
*...理想狀態(tài)下dl1線程為true從if執(zhí)行先打出"if objA"然后再接著打出"if objB"之后釋放A、B的鎖對象,之后dl2線程執(zhí)行else語句打出"else objB","else objA"。
非理想狀態(tài)下dl1先打出"if objA",之后線程dl2執(zhí)行打出"else objB",然后1、2線程的鎖對象A和B都處于被鎖的狀態(tài),兩個線程爭奪鎖對象發(fā)生死鎖現(xiàn)象。..*
public class DieLock extends Thread {
private boolean flag;
public DieLock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (MyLock.objA) {
System.out.println("if objA");
synchronized (MyLock.objB) {
System.out.println("if objB");
}
}
} else {
synchronized (MyLock.objB) {
System.out.println("else objB");
synchronized (MyLock.objA) {
System.out.println("else objA");
}
}
}
}
}
12.如何確保N個線程可以訪問N個資源同時又不導(dǎo)致死鎖?
使用多線程的時候,一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,并強(qiáng)制線程按照指定的順序獲取鎖。因此,如果所有的線程都是以同樣的順序加鎖和釋放鎖,就不會出現(xiàn)死鎖了。
13.Java集合類框架的基本接口有哪些?
Java集合類提供了一套設(shè)計良好的支持對一組對象進(jìn)行操作的接口和類。Java集合類里面最基本的接口有:
? Collection:代表一組對象,每一個對象都是它的子元素。
? Set:不包含重復(fù)元素的Collection。
? List:有順序的collection,并且可以包含重復(fù)元素。
? Map:可以把鍵(key)映射到值(value)的對象,鍵不能重復(fù)。
14.什么是迭代器(Iterator)?
Iterator接口提供了很多對集合元素進(jìn)行迭代的方法。每一個集合類都包含了可以返回迭代器實(shí)例的迭代方法。迭代器可以在迭代的過程中刪除底層集合的元素。
15.Iterator和ListIterator的區(qū)別是什么?
下面列出了他們的區(qū)別:
? Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
? Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向。
? ListIterator實(shí)現(xiàn)了Iterator接口,并包含其他的功能,比如:增加元素,替換元素,獲取前一個和后一個元素的索引,等等。
16.Java中的HashMap的工作原理是什么?
Java中的HashMap是以鍵值對(key-value)的形式存儲元素的。HashMap需要一個hash函數(shù),它使用hashCode()和equals()方法來向集合/從集合添加和檢索元素。當(dāng)調(diào)用put()方法的時候,HashMap會計算key的hash值,然后把鍵值對存儲在集合中合適的索引上。如果key已經(jīng)存在了,value會被更新成新值。HashMap的一些重要的特性是它的容量(capacity),負(fù)載因子(load factor)和擴(kuò)容極限(threshold resizing)。
17.HashMap和Hashtable有什么區(qū)別?
? HashMap和Hashtable都實(shí)現(xiàn)了Map接口,因此很多特性非常相似。但是,他們有以下不同點(diǎn):
?HashMap允許鍵和值是null,而Hashtable不允許鍵或者值是null。
?Hashtable是同步的,而HashMap不是。因此,HashMap更適合于單線程環(huán)境,而Hashtable適合于多線程環(huán)境。
? HashMap提供了可供應(yīng)用迭代的鍵的集合,因此,HashMap是快速失敗的。另一方面,Hashtable提供了對鍵的列舉(Enumeration)。
o 一般認(rèn)為Hashtable是一個遺留的類。
18.數(shù)組(Array)和列表(ArrayList)有什么區(qū)別?什么時候應(yīng)該使用Array而不是ArrayList?
下面列出了Array和ArrayList的不同點(diǎn):
?Array可以包含基本類型和對象類型,ArrayList只能包含對象類型。
?Array大小是固定的,ArrayList的大小是動態(tài)變化的。
? ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
? 對于基本類型數(shù)據(jù),集合使用自動裝箱來減少編碼工作量。但是,當(dāng)處理固定大小的基本數(shù)據(jù)類型的時候,這種方式相對比較慢。
19.ArrayList和LinkedList有什么區(qū)別?
ArrayList和LinkedList都實(shí)現(xiàn)了List接口,他們有以下的不同點(diǎn):
? ArrayList是基于索引的數(shù)據(jù)接口,它的底層是數(shù)組。它可以以O(shè)(1)時間復(fù)雜度對元素進(jìn)行隨機(jī)訪問。與此對應(yīng),LinkedList是以元素鏈表的形式存儲它的數(shù)據(jù),每一個元素都和它的前一個和后一個元素鏈接在一起,在這種情況下,查找某個元素的時間復(fù)雜度是O(n)。
? 相對于ArrayList,LinkedList的插入,添加,刪除操作速度更快,因為當(dāng)元素被添加到集合任意位置的時候,不需要像數(shù)組那樣重新計算大小或者是更新索引。
? LinkedList比ArrayList更占內(nèi)存,因為LinkedList為每一個節(jié)點(diǎn)存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。
也可以參考ArrayList vs. LinkedList。
20.如何權(quán)衡是使用無序的數(shù)組還是有序的數(shù)組?
有序數(shù)組最大的好處在于查找的時間復(fù)雜度是O(log n),而無序數(shù)組是O(n)。有序數(shù)組的缺點(diǎn)是插入操作的時間復(fù)雜度是O(n),因為值大的元素需要往后移動來給新元素騰位置。相反,無序數(shù)組的插入時間復(fù)雜度是常量O(1)。
21.HashSet和TreeSet有什么區(qū)別?
HashSet是由一個hash表來實(shí)現(xiàn)的,因此,它的元素是無序的。add(),remove(),contains()方法的時間復(fù)雜度是O(1)。
另一方面,TreeSet是由一個樹形的結(jié)構(gòu)來實(shí)現(xiàn)的,它里面的元素是有序的。因此,add(),remove(),contains()方法的時間復(fù)雜度是O(logn)。
22.Java中垃圾回收有什么目的?什么時候進(jìn)行垃圾回收?
垃圾回收的目的是識別并且丟棄應(yīng)用不再使用的對象來釋放和重用資源。
23.如果對象的引用被置為null,垃圾收集器是否會立即釋放對象占用的內(nèi)存?
不會,在下一個垃圾回收周期中,這個對象將是可被回收的。
24、String是最基本的數(shù)據(jù)類型嗎?
基本數(shù)據(jù)類型包括byte、int、char、long、float、double、boolean和short。
java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。為了提高效率節(jié)省空間,我們應(yīng)該用StringBuffer類
25、int 和 Integer 有什么區(qū)別
Java 提供兩種不同的類型:引用類型和原始類型(或內(nèi)置類型)。Int是java的原始數(shù)據(jù)類型,Integer是java為int提供的封裝類。Java為每個原始類型提供了封裝類。
26、String 和StringBuffer的區(qū)別
JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數(shù)據(jù)。這個String類提供了數(shù)值不可改變的字符串。而這個StringBuffer類提供的字符串進(jìn)行修改。
27、說出ArrayList,Vector, LinkedList的存儲性能和特性
ArrayList 和Vector都是使用數(shù)組方式存儲數(shù)據(jù),此數(shù)組元素數(shù)大于實(shí)際存儲的數(shù)據(jù)以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數(shù)組元素移動等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢,Vector由于使用了synchronized方法(線程安全),通常性能上較ArrayList差,而 Linke dList使用雙向鏈表實(shí)現(xiàn)存儲,按序號索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷,但是插入數(shù)據(jù)時只需要記錄本項的前后項即可,所以插入速度較快。
List的子類特點(diǎn)
ArrayList:
底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢
線程不安全,效率高
Vector:
底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢
線程安全,效率低
LinkedList:
底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快
線程不安全,效率高
28、Collection 和 Collections的區(qū)別
Collection是集合類的上級接口,繼承與他的接口主要有Set 和List.
Collections是針對集合類的一個幫助類,他提供一系列靜態(tài)方法實(shí)現(xiàn)對各種集合的搜索、排序、線程安全化等操作。
集合的繼承體系:
29、&和&&的區(qū)別。
&是位運(yùn)算符,表示按位與運(yùn)算,&&是邏輯運(yùn)算符,表示邏輯與(and)。
30、final, finally, finalize的區(qū)別。
final
用于聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。
finally是異常處理語句結(jié)構(gòu)的一部分,表示總是執(zhí)行。
finalize是Object類的一個方法,在垃圾收集器執(zhí)行的時候會調(diào)用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,例如關(guān)閉文件等。
31、sleep() 和 wait() 有什么區(qū)別?
sleep是線程類(Thread)的方法,導(dǎo)致此線程暫停執(zhí)行指定時間,給執(zhí)行機(jī)會給其他線程,但是監(jiān)控狀態(tài)依然保持,到時后會自動恢復(fù)。調(diào)用sleep不會釋放對象鎖。
wait是Object類的方法,對此對象調(diào)用wait方法導(dǎo)致本線程放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或not ifyAll)后本線程才進(jìn)入對象鎖定池準(zhǔn)備獲得對象鎖進(jìn)入運(yùn)行狀態(tài)。
32、error和exception有什么區(qū)別?
error
表示恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題。比如說內(nèi)存溢出。不可能指望程序能處理這樣的情況。
exception
表示一種設(shè)計或?qū)崿F(xiàn)問題。也就是說,它表示如果程序運(yùn)行正常,從不會發(fā)生的情況。
33、同步和異步有何異同,在什么情況下分別使用他們?舉例說明。
如果數(shù)據(jù)將在線程間共享。例如正在寫的數(shù)據(jù)以后可能被另一個線程讀到,或者正在讀的數(shù)據(jù)可能已經(jīng)被另一個線程寫過了,那么這些數(shù)據(jù)就是共享數(shù)據(jù),必須進(jìn)行同步存取。
當(dāng)應(yīng)用程序在對象上調(diào)用了一個需要花費(fèi)很長時間來執(zhí)行的方法,并且不希望讓程序等待方法的返回時,就應(yīng)該使用異步編程,在很多情況下采用異步途徑往往更有效率。
34、GC是什么? 為什么要有GC?
GC是垃圾收集的意思(Gabage Collection),內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯誤的內(nèi)存回收會導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java提供的GC功能可以自動監(jiān)測對象是否超過作用域從而達(dá)到自動回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法。
35、short s1 = 1; s1 = s1 + 1;有什么錯? short s1 = 1; s1 +=
1;有什么錯?
short s1 = 1; s1 = s1 + 1;
(s1+1運(yùn)算結(jié)果是int型,需要強(qiáng)制轉(zhuǎn)換類型)
short s1 = 1; s1 += 1;(可以正確編譯,+=內(nèi)置運(yùn)算符運(yùn)算時可自動變換數(shù)據(jù)類型)
36、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math.round(11.5)==12
Math.round(-11.5)==-11
round方法返回與參數(shù)最接近的長整數(shù),參數(shù)加1/2后求其floor.
37、String s = new String(“xyz”);創(chuàng)建了幾個String Object?
兩個,一個是在堆中創(chuàng)建的s一個是在字符串常量池中創(chuàng)建的“xyz”。
38、接口是否可繼承接口?
抽象類是否可實(shí)現(xiàn)(implements)接口?
抽象類是否可繼承實(shí)體類(concrete class)?
接口可以繼承接口。抽象類可以實(shí)現(xiàn)(implements)接口,抽象類是否可繼承實(shí)體類,但前提是實(shí)體類必須有明確的構(gòu)造函數(shù)。
39、List, Set, Map是否繼承自Collection接口?
List,Set是,Map不是
40、abstract的method是否可同時是static,是否可同時是native,是否可同時是synchronized?
都不能
41、是否可以繼承String類?
String類是final類故不可以繼承。
42、swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
switch(expr1)中,expr1是一個整數(shù)表達(dá)式。因此傳遞給switch 和 case 語句的參數(shù)應(yīng)該是 int、 short、 char 或者byte。long,string 都不能作用于swtich。
43、try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執(zhí)行,什么時候被執(zhí)行,在return前還是后?
會執(zhí)行,在return前執(zhí)行(finally中程序一定會被執(zhí)行,return結(jié)束后程序結(jié)束,所以肯定在之前執(zhí)行)。
44、兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?
不對,有相同的hash code。(hashcode內(nèi)部也是根據(jù)對象的 來做處理的)
45、當(dāng)一個線程進(jìn)入一個對象的一個synchronized方法后,其它線程是否可進(jìn)入此對象的其它方法?
不能,一個對象的一個synchronized方法只能由一個線程訪問。(同步代碼塊時對象鎖可以是任何對象,同步方法時對象鎖只能是this對象所以無法訪問其他方法)
46、編程題: 寫一個Singleton出來。
Singleton模式主要作用是保證在Java應(yīng)用程序中,一個類Class只有一個實(shí)例存在。
一般Singleton模式通常有幾種種形式:
第一種形式:
定義一個類,它的構(gòu)造函數(shù)為private的,它有一個static的private的該類變量,在類初始化時實(shí)例話,通過一個public的getInsta nce方法獲取對它的引用,繼而調(diào)用其中的方法。
public class Singleton {
private Singleton(){}
//在自己內(nèi)部定義自己一個實(shí)例,是不是很奇怪?
//注意這是private 只供內(nèi)部調(diào)用
private static Singleton instance = new Singleton();
//這里提供了一個供外部訪問本class的靜態(tài)方法,可以直接訪問
public static Singleton getInstance() {
return instance;
}
}
第二種形式:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//這個方法比上面有所改進(jìn),不用每次都進(jìn)行生成對象,只是第一次
//使用時生成實(shí)例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance; }
}
其他形式:
定義一個類,它的構(gòu)造函數(shù)為private的,所有方法為static的。
一般認(rèn)為第一種形式要更加安全些
47、Java的接口和C++的虛類的相同和不同處。
由于Java不支持多繼承,而有可能某個類或?qū)ο笠褂梅謩e在幾個類或?qū)ο罄锩娴姆椒ɑ驅(qū)傩裕F(xiàn)有的單繼承機(jī)制就不能滿足要求。與繼承相比,接口有更高的靈活性,因為接口中沒有任何實(shí)現(xiàn)代碼。當(dāng)一個類實(shí)現(xiàn)了接口以后,該類要實(shí)現(xiàn)接口里面所有的方法和屬性,并且接口里面的屬性在默認(rèn)狀態(tài)下面都是public static,所有方法默認(rèn)情況下是public.一個類可以實(shí)現(xiàn)多個接口。
48、Java中的異常處理機(jī)制的簡單原理和應(yīng)用。
當(dāng)JAVA 程序違反了JAVA的語義規(guī)則時,JAVA虛擬機(jī)就會將發(fā)生的錯誤表示為一個異常。違反語義規(guī)則包括2種情況。一種是JAVA類庫內(nèi)置的語義檢查。例如數(shù)組下標(biāo)越界,會引發(fā)IndexOutOfBoundsException;訪問null的對象時會引發(fā)NullPointerException。另一種情況就是JAVA允許程序員擴(kuò)展這種語義檢查,程序員可以創(chuàng)建自己的異常,并自由選擇在何時用throw關(guān)鍵字引發(fā)異常。所有的異常都是java.lang.Thowable的子類。
49、垃圾回收的優(yōu)點(diǎn)和原理。并考慮2種回收機(jī)制。
Java語言中一個顯著的特點(diǎn)就是引入了垃圾回收機(jī)制,使c++程序員最頭疼的內(nèi)存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候不再需要考慮內(nèi)存管理。由于有個垃圾回收機(jī)制,Java中的對象不再有”作用域”的概念,只有對象的引用才有”作用域”。垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個單獨(dú)的低級別的線程運(yùn)行,不可預(yù)知的情況下對內(nèi)存堆中已經(jīng)死亡的或者長時間沒有使用的對象進(jìn)行清楚和回收,程序員不能實(shí)時的調(diào)用垃圾回收器對某個對象或所有對象進(jìn)行垃圾回收。回收機(jī)制有分代復(fù)制垃圾回收和標(biāo)記垃圾回收,增量垃圾回收。
50、char型變量中能不能存貯一個中文漢字?為什么?
能夠定義成為一個中文的,因為java中以unicode編碼,一個char占2個字節(jié),所以放一個中文是沒問題的
51、多線程有幾種實(shí)現(xiàn)方法,都是什么?同步有幾種實(shí)現(xiàn)方法,都是什么?
多線程有兩種實(shí)現(xiàn)方法,分別是繼承Thread類與實(shí)現(xiàn)Runnable接口
同步的實(shí)現(xiàn)方面有兩種,分別是同步代碼塊和同步方法
52、線程的基本概念、線程的基本狀態(tài)以及狀態(tài)之間的關(guān)系
線程指在程序執(zhí)行過程中,能夠執(zhí)行程序代碼的一個執(zhí)行單位,每個程序至少都有一個線程,也就是程序本身。
Java中的線程有五種狀態(tài)分別是:新建、就緒、運(yùn)行、阻塞、結(jié)束。
53、簡述synchronized和java.util.concurrent.locks.Lock的異同?
主要相同點(diǎn):Lock能完成synchronized所實(shí)現(xiàn)的所有功能
主要不同點(diǎn):Lock有比synchronized更精確的線程語義和更好的性能。
Lock是一個類,synchronized是一個關(guān)鍵字
synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。
54、JAVA語言如何進(jìn)行異常處理,關(guān)鍵字:throws,throw,try,catch,finally分別代表什么意義?在try塊中可以拋出異常嗎?
Java 通過面向?qū)ο蟮姆椒ㄟM(jìn)行異常處理,把各種不同的異常進(jìn)行分類,并提供了良好的接口。在Java中,每個異常都是一個對象,它是Throwable 類或其它子類的實(shí)例。當(dāng)一個方法出現(xiàn)異常后便拋出一個異常對象,該對象中包含有異常信息,調(diào)用這個對象的方法可以捕獲到這個異常并進(jìn)行處理。Java的異常處理是通過5 個關(guān)鍵詞來實(shí)現(xiàn)的:try、catch、throw、throws和finally。一般情況下是用try來執(zhí)行一段程序,如果出現(xiàn)異常,系統(tǒng)會拋出(throws)一個異常,這時候你可以通過它的類型來捕捉(catch)它,或最后(finally)由缺省處理器來處理。
用try來指定一塊預(yù)防所有”異常”的程序。緊跟在try程序后面,應(yīng)包含一個catch子句來指定你想要捕捉的”異常”的類型。
throw語句用來明確地拋出一個”異常”。
throws用來標(biāo)明一個成員函數(shù)可能拋出的各種”異常”。
Finally為確保一段代碼不管發(fā)生什么”異常”都被執(zhí)行一段代碼。
可以在一個成員函數(shù)調(diào)用的外面寫一個try語句,在這個成員函數(shù)內(nèi)部寫另一個try語句保護(hù)其他代碼。每當(dāng)遇到一個try語句,”異常”的框架就放到堆棧上面,直到所有的try語句都完成。如果下一級的try語句沒有對某種”異常”進(jìn)行處理,堆棧就會展開,直到遇到有處理這種”異常”的try語句。
55、一個”.java“源文件中是否可以包括多個類(不是內(nèi)部類)?有什么限制?
可以。必須只有一個類名與文件名相同。
56、java中有幾種類型的流?JDK為每種類型的流提供了一些抽象類以供繼承,請說出他們分別是哪些類?
字節(jié)流,字符流。字節(jié)流繼承于InputStream OutputStream,字符流繼承于InputStreamReader OutputStreamWriter。在java.io包中還有許多其他的流,主要是為了提高性能和使用方便。
57、java中會存在內(nèi)存泄漏嗎,請簡單描述。
會。如:int i,i2; return (i-i2); //when i為足夠大的正數(shù),i2為足夠大的負(fù)數(shù)。結(jié)果會造成溢位,導(dǎo)致錯誤。
58、java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?
方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)。重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn),重載Overloading是一個類中多態(tài)性的一種表現(xiàn)。
59、垃圾回收器的基本原理是什么?垃圾回收器可以馬上回收內(nèi)存嗎?有什么辦法主動通知虛擬機(jī)進(jìn)行垃圾回收?
對于GC來說,當(dāng)程序員創(chuàng)建對象時,GC就開始監(jiān)控這個對象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是”可達(dá)的”,哪些對象是”不可達(dá)的”。當(dāng)GC確定一些對象為”不可達(dá)”時,GC就有責(zé)任回收這些內(nèi)存空間。可以。程序員可以手動執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語言規(guī)范并不保證GC一定會執(zhí)行。
60、什么是java序列化,如何實(shí)現(xiàn)java序列化?
序列化就是一種用來處理對象流的機(jī)制,所謂對象流也就是將對象的內(nèi)容進(jìn)行流化。可以對流化后的對象進(jìn)行讀寫操作,也可將流化后的對象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決在對對象流進(jìn)行讀寫操作時所引發(fā)的問題。
序列化的實(shí)現(xiàn):將需要被序列化的類實(shí)現(xiàn)Serializable接口,該接口沒有需要實(shí)現(xiàn)的方法,implements Serializable只是為了標(biāo)注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構(gòu)造一個ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數(shù)為obj的對象寫出(即保存其狀態(tài)),要恢復(fù)的話則用輸入流。
61、是否可以從一個static方法內(nèi)部發(fā)出對非static方法的調(diào)用?
不可以,如果其中包含對象的method();不能保證對象初始化.
62、List、Map、Set三個接口,存取元素時,各有什么特點(diǎn)?
List 以特定次序來持有元素,可有重復(fù)元素。
Set 無法擁有重復(fù)元素,內(nèi)部排序。
Map 保存key-value值,value可多值。
63、使用final關(guān)鍵字修飾一個變量時,是引用不能變,還是引用的對象不能變?
使用final關(guān)鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內(nèi)容還是可以改變的。例如,對于如下語句:
final StringBuffer a=new StringBuffer(“immutable”);
執(zhí)行如下語句將報告編譯期錯誤:
a=new StringBuffer(“”);
但是,執(zhí)行如下語句則可以通過編譯:
a.append(” broken!”);
有人在定義方法的參數(shù)時,可能想采用如下形式來阻止方法內(nèi)部修改傳進(jìn)來的參數(shù)對象:
public void method(final StringBuffer param)
{
}
實(shí)際上,這是辦不到的,在該方法內(nèi)部仍然可以增加如下代碼來修改參數(shù)對象:
param.append(“a”);
65、請說出作用域public,private,protected,以及不寫時的區(qū)別
這四個作用域的可見范圍如下表所示。
說明:如果在修飾的元素上面沒有寫任何訪問修飾符,則表示friendly。
作用域 當(dāng)前類 同一package 子孫類 其他package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×
備注:只要記住了有4種訪問權(quán)限,4個訪問范圍,然后將全選和范圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。
66、線程如何同步和通訊。
線程同步
什么是線程同步?
當(dāng)使用多個線程來訪問同一個數(shù)據(jù)時,非常容易出現(xiàn)線程安全問題(比如多個線程都在操作同一數(shù)據(jù)導(dǎo)致數(shù)據(jù)不一致),所以我們用同步機(jī)制來解決這些問題。
實(shí)現(xiàn)同步機(jī)制有兩個方法:
1。同步代碼塊:
synchronized(同一個數(shù)據(jù)){} 同一個數(shù)據(jù):就是N條線程同時訪問一個數(shù)據(jù)。
2。同步方法:
public synchronized 數(shù)據(jù)返回類型 方法名(){}
就是使用 synchronized 來修飾某個方法,則該方法稱為同步方法。對于同步方法而言,無需顯示指定同步監(jiān)視器,同步方法的同步監(jiān)視器是 this 也就是該對象的本身(這里指的對象本身有點(diǎn)含糊,其實(shí)就是調(diào)用該同步方法的對象)通過使用同步方法,可非常方便的將某類變成線程安全的類
線程通訊:
為什么要使用線程通訊?
當(dāng)使用synchronized 來修飾某個共享資源時(分同步代碼塊和同步方法兩種情況),當(dāng)某個線程獲得共享資源的鎖后就可以執(zhí)行相應(yīng)的代碼段,直到該線程運(yùn)行完該代碼段后才釋放對該 共享資源的鎖,讓其他線程有機(jī)會執(zhí)行對該共享資源的修改。當(dāng)某個線程占有某個共享資源的鎖時,如果另外一個線程也想獲得這把鎖運(yùn)行就需要使用wait() 和notify()/notifyAll()方法來進(jìn)行線程通訊了。
其他答案:
同學(xué)回答說synchronized方法或代碼塊!面試官似乎不太滿意!
只有多個synchronized代碼塊使用的是同一個監(jiān)視器對象,這些synchronized代碼塊之間才具有線程互斥的效果,假如a代碼塊用obj1作為監(jiān)視器對象,假如b代碼塊用obj2作為監(jiān)視器對象,那么,兩個并發(fā)的線程可以同時分別進(jìn)入這兩個代碼塊中。 …這里還可以分析一下同步的原理。
對于同步方法的分析,所用的同步監(jiān)視器對象是this
接著對于靜態(tài)同步方法的分析,所用的同步監(jiān)視器對象是該類的Class對象
接著對如何實(shí)現(xiàn)代碼塊與方法的同步進(jìn)行分析。
67、String s = “Hello”;s = s + ” world!”;這兩行代碼執(zhí)行后,原始的String對象中的內(nèi)容到底變了沒有?
沒有。因為String被設(shè)計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內(nèi)容是 “Hello”,然后我們對s進(jìn)行了+操作,那么s所指向的那個對象是否發(fā)生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個 String對象,內(nèi)容為”Hello world!”,原來那個對象還存在于內(nèi)存之中,只是s這個引用變量不再指向它了。
68、String 和StringBuffer的區(qū)別
JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數(shù)據(jù)。String類表示內(nèi)容不可改變的字符串。而StringBuffer類表示內(nèi)容可以被修改的字符串。當(dāng)你知道字符數(shù)據(jù)要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動態(tài)構(gòu)造字符數(shù)據(jù)。另外,String實(shí)現(xiàn)了equals方法,new String(“abc”).equals(new String(“abc”)的結(jié)果為true,而StringBuffer沒有實(shí)現(xiàn)equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結(jié)果為false。
69、StringBuffer與StringBuilder的區(qū)別
StringBuffer和StringBuilder類都表示內(nèi)容可以被修改的字符串,StringBuilder是線程不安全的,運(yùn)行效率高,如果一個字符串變量是在方法里面定義,這種情況只可能有一個線程訪問它,不存在不安全的因素了,則用StringBuilder。如果要在類里面定義成員變量,并且這個類的實(shí)例對象會在多線程環(huán)境下使用,那么最好用StringBuffer。
70、數(shù)組有沒有l(wèi)ength()這個方法? String有沒有l(wèi)ength()這個方法?
數(shù)組沒有l(wèi)ength()這個方法,有l(wèi)ength的屬性。String有有l(wèi)ength()這個方法。
71、下面的程序代碼輸出的結(jié)果是多少?
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 ;
}
}
}
返回的結(jié)果是2。
72、設(shè)計4個線程,其中兩個線程每次對j增加1,另外兩個線程對j每次減少1。寫出程序。
以下程序使用內(nèi)部類實(shí)現(xiàn)線程,對j增減的時候沒有考慮順序問題。
public class ThreadTest1
{
private int j;
public static void main(String args[]){
ThreadTest1 tt=new ThreadTest1();
Inc inc=tt.new Inc();
Dec dec=tt.new Dec();
for(int i=0;i<2;i++){
Thread t=new Thread(inc);
t.start();
t=new Thread(dec);
t.start();
}
}
private synchronized void inc(){
j++;
System.out.println(Thread.currentThread().getName()+"-inc:"+j);
}
private synchronized void dec(){
j--;
System.out.println(Thread.currentThread().getName()+"-dec:"+j);
}
class Inc implements Runnable{
public void run(){
for(int i=0;i<100;i++){
inc();
}
}
}
class Dec implements Runnable{
public void run(){
for(int i=0;i<100;i++){
dec();
}
73、heap和stack有什么區(qū)別。
java的內(nèi)存分為兩類,一類是棧內(nèi)存,一類是堆內(nèi)存。棧內(nèi)存是指程序進(jìn)入一個方法時,會為這個方法單獨(dú)分配一塊私屬存儲空間,用于存儲這個方法內(nèi)部的局部變量,當(dāng)這個方法結(jié)束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。
堆是與棧作用不同的內(nèi)存,一般用于存放不放在當(dāng)前方法棧中的那些數(shù)據(jù),例如,使用new創(chuàng)建的對象都放在堆里,所以,它不會隨方法的結(jié)束而消失。方法中的局部變量使用final修飾后,放在堆中,而不是棧中。
74、寫一單實(shí)例類要求精簡、清晰。
懶漢模式:
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){
}
public static SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
#如上,通過提供一個靜態(tài)的對象instance,利用private權(quán)限的構(gòu)造方法和getInstance()方法來給予訪問者一個單例。
75、一列數(shù)的規(guī)則如下: 1、1、2、3、5、8、13、21、34…… 求第30位數(shù)是多少, 用遞歸算法實(shí)現(xiàn)
public class Test {
public static void main(String[] args) {
System.out.println("結(jié)果是:"+Test.foo(30));
}
/**
* 遞歸算法實(shí)現(xiàn)
*/
public static int foo(int i){
if(i<=0)
return 0;
else if(i>0 && i<=2)
return 1;
return foo(i-1) + foo(i-2);
}
}
76、
/*
面試題:final修飾局部變量的問題
基本類型:基本類型的值不能發(fā)生改變。
引用類型:引用類型的地址值不能發(fā)生改變,但是,該對象的堆內(nèi)存的值是可以改變的。
結(jié)果:100
10
--------------
10
100
--------------
10
100
*/
class Student {
int age = 10;
}
class FinalTest {
public static void main(String[] args) {
//局部變量是基本數(shù)據(jù)類型
int x = 10;
x = 100;
System.out.println(x);
final int y = 10;
//無法為最終變量y分配值
//y = 100;
System.out.println(y);
System.out.println("--------------");
//局部變量是引用數(shù)據(jù)類型
Student s = new Student();
System.out.println(s.age);
s.age = 100;
System.out.println(s.age);
System.out.println("--------------");
final Student ss = new Student();
System.out.println(ss.age);
ss.age = 100;
System.out.println(ss.age);
//重新分配內(nèi)存空間
//無法為最終變量ss分配值
ss = new Student();
}
}
77、多態(tài)中成員訪問的特點(diǎn)
/*
多態(tài):同一個對象(事物),在不同時刻體現(xiàn)出來的不同狀態(tài)。
舉例:
貓是貓,貓是動物。
水(液體,固體,氣態(tài))。
多態(tài)的前提:
A:要有繼承關(guān)系。
B:要有方法重寫。
其實(shí)沒有也是可以的,但是如果沒有這個就沒有意義。
動物 d = new 貓();//讀的時候從右往左讀(也可以這樣理解貓是new出來的對象,
而左邊是一個類。所以就相當(dāng)于判斷一個對象是不是這個類的實(shí)例)貓是貓,貓是動物。
d.show();
動物 d = new 狗();
d.show();
C:要有父類引用指向子類對象。
父 f = new 子();
用代碼體現(xiàn)一下多態(tài)。
多態(tài)中的成員訪問特點(diǎn):
A:成員變量
編譯看左邊,運(yùn)行看左邊。
B:構(gòu)造方法
創(chuàng)建子類對象的時候,訪問父類的構(gòu)造方法,對父類的數(shù)據(jù)進(jìn)行初始化。
C:成員方法
編譯看左邊,運(yùn)行看右邊。
D:靜態(tài)方法
編譯看左邊,運(yùn)行看左邊。
(靜態(tài)和類相關(guān),算不上重寫,所以,訪問還是左邊的)
由于成員方法存在方法重寫,所以它運(yùn)行看右邊。
*/
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父類引用指向子類對象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//找不到符號
//System.out.println(f.num2);
f.show();
//找不到符號
//f.method();
f.function();
}
}
總結(jié)
- 上一篇: PSTN ,PBX ,IP PBX,Vo
- 下一篇: iOS逆向工程之Reveal工具的安装、