Java常見面試題總結
轉載請註明出處https://www.cnblogs.com/lwy521/
1.面向對象
面向對象是基於現實事物,將事物抽象成對象,賦予對象屬性和方法,讓後讓每一對象去執行自己的方法與屬性,面向對象有三大基本特性:
封裝:把對象的屬性方法結合在一起,成為一個獨立的代碼塊。並盡可能隱藏對象的內部實現環節
繼承:從已有的類派生新的類。新類能得到已有的類的屬性和方法,並可以擴展出新的屬性和行為,繼承的作用是為了提高代碼的復用性,繼承具有傳遞性,單一性
多態:是同一種行為,有多重不同的表現狀態或形態的能力,分為行為的多態和對象的多態,表現形式有重寫重載向上造型
2.重載重寫的區別
1>重寫:發生在父子類中,方法名相同,參數列表相同,方法體不同,遵循運行期綁定,看對象類型類調用方法
兩同兩小一大
兩小:返回值,異常小於等於父類返回值,異常
一大:訪問修飾符大於等於父類訪問修飾符
2>重載:發生在一個類中,方法名相同,參數列表不同,方法體不用,遵循"編譯期綁定",看引用/參數類型來綁定方法.
為什麽不能根據返回類型來區分重載",快說出你的答案吧!
因為調用時不能指定類型信息,編譯器不知道你要調用哪個函數。 例如:
float max(int a, int b);
int max(int a, int b);
當調用max(1, 2);時無法確定調用的是哪個,單從這一點上來說,僅返回值類型不同的重載是不應該允許的。
3.抽象類與接口的區別
1>接口是完全抽象的,不存在方法的實現
抽象類可以方法的實現
2>接口使用implement實現方法,子類必須實現方法
抽象類通過extends繼承,如果子類不是抽象類,那麽必須去實現抽象方法
3>接口沒有構造器
抽象類有構造器,但不能被實例化
4>抽象方法可以有public、protected和default這些修飾符
接口只能被默認的public修飾
5>抽象方法可以有main方法並且我們可以運行它;
接口沒有
6>抽象方法可以繼承一個類和實現多個接口
接口只可以繼承一個或多個其他接口
聲明方法的存在而不去實現它的類被叫做抽象類(abstract class),它用於要創建一個體現某些基本行為的類,並為該類聲明方法,但不能在該類中實現該類的情況。不能創建abstract 類的實例。然而可以創建一個變量,其類型是一個抽象類,並讓它指向具體子類的一個實例。不能有抽象構造函數或抽象靜態方法。Abstract 類的子類為它們父類中的所有抽象方法提供實現,否則它們也是抽象類為。取而代之,在子類中實現該方法。知道其行為的其它類可以在類中實現這些方法。
接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。多繼承性可通過實現這樣的接口而獲得。接口中的所有方法都是抽象的,沒有一個有程序體。接口只可以定義static final成員變量。接口的實現與子類相似,除了該實現類不能從接口定義中繼承行為。當類實現特殊接口時,它定義(即將程序體給予)所有這種接口的方法。然後,它可以在實現了該接口的類的任何對象上調用接口的方法。由於有抽象類,它允許使用接口名作為引用變量的類型。通常的動態聯編將生效。引用可以轉換到接口類型或從接口類型轉換,instanceof 運算符可以用來決定某對象的類是否實現了接口。
4.什麽是匿名內部類
沒有名字的類稱為匿名內部類,想要創建一個父類接口的子類對象,且該對象只被創建一次,此時 該類不必命名,稱為匿名內部類
1.只能用於繼承一個類或者實現一個接口,並且只能創建一個該類的實例
2.匿名內部類中沒有構造方法,訪問控制修飾符.也不能有靜態的變量,方法和類.
3.匿名內部類屬於局部內部類,所以局部內部類的限制也對其有效,只能訪問外部類的靜態方法和靜態變量
5.int 與integer的區別
1>int是基本數據對象,不能直接參與面向對象的開發,所以提供了包裝類Integer
2>integer變量必須實例化後才能使用,int變量不需要.
3>Integer的默認值為null,int的默認值為0;
4>jdk1.5提供自動拆裝箱,滿足了基本數據變量與引用類型的賦值
6.正則表達式
正則表達式是用於字符串的匹配和替換,驗證當前字符串是否滿足各種需求.
7.String,StringBuilder和StringBuffer的區別。
1.String:字符串常量,是不可變對象,每次對String類型進行改變都等同於生成了一個新的String對象,速度慢. 適用於少量字符串操作的情況.
2.StringBuffer:其中很多方法有synchronized關鍵字,是線程安全的可變字符序列,速度較快.適用於多線程下在字符緩沖區進行大量操作的情況
2.StringBuilder,JDK1.5之後推出的與StringBuffer兼容的API,用作StringBuffer的一個簡單替換,單個線程使用時,建議優先采用,速度最快.適用於多線程下載字符緩沖區進行大量操作的情況.
8.什麽是socket?
套接字(socket)是一個網絡中特定節點的網絡標識符,套接字包含一個特定的地址和端口號,java中的網絡通信是通過socket實現的,socket包含兩大類: serversocket和socket兩大類,ServerSocket用於服務器端,可以通過accept方法監聽請求,監聽請求後返回Socket,Socket用於完成具體數據傳輸,客戶端也可以使用Socket發起請求並傳輸數據.
9.Html與xml的區別。
1.HTML:超文本標記語言,XML:可擴展標記語言
2.HTML語法不嚴格區分大小寫,可以自動過濾空格,可以不適用引號等,XML卻相反
3.HTML中有固定的標簽,xml可以自定義和擴展標簽
4.HTML是用來顯示數據的,xml是用來描述,存放數據的.
10.Throw與throws的區別
1.Throws出現在方法函數頭;而throw出現在函數體
2.throws表示出現異常的一種可能性,並不一定會發生這些異常;
throw則是拋出了異常,執行throw則一定拋出了某種異常對象.
3.它們都是消極處理異常的方式,只是拋出或者可能拋出異常,但是不會由函數去處理異常,真正的處理異常由函數的上層調用處理.
11.說一說你對異常處理機制的理解
如果程序不能正常的運行,那麽可以就可以通過另一種路徑退出方法,在這種情況下會拋出一個封裝了錯誤信息的對象。這個方法會立刻退出同時不返回任何值。另外,調用這個方法的其他代碼也無法繼續執行,異常處理機制會將代碼執行交給異常處理器。
如果出現RuntimeException,那麽一定是程序員的錯誤
遇到問題不進行具體處理,而是繼續拋給調用者 拋出異常有三種形式,
1.是throw,一個throws,還有一種系統自動拋異常。
2.針對性處理方式:使用try-catch捕獲異常
12. Final和finally以及finalize的區別
1.Final:修飾符關鍵字,用於聲明屬性,方法和類,分別表示:屬性不可改變,方法不能被重寫,類不能被繼承.
2.Finally:是異常處理機制的一部分,finally確保只要程序執行到try塊中,那麽finally塊中的代碼必定執行.
3.Finalize:是Object類的一個方法,在垃圾收集器(gc)將對象從內存中清除出去之前,做必要的清理工作和其他資源的回收.
13.List,set,map的區別。
1.List是Collection的一個子接口,稱為線性表,是可重復有序集,可以通過下標對元素操作,常用實現類有ArrayList:數組實現,查詢性能好.和LinkedList:鏈表實現,便於增刪元素.
2.set也是Collection的一個子接口,是不可重復且無序集,但其實現類能對集合中的對象按照特定的方式排序,比如TreeSet.常用實現類有HashSet和TreeSet.
3.Map接口,查找表,其中的每一個元素是一個鍵值對,鍵對象不可重復,值對象可重復.常用實現類有:HashMap:當今世界查詢速度最快的數據結構.HashTable 和LinkedHashMap 等.
Set裏的元素是不能重復的,那麽用什麽方法來區分重復與否呢? 是用==還是equals()? 它們有何區別:
Set裏的元素是不能重復的,那麽用iterator()方法來區分重復與否。equals()是判讀兩個Set是否相等。
equals()和==方法決定引用值是否指向同一對象equals()在類中被覆蓋,為的是當兩個分離的對象的內容和類型相配的話,返回真值。
14.HashMap與HashTable的區別。
1.HashMap是線程不安全的,HashMap是Map的一個子接口,是將鍵映射到值得到對象,不允許鍵值重復,允許空鍵和空值.
2.HashTable是線程安全的集合,不允許null值作為key或value,它是synchronized修飾的,多個線程訪問時不需要自己為它的方法實現同步,而HashMap在被多個線程訪問時需要自己為它的方法實現同步.
3.由於HashMap非線程安全,所以HashMap的效率要比HashTable的效率高一些.
15.線程與進程的區別
1、定義
進程:是執行中一段程序,即一旦程序被載入到內存中並準備執行,它就是一個進程。進程是操作系統資源分配的基本單位.
線程:單個進程中執行中每個任務就是一個線程。
線程:是進程中任務調度和執行的基本單位
2、一個線程只能屬於一個進程,但是一個進程可以擁有多個線程。多線程處理就是允許一個進程中在同一時刻執行多個任務。
3、線程是一種輕量級的進程,與進程相比,線程給操作系統帶來側創建、維護、和管理的負擔要輕,意味著線程的代價或開銷比較小。
4.沒有線程的進程可以看做是單線程的,如果一個進程內有多個線程,則執行過程不是一條線的,而是多條線(線程)共同完成的;線程是進程的一部分,所以線程也被稱為輕權進程或者輕量級進程。
16.線程的生命周期?線程有哪些狀態
1、線程的生命周期:新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態。
17.說一說你對反射機制的看法?反射機制的優缺點?
1.反射機制:將在編譯期實例化一個類,操作其屬性和方法的操作轉換為運行期決定.
2.適度使用可以提高代碼的靈活度,過度使用會降低代碼運行效率,增加資源開銷.
3.步驟:
1.通過class類中的forName靜態方法獲取加載類對象
2.通過類對象實例化該類.newInstance方法
3.獲取類中的方法,通過傳入參數匹配對應的方法
getDeclaredMethods("方法名","數據類型.class")
4.傳入實參,執行該方法
invoke(obj,"實參").
18.如何創建一個線程池?利用線程池有哪些好處。(數據庫連接池)
1.線程池:管理線程機制,主要解決重用線程和控制線程數量.
2.可以有效處理多個線程的並發問題,避免大量的線程因為互相強占系統資源導致阻塞現象,有效降低頻繁創建和銷毀對性能帶來的開銷.
3.對線程數量的控制也應在硬件的承受範圍之內.
4.創建:fixedThreadPool:正規線程池,指定了線程數,有核心線程,正規的並發線程,響應速度快,多用於服務器.
ExecutorService threadpool = Executors.newFixedThreadPool(3);
19.HTTP協議
HttP協議:超文本傳輸協議
1.該協議是應用層協議,該協議應用在瀏覽器與服務器之間
2.規定了瀏覽器與服務器之間數據傳輸的方式,以及數據內容定義等規則
3.HTTP協議要求必須建立在可靠的傳輸協議基礎上,通常使用的是TCP協議.
4.HTTP協議定義了瀏覽器(瀏覽器)與服務器之間的交互規則:要求客戶端發起請求,服務端接收請 求並處理,然後響應客戶端.不允許服務端主動響應客戶端.
5.HTTP協議要求使用的字符集為ISO8859-1,不支持中文字符,所以傳輸中文時需要特別處理.
19.靜態變量和實例變量的區別
1.實例變量是屬於某個對象的屬性,必須創建了實例對象,其中的實例變量才會被分配空間,才能使用這個實例變量.
2.靜態變量屬於類,也稱類變量,只要程序加載了類的字節碼文件,無需創建任何實例對象,靜態變量就會被分配空間(方法區),就可以被使用
3.總結:實例變量必須在創建對象後才可以通過這個對象來使用,而靜態變量可以直接使用類名類引用.
20.內存管理:
1.堆中存放: new出來的對象(包括實例變量)
實例變量生命周期:從對象被創建到被回收
2.棧中存放: 正在調用的方法中的局部變量(包括方法中的參數)
局部變量生命周期:調用方法時存在棧中,方法結束時與棧幀一次消失.
3.方法區: 存儲.class字節碼文件(包括方法,靜態變量);
21.&和&&的區別:
&是位運算符。&&是布爾邏輯運算符。
22.Collection 和 Collections的區別:
Collections是個java.util下的類,它包含有各種有關集合操作的靜態方法。
Collection是個java.util下的接口,它是各種集合結構的父接口。
22.GC是什麽? 為什麽要有GC? (基礎):
GC是垃圾收集器。Java 程序員不用擔心內存管理,因為垃圾收集器會自動進行管理。要請求垃圾收集,可以調用下面的方法之一:
System.gc()
Runtime.getRuntime().gc()。
23.String s = new String("xyz");創建了幾個String Object:
兩個對象,一個是“xyx”,一個是指向“xyx”的引用對象s。
第一個對象是字符串常量"xyz" 第二個對象是new String("xyz")的時候產生的,在堆中分配內存給這個對象,只不過這個對象的內容是指向字符串常量"xyz" 另外還有一個引用s,指向第二個對象。這是一個變量,在棧中分配內存。
24.sleep() 和 wait() 有什麽區別:
sleep()方法是使線程停止一段時間的方法。在sleep 時間間隔期滿後,線程不一定立即恢復執行。這是因為在那個時刻,其它線程可能正在運行而且沒有被調度為放棄執行,除非(a)“醒來”的線程具有更高的優先級(b)正在運行的線程因為其它原因而阻塞。
wait()是線程交互時,如果線程對一個同步對象x 發出一個wait()調用,該線程會暫停執行,被調對象進入等待狀態,直到被喚醒或等待時間到。
25.數組有沒有length()這個方法? String有沒有length()這個方法:
數組沒有length()這個方法,有length的屬性。
String有有length()這個方法。
26.啟動一個線程是用run()還是start():
啟動一個線程是調用start()方法,使線程所代表的虛擬處理機處於可運行狀態,這意味著它可以由JVM調度並執行。這並不意味著線程就會立即運行。run()方法可以產生必須退出的標誌來停止一個線程。
27.構造器Constructor是否可被override:
構造器Constructor不能被繼承,因此不能重寫Overriding,但可以被重載Overloading。
28.try {}裏有一個return語句,那麽緊跟在這個try後的finally {}裏的code會不會被執行,什麽時候被執行,在return前還是後:
會執行,在return前執行。
在finally中改變返回值的做法是不好的,因為如果存在finally代碼塊,try中的return語句不會立馬返回調用者,而是記錄下返回值待finally代碼塊執行完畢之後再向調用者返回其值,然後如果在finally中修改了返回值,就會返回修改後的值。顯然,在finally中返回或者修改返回值會對程序造成很大的困擾,C#中直接用編譯錯誤的方式來阻止程序員幹這種齷齪的事情,Java中也可以通過提升編譯器的語法檢查級別來產生警告或錯誤,Eclipse中可以在如圖所示的地方進行設置,強烈建議將此項設置為編譯錯誤。
29.ArrayList和Vector的區別,HashMap和Hashtable的區別:
答:就ArrayList與Vector主要從二方面來說.
一.同步性:Vector是線程安全的,也就是說是同步的,而ArrayList是線程序不安全的,不是同步的
二.數據增長:當需要增長時,Vector默認增長為原來一培,而ArrayList卻是原來的一半
就HashMap與HashTable主要從三方面來說。
一.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value。
30.說一說Servlet的生命周期:
答:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init,service和destroy方法表達。
31.JAVA SERVLET API中forward() 與redirect()的區別:
答:前者僅是容器中控制權的轉向,在客戶端瀏覽器地址欄中不會顯示出轉向後的地址;後者則是完全的跳轉,瀏覽器將會得到跳轉的地址,並重新發送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉後的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,盡量使用forward()方法,並且,這樣也有助於隱藏實際的鏈接。在有些情況下,比如,需要跳轉到一個其它服務器上的資源,則必須使用sendRedirect()方法。
32.Class.forName的作用?為什麽要用:
答:調用該訪問返回一個以字符串指定類名的類的對象。
33.Jdo是什麽:
JDO是Java對象持久化的新的規範
34.xml有哪些解析技術?區別是什麽:
答:有DOM,SAX,STAX等
DOM:處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構占用的內存較多,而且DOM必須在解析文件之前把整個文檔裝入內存,適合對XML的隨機訪問
SAX:不現於DOM,SAX是事件驅動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當遇到像文件開頭,文檔結束,或者標簽開頭與標簽結束時,它會觸發一個事件,用戶通過在其回調事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問
STAX:Streaming API for XML (StAX)。
35.基本數據類型包括byte1、short2、int4、long8、char2、float4、double8、boolean1
36.序列化和反序列化的概念
把對象轉換為字節序列的過程稱為對象的序列化
把字節序列恢復為對象的過程稱為對象的反序列化
37.heap和stack有什麽區別:
棧是一種線形集合,其添加和刪除元素的操作應在同一段完成。棧按照後進先出的方式進行處理。堆是棧的一個組成元素。
38.J2EE是技術還是平臺還是框架:
J2EE本身是一個標準,一個為企業分布式應用的開發提供的標準平臺。
J2EE也是一個框架,包括JDBC、JNDI、RMI、JMS、EJB、JTA等技術。
編寫 java文件的註意事項:
39.常用的設計模式?說明工廠模式:
Java中的23種設計模式:Factory(工廠模式),Builder(建造模式), Factory Method(工廠方法模式),Prototype(原始模型模式),Singleton(單例模式), Facade(門面模式),Adapter(適配器模式), Bridge(橋梁模式), Composite(合成模式),Decorator(裝飾模式), Flyweight(享元模式), Proxy(代理模式),Command(命令模式), Interpreter(解釋器模式), Visitor(訪問者模式),Iterator(叠代子模式), Mediator(調停者模式), Memento(備忘錄模式),Observer(觀察者模式),State(狀態模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibleity(責任鏈模式)。
工廠模式:工廠模式是一種經常被使用到的模式,根據工廠模式實現的類可以根據提供的數據生成一組類中某一個類的實例,通常這一組類有一個公共的抽象父類並且實現了相同的方法,但是這些方法針對不同的數據進行了不同的操作。首先需要定義一個基類,該類的子類通過不同的方法實現了基類中的方法。然後需要定義一個工廠類,工廠類可以根據條件生成不同的子類實例。當得到子類的實例後,開發人員可以調用基類中的方法而不必考慮到底返回的是哪一個子類的實例。
40.java中有幾種方法可以實現一個線程?
有兩種實現方法,分別是繼承Thread類與實現Runnable接口
41.什麽是java序列化,如何實現java序列化:
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。可以對流化後的對象進行讀寫操作,也可將流化後的對象傳輸於網絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發的問題。序列化的實現:將需要被序列化的類實現Serializable接口,該接口沒有需要實現的方法,implements Serializable只是為了標註該對象是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。
42.垃圾回收的優點和原理。並考慮2種回收機制
答:Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候不再需要考慮內存管理。由於有個垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用才有"作用域"。垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作為一個單獨的低級別的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清楚和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。回收機制有分代復制垃圾回收和標記垃圾回收,增量垃圾回收。
43.是否可以繼承String類
答:String類是final類故不可以繼承
44.抽象類的特點:
1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關鍵字修飾(可以描述類和方法,不可以描述變量)。
2:抽象方法只定義方法聲明,並不定義方法實現。
3:抽象類不可以被創建對象(實例化)。
4:只有通過子類繼承抽象類並覆蓋了抽象類中的所有抽象方法後,該子類才可以實例化。否則,該子類還是一個抽象類。
5: 抽象類只能單繼承。
45.js塊元素,行元素
塊元素
<address> 定義地址
<caption> 定義表格標題
<dd> 定義列表中定義條目
<div> 定義文檔中的分區或節
<dl> 定義列表
<dt> 定義列表中的項目
<fieldset> 定義一個框架集
<form> 創建 HTML 表單
<h1> 定義最大的標題
<h2> 定義副標題
<h3> 定義標題
<h4> 定義標題
<h5> 定義標題
<h6> 定義最小的標題
<hr> 創建一條水平線
<legend> 元素為 fieldset 元素定義標題
<li> 標簽定義列表項目
<noframes> 為那些不支持框架的瀏覽器顯示文本,於 frameset 元素內部
<noscript> 定義在腳本未被執行時的替代內容
<ol> 定義有序列表
<ul> 定義無序列表
<p> 標簽定義段落
<pre> 定義預格式化的文本
<table> 標簽定義 HTML 表格
<tbody> 標簽表格主體(正文)
<td> 表格中的標準單元格
<tfoot> 定義表格的頁腳(腳註或表註)
<th> 定義表頭單元格
<thead> 標簽定義表格的表頭
<tr> 定義表格中的行
<a>行元素 標簽可定義錨
<abbr> 表示一個縮寫形式
<acronym> 定義只取首字母縮寫
<b> 字體加粗
<bdo> 可覆蓋默認的文本方向
<big> 大號字體加粗
<br> 換行
<cite> 引用進行定義
<code> 定義計算機代碼文本
<dfn> 定義一個定義項目
<em> 定義為強調的內容
<i> 斜體文本效果
<img> 向網頁中嵌入一幅圖像
<input> 輸入框
<kbd> 定義鍵盤文本
<label> 標簽為 input 元素定義標註(標記)
<q> 定義短的引用
<samp> 定義樣本文本
<select> 創建單選或多選菜單
<small> 呈現小號字體效果
<span> 組合文檔中的行內元素
<strong> 語氣更強的強調的內容
<sub> 定義下標文本
<sup> 定義上標文本
<textarea> 多行的文本輸入控件
<tt> 打字機或者等寬的文本效果
<var> 定義變量
46.修飾權限問題
47.描述一下JVM加載class文件的原理機制?
答:JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現的,Java中的類加載器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。 由於Java的跨平臺性,經過編譯的Java源程序並不是一個可執行程序,而是一個或多個類文件。當Java程序需要使用某個類時,JVM會確保這個類已經被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的.class文件中的數據讀入到內存中,通常是創建一個字節數組讀入.class文件,然後產生與所加載類對應的Class對象。加載完成後,Class對象還不完整,所以此時的類還不可用。當類被加載後就進入連接階段,這一階段包括驗證、準備(為靜態變量分配內存並設置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟。最後JVM對類進行初始化,包括:1)如果類存在直接的父類並且這個類還沒有被初始化,那麽就先初始化父類;2)如果類中存在初始化語句,就依次執行這些初始化語句。 類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類加載過程采取了父親委托機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根加載器,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載。JVM不會向Java程序提供對Bootstrap的引用。下面是關於幾個類加載器的說明:
Bootstrap:一般用本地代碼實現,負責加載JVM基礎核心類庫(rt.jar);
Extension:從java.ext.dirs系統屬性所指定的目錄中加載類庫,它的父加載器是Bootstrap;
System:又叫應用類加載器,其父類是Extension。它是應用最廣泛的類加載器。它從環境變量classpath或者系統屬性java.class.path所指定的目錄中加載類,是用戶自定義加載器的默認父加載器。
48.靜態嵌套類(Static Nested Class)和內部類(Inner Class)的不同?
答:Static Nested Class是被聲明為靜態(static)的內部類,它可以不依賴於外部類實例被實例化。而通常的內部類需要在外部類實例化後才能實例化,其語法看起來挺詭異的,如下所示。
面試題 - 下面的代碼哪些地方會產生編譯錯誤?
class Outer {
class Inner {}
public static void foo() { new Inner(); }
public void bar() { new Inner(); }
public static void main(String[] args) {
new Inner();
}
}
註意:Java中非靜態內部類對象的創建要依賴其外部類對象,上面的面試題中foo和main方法都是靜態方法,靜態方法中沒有this,也就是說沒有所謂的外部類對象,因此無法創建內部類對象,如果要在靜態方法中創建內部類對象,可以這樣做:
new Outer().new Inner();
49.數據類型之間的轉換:
如何將字符串轉換為基本數據類型?
如何將基本數據類型轉換為字符串?
答:
調用基本數據類型對應的包裝類中的方法parseXXX(String)或valueOf(String)即可返回相應基本類型;
一種方法是將基本數據類型與空字符串("")連接(+)即可獲得其所對應的字符串;另一種方法是調用String 類中的valueOf()方法返回相應字符串
50.如何實現字符串的反轉及替換?
答:方法很多,可以自己寫實現也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常見的面試題是用遞歸實現字符串反轉,代碼如下所示:
public static String reverse(String originStr) {
if(originStr == null || originStr.length() <= 1)
return originStr;
return reverse(originStr.substring(1)) + originStr.charAt(0);
}
51.Error和Exception有什麽區別?
答:Error表示系統級的錯誤和程序不必處理的異常,是恢復不是不可能但很困難的情況下的一種嚴重問題;比如內存溢出,不可能指望程序能處理這樣的情況;Exception表示需要捕捉或者需要程序進行處理的異常,是一種設計或實現問題;也就是說,它表示如果程序運行正常,從不會發生的情況。
52.列出一些你常見的運行時異常?
答:
ArithmeticException(算術異常)
ClassCastException (類轉換異常)
IllegalArgumentException (非法參數異常)
IndexOutOfBoundsException (下標越界異常)
NullPointerException (空指針異常)
SecurityException (安全異常)
53、List、Set、Map是否繼承自Collection接口?
答:List、Set 是,Map 不是。Map是鍵值對映射容器,與List和Set有明顯的區別,而Set存儲的零散的元素且不允許有重復元素(數學中的集合也是如此),List是線性結構的容器,適用於按數值索引訪問元素的情形。
54.List、Set、Map是否繼承自Collection接口?
答:List、Set 是,Map 不是。Map是鍵值對映射容器,與List和Set有明顯的區別,而Set存儲的零散的元素且不允許有重復元素(數學中的集合也是如此),List是線性結構的容器,適用於按數值索引訪問元素的情形。
55.synchronized關鍵字的用法?
答:synchronized關鍵字可以將對象或者方法標記為同步,以實現對對象和方法的互斥訪問,可以用synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時將synchronized作為方法的修飾符。在第60題的例子中已經展示了synchronized關鍵字的用法。
56.Java中有幾種類型的流?
答:字節流和字符流。字節流繼承於InputStream、OutputStream,字符流繼承於Reader、Writer。在 java.io 包中還有許多其他的流,主要是為了提高性能和使用方便。關於Java的I/O需要註意的有兩點:一是兩種對稱性(輸入和輸出的對稱性,字節和字符的對稱性);二是兩種設計模式(適配器模式和裝潢模式)。另外Java中的流不同於C#的是它只有一個維度一個方向。
面試題 - 編程實現文件拷貝。(這個題目在筆試的時候經常出現,下面的代碼給出了兩種實現方案)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public final class MyUtil {
private MyUtil() {
throw new AssertionError();
}
public static void fileCopy(String source, String target) throws IOException {
try (InputStream in = new FileInputStream(source)) {
try (OutputStream out = new FileOutputStream(target)) {
byte[] buffer = new byte[4096];
int bytesToRead;
while((bytesToRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
}
}
}
public static void fileCopyNIO(String source, String target) throws IOException {
try (FileInputStream in = new FileInputStream(source)) {
try (FileOutputStream out = new FileOutputStream(target)) {
FileChannel inChannel = in.getChannel();
FileChannel outChannel = out.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(4096);
while(inChannel.read(buffer) != -1) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
}
}
}
}
註意:上面用到Java 7的TWR,使用TWR後可以不用在finally中釋放外部資源 ,從而讓代碼更加優雅。
57.你在項目中哪些地方用到了XML?
答:XML的主要作用有兩個方面:數據交換和信息配置。在做數據交換時,XML將數據用標簽組裝成起來,然後壓縮打包加密後通過網絡傳送給接收者,接收解密與解壓縮後再從XML文件中還原相關信息進行處理,XML曾經是異構系統間交換數據的事實標準,但此項功能幾乎已經被JSON(JavaScript Object Notation)取而代之。當然,目前很多軟件仍然使用XML來存儲配置信息,我們在很多項目中通常也會將作為配置信息的硬代碼寫在XML文件中,Java的很多框架也是這麽做的,而且這些框架都選擇了dom4j作為處理XML的工具,因為Sun公司的官方API實在不怎麽好用。
補充:現在有很多時髦的軟件(如Sublime)已經開始將配置文件書寫成JSON格式,我們已經強烈的感受到XML的另一項功能也將逐漸被業界拋棄。
58.獲得一個類的類對象有哪些方式?
答:
方法1:類型.class,例如:String.class
方法2:對象.getClass(),例如:"hello".getClass()
方法3:Class.forName(),例如:Class.forName("java.lang.String")
59.如何通過反射創建對象?
答:
方法1:通過類對象調用newInstance()方法,例如:String.class.newInstance()
方法2:通過類對象的getConstructor()或getDeclaredConstructor()方法獲得構造器(Constructor)對象並調用其newInstance()方法創建對象,例如:String.class.getConstructor(String.class).newInstance("Hello");
60.用Java寫一個單例類。
答:
餓漢式單例
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
懶漢式單例
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance(){
if (instance == null) instance = new Singleton();
return instance;
}
}
註意:實現一個單例有兩點註意事項,①將構造器私有,不允許外界通過構造器創建對象;②通過公開的靜態方法向外界返回類的唯一實例。這裏有一個問題可以思考:Spring的IoC容器可以為普通的類創建單例,它是怎麽做到的呢?
61.冒泡排序幾乎是個程序員都寫得出來,但是面試的時候如何寫一個逼格高的冒泡排序卻不是每個人都能做到,下面提供一個參考代碼:
import java.util.Comparator;
/**
* 排序器接口(策略模式: 將算法封裝到具有共同接口的獨立的類中使得它們可以相互替換)
* @author nnngu
*
*/
public interface Sorter {
/**
* 排序
* @param list 待排序的數組
*/
public <T extends Comparable<T>> void sort(T[] list);
/**
* 排序
* @param list 待排序的數組
* @param comp 比較兩個對象的比較器
*/
public <T> void sort(T[] list, Comparator<T> comp);
}
import java.util.Comparator;
/**
* 冒泡排序
*
* @author nnngu
*
*/
public class BubbleSorter implements Sorter {
@Override
public <T extends Comparable<T>> void sort(T[] list) {
boolean swapped = true;
for (int i = 1, len = list.length; i < len && swapped; ++i) {
swapped = false;
for (int j = 0; j < len - i; ++j) {
if (list[j].compareTo(list[j + 1]) > 0) {
T temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
swapped = true;
}
}
}
}
@Override
public <T> void sort(T[] list, Comparator<T> comp) {
boolean swapped = true;
for (int i = 1, len = list.length; i < len && swapped; ++i) {
swapped = false;
for (int j = 0; j < len - i; ++j) {
if (comp.compare(list[j], list[j + 1]) > 0) {
T temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
swapped = true;
}
}
}
}
Java常見面試題總結