Java面試題答案

1、面向對象的特征有哪些方面?

答:面向對象的特征主要有以下幾個方面:

-- 抽象:抽象是將一類對象的共同特征總結出來構造類的過程,包括數據抽象和行為抽象兩方面。抽象只關注對象有哪些屬性和行為,并不關具體細節是什么。

-- 封裝:通常認為封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口。面向對象的本質就是將現實世界描繪成一系列完全自治、封閉的對象。我們在類中編寫的方法就是對實現細節的一種封裝;我們編寫一個類就是對數據和數據操作的封裝。可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口(可以想想普通洗衣機和全自動洗衣機的差別,明顯全自動洗衣機封裝更好因此操作起來更簡單;我們現在使用的智能手機也是封裝得足夠好的,因為幾個按鍵就搞定了所有的事情)。

-- 繼承:繼承是從已有類得到繼承信息創建新類的過程。提供繼承信息的類被稱為父類(超類、基類);得到繼承信息的類被稱為子類(派生類)。繼承讓變化中的軟件系統有了一定的延續性,同時繼承也是封裝程序中可變因素的重要手段。

-- 多態性:多態性是指允許不同子類型的對象對同一消息作出不同的響應。簡單的說就是用同樣的對象引用調用同樣的方法但是做了不同的事情。多態性分為編譯時的多態性和運行時的多態性。方法重載(overload)實現的是編譯時的多態性(也稱為前綁定),而方法重寫(override)實現的是運行時的多態性(也稱為后綁定)。

2、訪問修飾符public,private,protected,以及不寫(默認)時的區別?

答:類的成員不寫訪問修飾時默認為default。范圍見下圖:

修飾符 當前類 同 包 子 類 其他包
public
protected ×
default × ×
private × × ×
3、String 是最基本的數據類型嗎?

答:不是。Java中的基本數據類型只有8個:byte、short、int、long、float、double、char、boolean。

4、int和Integer有什么區別?

答:Java是一個近乎純潔的面向對象編程語言,但是為了編程的方便還是引入了基本數據類型,但是為了能夠將這些基本數據類型當成對象操作,Java為每一個基本數據類型都引入了對應的包裝類型(wrapper class),int的包裝類就是Integer,從Java 5開始引入了自動裝箱/拆箱機制,使得二者可以相互轉換。

Java 為每個原始類型提供了包裝類型:

  • 原始類型: boolean,char,byte,short,int,long,float,double

  • 包裝類型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

5、重載(Overload)和重寫(Override)的區別?

答:方法的重載和重寫都是實現多態的方式,區別在于前者實現的是編譯時的多態性,而后者實現的是運行時的多態性。重載發生在一個類中,同名的方法如果有不同的參數列表(參數類型不同、參數個數不同或者二者都不同)則視為重載;重寫發生在子類與父類之間,重寫要求子類重寫方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好訪問(只能比父類訪問范圍更大),不能比父類被重寫方法聲明更多的異常(里氏代換原則)。

6、抽象類(abstract class)和接口(interface)有什么異同?

答:抽象類和接口都不能夠實例化(new XXX),但可以定義抽象類和接口類型的引用(XXX xx = new XXX的實現類)。一個類如果繼承了某個抽象類或者實現了某個接口都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明為抽象類。接口比抽象類更加抽象,因為抽象類中可以定義構造器,可以有抽象方法和具體方法,而接口中不能定義構造器而且其中的方法全部都是抽象方法。抽象類中的成員可以是private、default、protected、public的,而接口中的成員全都是public的。抽象類中可以定義成員變量,而接口中定義的成員變量實際上都是常量。有抽象方法的類必須被聲明為抽象類,而抽象類未必要有抽象方法。

7、Java里的傳引用和傳值的區別是什么?

答:傳引用是指傳遞的是地址而不是值本身,傳值則是傳遞值的一份拷貝。

8、==與equals的區別?

答:==比較的是引用而equals方法比較的是內容。public boolean equals(Object obj) 這個方法是由Object對象提供的,可以由子類進行重寫。

9、如何將String類型轉化成Number類型?

答:Integer類的valueOf方法可以將String轉成Number。

10、&操作符和&&操作符有什么區別?

答:&是位運算符,表示按位與運算;&&是邏輯運算符,表示邏輯與(and)。除了長得像沒有半點關系。

11、switch 語句能否作用在byte 上,能否作用在long 上,能否作用在String上?

答:在switch(expr1)中,expr1只能是一個整數表達式或者枚舉常量(更大字體),整數表達式可以是int基本類型或Integer包裝類型,由于,byte,short,char都可以隱含轉換為int,所以,這些類型以及這些類型的包裝類型也是可以的。顯然,long和String類型都不符合switch的語法規定,并且不能被隱式轉換成int類型,所以,它們不能作用于swtich語句中。

12、short s1 = 1; s1 = s1 + 1; 有什么錯? short s1 = 1; s1 +=1; 有什么錯?

答:對于

  short s1 = 1;   
  s1 = s1 + 1;

由于s1+1運算時會自動提升表達式的類型,所以結果是int型,再賦值給short類型s1時,編譯器將報告需要強制轉換類型的錯誤。

對于

  short s1 = 1; 
  s1 += 1;

由于 +=是java語言規定的運算符,java編譯器會對它進行特殊處理,因此可以正確編譯。

13、使用final 關鍵字修飾一個變量時,是引用不能變,還是引用的對象不能變?

答:使用final關鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內容還是可以改變的。例如,對于如下語句:

final StringBuffer a=new StringBuffer("abcdefg");

執行如下語句將報告編譯期錯誤:

a=new StringBuffer("");

但是,執行如下語句則可以通過編譯:

a.append("xxoo");
14、String s = new String("xyz"); 創建了幾個String Object?

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

15、StringBuffer 與StringBuilder的區別?

答:StringBuilder不是線程安全的,運行效率高;StringBuffer是線程安全的,運行效率不及StringBuilder。

16、數組有沒有length() 這個方法?String 有沒有length() 這個方法?

答:數組沒有length()這個方法,有length的屬性。String有有length()這個方法。

17、final, finally, finalize的區別?

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

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

finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收。

18、啟動一個線程是用run() 還是start()?

答:啟動一個線程是調用start()方法,使線程就緒狀態,以后可以被調度為運行狀態,一個線程必須關聯一些具體的執行代碼,run()方法是該線程所關聯執行的代碼。

19、字節流與字符流的區別?

答:在應用中,經常要完全是字符的一段文本輸出去或讀進來,用字節流可以嗎?計算機中的一切最終都是二進制的字節形式存在。對于“中國”這些字符,首先要得到其對應的字節,然后將字節寫入到輸出流。讀取時,首先讀到的是字節,可是我們要把它顯示為字符,我們需要將字節轉換成字符。由于這樣的需求很廣泛,人家專門提供了字符流的包裝類。底層設備永遠只接受字節數據,有時候要寫字符串到底層設備,需要將字符串轉成字節再進行寫入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫入底層設備,這為我們向IO設別寫入或讀取字符串提供了一點點方便。字符向字節轉換時,要注意編碼的問題,因為字符串轉成字節數組,其實是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。

20、什么是java 序列化,如何實現java 序列化?

答:我們有時候將一個java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個java對象,例如,要將java對象存儲到硬盤或者傳送給網絡上的其他計算機,這個過程我們可以自己寫代碼去把一個java對象變成某個格式的字節流再傳輸,但是,jre本身就提供了這種支持,我們可以調用OutputStream的writeObject方法來做,如果要讓java幫我們做,要被傳輸的對象必須實現serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable接口。

21、Servlet的生命周期?

答:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init,service和destroy方法表達。web容器加載servlet,生命周期開始,通過調用servlet的init()方法進行servlet的初始化,通過調用service()方法實現,根據請求的不同調用不同的doXXX方法(doGet,doPost)等,結束服務,web容器調用servlet的destroy()方法。

22、servlet api 中 forward()與redirect()的區別?

答:前者僅是容器中控制權的轉向,在客戶端瀏覽器地址欄中不會顯示出轉向后的地址;后者則是完全的跳轉,瀏覽器將會得到跳轉的地址,并重新發送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉后的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,盡量使用forward()方法,并且,這樣也有助于隱藏實際的鏈接。在有些情況下,比如,需要跳轉到一個其它服務器上的資源,則必須使用sendRedirect()方法。

23、 jsp 有哪些內置對象? 作用分別是什么?

答:JSP共有以下9個內置的對象:

-- request, 表示HttpServletRequest對象,它包含了有關瀏覽器請求的信息,并且提供了幾個用于獲取cookie, header, 和session數據的有用的方法。

-- response,表示HttpServletResponse對象,并提供了幾個用于設置送回瀏覽器的響應的方法(如cookies,頭信息等)。

-- pageContext,表示一個javax.servlet.jsp.PageContext對象。它是用于方便存取各種范圍的名字空間、servlet相關的對象的API,并且包裝了通用的servlet相關功能的方法。

-- session,表示一個請求的javax.servlet.http.HttpSession對象。Session可以存貯用戶的狀態信息。

-- application,表示一個javax.servle.ServletContext對象。這有助于查找有關servlet引擎和servlet環境的信息。

-- out,out對象是javax.jsp.JspWriter的一個實例,并提供了幾個方法使你能用于向瀏覽器回送輸出結果。

-- config,表示一個javax.servlet.ServletConfig對象。該對象用于存取servlet實例的初始化參數。

-- page,表示從該頁面產生的一個servlet實例。

-- exception 針對錯誤網頁,未捕捉的例外

24、JSP中動態INCLUDE與靜態INCLUDE的區別?

答:動態INCLUDE用<jsp:include page=included.jsp flush=true/>實現它總是會檢查所含文件中的變化,適合用于包含動態頁面,并且可以帶參數。

靜態INCLUDE用<%@include file=included.htm %>實現,不會檢查所含文件的變化,適用于包含靜態頁面。

25、JSP 和Servlet 有哪些相同點和不同點,他們之間的聯系是什么?

答:JSP是Servlet技術的擴展,本質上還是Servlet。JSP側重于表現層,Servlet主要用于控制邏輯。

26、MVC 是什么?各個部分都有那些技術來實現?

答:MVC是Model-View-Controller的簡寫。

Model代表的是應用的業務邏輯(通過JavaBean,EJB組件實現)

View是應用的表示面(由JSP頁面產生)

Controller是提供應用的處理過程控制(一般是一個Servlet)

通過這種設計模型把應用邏輯,處理過程和顯示邏輯分成不同的組件實現。這些組件可以進行交互和重用。

27、JDBC 中的PreparedStatement 相比Statement 的好處?

答:PreparedStatement 會緩存指令,所以性能比Statement高。PreparedStatement在預編譯的時候過濾了特殊字符串,所以會防止SQL注入。

28、數據庫三范式是什么?

答:第一范式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。

第二范式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些字段決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴于任意一組候選關鍵字。

第三范式(3NF):在第二范式的基礎上,數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三范式。所謂傳遞函數依賴,指的是如果存在"A → B → C"的決定關系,則C傳遞函數依賴于A。因此,滿足第三范式的數據庫表應該不存在如下依賴關系: 關鍵字段 → 非關鍵字段x → 非關鍵字段y

29、什么是主鍵?什么是外鍵?

答:主鍵是表里的(一個或多個)字段,只用來定義表格里的行;主鍵里的值總是唯一的。外鍵是一個用來建立兩個表格之間關系的約束。這種關系一般都涉及一個表格里的主鍵字段與另外一個表(可能是同一表)里的字段。那么這些相連的字段就是外鍵。

30、什么是數據庫事務?事務有哪些特性?簡述事務的隔離級別?

答:事務是是一系列的數據庫操作,是數據庫應用的基本邏輯單位。

事務有原子性、一致性、隔離性、持久性。

-- 原子性。即不可分割性,事務要么全部被執行,要么就全部不被執行。

-- 隔離性。在事務正確提交之前,不允許把該事務對數據的任何改變提供給任何其他事務。

-- 持久性。事務正確提交后,其結果將永久保存在數據庫中,即使在事務提交后有了其他故障,事務的處理結果也會得到保存。

事務的隔離級別:讀未提交(Read Uncommitted):可以發生臟讀、不可重復讀和幻讀;讀提交(Read Committed):不可以發生臟讀可以發生不可重復讀和幻讀;可重復讀取(Repeatable Read):不可以發生臟讀和不可重復讀,可以發生幻讀;序列化(Serializable):不可以發生臟讀、不可重復讀和幻讀。

-- 臟讀:臟讀又稱無效數據的讀出,是指在數據庫訪問中,事務T1將某一值修改,然后事務T2讀取該值,此后T1因為某種原因撤銷對該值的修改,這就導致了T2所讀取到的數據是無效的。

事務一 事務二

/* Query 1 /
SELECT age FROM users WHERE id = 1;
/
will read 20 /
/
Query 2 /
UPDATE users SET age = 21 WHERE id = 1;
/
No commit here /
/
Query 1 /
SELECT age FROM users WHERE id = 1;
/
will read 21 */

ROLLBACK;
-- 不可重復讀:是指在數據庫訪問中,一個事務范圍內兩個相同的查詢卻返回了不同數據。這是由于查詢時系統中其他事務修改的提交而引起的。比如事務T1讀取某一數據,事務T2讀取并修改了該數據,T1為了對讀取值進行檢驗而再次讀取該數據,便得到了不同的結果。

事務一 事務二
/* Query 1 */
SELECT * FROM users WHERE id = 1;

/* Query 2 /
UPDATE users SET age = 21 WHERE id = 1;
COMMIT;
/
Query 1 */
SELECT * FROM users WHERE id = 1;
COMMIT;

-- 幻讀:幻讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,比如這種修改涉及到表中的“全部數據行”。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入“一行新數據”。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。

事務一 事務二
/* Query 1 */
SELECT * FROM users;

/* Query 2 /
INSERT INTO users VALUES ( 3, 'Bob', 27 );
COMMIT;
/
Query 1 */
SELECT * FROM users;

31、HashMap的實現原理?

答:在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。

HashMap是基于hashing的原理,我們使用put(key, value)存儲對象到HashMap中,使用get(key)從HashMap中獲取對象。當我們給put()方法傳遞鍵和值時,我們先對鍵調用hashCode()方法,返回的hashCode用于找到數組中的位置來儲存Entry對象。當對象的hashcode相同時,它們在數組中的位置相同,“碰撞”會發生。因為HashMap使用線性鏈表存儲對象,這個Entry會存儲在線性鏈表中。將會調用key的eqauls()方法比較決定是采用覆蓋行為(返回 true),還是產生 Entry 鏈(返回 false),新加入的放在鏈頭,最先加入的放在鏈尾。

32、HashMap與HashTable的區別?

答:HashMap可以接受null鍵值和值,而Hashtable則不能。
Hashtable是線程安全的,通過synchronized實現線程同步。而HashMap是非線程安全的,但是速度比Hashtable快。

33、ArrayList與LinkedList的區別?

答:兩者都實現的是List接口,不同之處在于:

-- ArrayList是基于動態數組實現的,LinkedList是基于鏈表的數據結構。

-- get訪問List內部任意元素時,ArrayList的性能要比LinkedList性能好。LinkedList中的get方法是要按照順序從列表的一端開始檢查,直到另一端

-- 對于新增和刪除操作LinkedList要強于ArrayList,因為ArrayList要移動數據

附加:
LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:

List list = Collections.synchronizedList(new LinkedList(…));
34、如果HashMap的大小超過了負載因子(load factor)定義的容量,怎么辦?

答:HashMap默認的負載因子大小為0.75,也就是說,當一個map填滿了75%的空間的時候,和其它集合類(如ArrayList等)一樣,將會創建原來HashMap大小的兩倍的數組,來重新調整map的大小,并將原來的對象放入新的數組中。這個過程叫作rehashing,因為它調用hash方法找到新的bucket位置。

35、ConcurrentHashMap和Hashtable的區別?

答:它們都可以用于多線程的環境,但是當Hashtable的大小增加到一定的時候,性能會急劇下降,因為迭代時需要被鎖定很長的時間。因為ConcurrentHashMap引入了分割(segmentation),不論它變得多么大,僅僅需要鎖定map的某個部分,而其它的線程不需要等到迭代完成才能訪問map。簡而言之,在迭代的過程中,ConcurrentHashMap僅僅鎖定map的某個部分,而Hashtable則會鎖定整個map。

36、Collection 和 Collections的區別?

答:Collection是集合類的上級接口,繼承與他的接口主要有Set 和List.

Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作。

37、簡單描述java集合類?

答:java集合類都繼承于Collection接口,主要有三種:List、Set和Map。

-- List有子類LinkedList、ArrayList和Vector

ArrayList: 元素單個,效率高,多用于查詢 。

Vector: 元素單個,線程安全,多用于查詢。

LinkedList: 元素單個,多用于插入和刪除

-- Set有子類HashSet、SortedSet和TreeSet

-- Map有子類HashMap、HashTable、LinkedHashMap和WeakHashMap

HashMap: 元素成對,元素可為空。

HashTable: 元素成對,線程安全,元素不可為空。

LinkedHashMap:它保留插入的順序,如果需要輸出的順序和輸入時的相同,那么就選用LinkedHashMap。

WeakHashMap: 是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被。

38、當一個線程進入一個對象的一個synchronized方法后,其它線程是否可進入此對象的其它方法?

答:分幾種情況:

-- 其他方法前是否加了synchronized關鍵字,如果沒加,則能。

-- 如果這個方法內部調用了wait,則可以進入其他synchronized方法。

-- 如果其他個方法都加了synchronized關鍵字,并且內部沒有調用wait,則不能。

39、sleep() 和 wait() 有什么區別?

答:sleep就是當前線程主動讓出cpu,cpu去執行其他線程,在sleep指定的時間過后,cpu才會回到這個線程上繼續往下執行,如果當前線程進入了同步鎖,sleep方法并不會釋放鎖,即使當前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執行。

wait是指在一個已經進入了同步鎖的線程內,讓自己讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖并運行,只有其他線程調用了notify方法(notify并不釋放鎖,只是處于wait狀態的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在當前線程中,如果notify方法后面的代碼還有很多,需要這些代碼執行完后才會釋放鎖),值得注意的是,notify方法只是隨機通知一個wait狀態的線程,notifyAll方法可以通知所有wait該鎖的線程。

例子:

運行結果:

enter thread1...

thread1 is waiting

enter thread2...

thread2 is waiting

enter thread3...

thread2 notify other thread can release wait status..

thread3 is sleeping ten millisecond...

thread3 is going on...

thread3 is being over!

thread1 is going on...

thread1 is being over!

如果調用的是notify,則結果如上,thread1執行完畢,thread2一直被掛著。

40、Java中的volatile 變量是什么?

答:volatile是一個特殊的修飾符,只有成員變量才能使用它。在Java并發程序缺少同步類的情況下,多線程對成員變量的操作對其它線程是透明的。volatile變量可以保證下一個讀取操作會在前一個寫操作之后發生。

41、 什么是線程安全?Vector是一個線程安全類嗎?

答:如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的情況下也不會出現計算失誤。很顯然你可以將集合類分成兩組,線程安全和非線程安全的。Vector 是用同步方法來實現線程安全的, 而和它相似的ArrayList不是線程安全的。

42、什么是ThreadLocal變量?

答:ThreadLocal用于創建線程的本地變量,我們知道一個對象的所有線程會共享它的全局變量,所以這些變量不是線程安全的,我們可以使用同步技術。但是當我們不想使用同步的時候,我們可以選擇ThreadLocal變量。每個線程都會擁有他們自己的Thread變量,它們可以使用get()\set()方法去獲取他們的默認值或者在線程內部改變他們的值。

43、 Java中interrupted 和 isInterruptedd方法的區別?

答:interrupted() 和 isInterrupted()的主要區別是前者會將中斷狀態清除而后者不會。Java多線程的中斷機制是用內部標識來實現的,調用Thread.interrupt()來中斷一個線程就會設置中斷標識為true。當中斷線程調用靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。而非靜態方法isInterrupted()用來查詢其它線程的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何拋出InterruptedException異常的方法都會將中斷狀態清零。無論如何,一個線程的中斷狀態有有可能被其它線程調用中斷來改變。

44、什么是線程池? 為什么要使用它?

答:創建線程要花費昂貴的資源和時間,如果任務來了才創建線程那么響應時間會變長,而且一個進程能創建的線程數有限。為了避免這些問題,在程序啟動的時候就創建若干線程來響應處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創建不同的線程池。比如單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合很多生存期短的任務的程序的可擴展線程池)。

45、有三個線程T1,T2,T3,怎么確保它們按順序執行?

答:在多線程中有多種方法讓線程按特定順序執行,你可以用線程類的join()方法在一個線程中啟動另一個線程,另外一個線程完成該線程繼續執行。為了確保三個線程的順序你應該先啟動最后一個(T3調用T2,T2調用T1),這樣T1就會先完成而T3最后完成。

46、什么是服務端包含(Server Side Include)?

答:服務端包含(SSI)是一種簡單的解釋型服務端腳本語言,大多數時候僅用在Web上,用servlet標簽嵌入進來。SSI最常用的場景把一個或多個文件包含到Web服務器的一個Web頁面中。當瀏覽器訪問Web頁面的時候,Web服務器會用對應的servlet產生的文本來替換Web頁面中的servlet標簽。

47、HTTP響應的結構是怎么樣的?

答:HTTP響應由三個部分組成:

狀態碼(Status Code):描述了響應的狀態??梢杂脕頇z查是否成功的完成了請求。請求失敗的情況下,狀態碼可用來找出失敗的原因。如果Servlet沒有返回狀態碼,默認會返回成功的狀態碼HttpServletResponse.SC_OK。

HTTP頭部(HTTP Header):它們包含了更多關于響應的信息。比如:頭部可以指定認為響應過期的過期日期,或者是指定用來給用戶安全的傳輸實體內容的編碼格式。

主體(Body):它包含了響應的內容。它可以包含HTML代碼,圖片,等等。主體是由傳輸在HTTP消息中緊跟在頭部后面的數據字節組成的。

48、什么是cookie?session和cookie有什么區別?

答:cookie是Web服務器發送給瀏覽器的一塊信息。瀏覽器會在本地文件中給每一個Web服務器存儲cookie。以后瀏覽器在給特定的Web服務器發請求的時候,同時會發送所有為該服務器存儲的cookie。下面列出了session和cookie的區別:

無論客戶端瀏覽器做怎么樣的設置,session都應該能正常工作。客戶端可以選擇禁用cookie,但是,session仍然是能夠工作的,因為客戶端無法禁用服務端的session。

在存儲的數據量方面session和cookies也是不一樣的。session能夠存儲任意的Java對象,cookie只能存儲String類型的對象。

49、使用Spring框架的好處是什么?

答:輕量:Spring 是輕量的,基本的版本大約2MB。

控制反轉:Spring通過控制反轉實現了松散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。

面向切面的編程(AOP):Spring支持面向切面的編程,并且把應用業務邏輯和系統服務分開。

容器:Spring 包含并管理應用中對象的生命周期和配置。

MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。

事務管理:Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)。

異常處理:Spring 提供方便的API把具體技術相關的異常(比如由JDBC,Hibernate or JDO拋出的)轉化為一致的unchecked 異常。

50、解釋Spring框架中bean的生命周期?

答:-- Spring容器 從XML 文件中讀取bean的定義,并實例化bean。

-- Spring根據bean的定義填充所有的屬性。

-- 如果bean實現了BeanNameAware 接口,Spring 傳遞bean 的ID 到 setBeanName方法。

-- 如果Bean 實現了 BeanFactoryAware 接口, Spring傳遞beanfactory 給setBeanFactory 方法。

-- 如果有任何與bean相關聯的BeanPostProcessors,Spring會在postProcesserBeforeInitialization()方法內調用它們。

-- 如果bean實現IntializingBean了,調用它的afterPropertySet方法,如果bean聲明了初始化方法,調用此初始化方法。

-- 如果有BeanPostProcessors 和bean 關聯,這些bean的postProcessAfterInitialization() 方法將被調用。

-- 如果bean實現了 DisposableBean,它將調用destroy()方法。

51、Spring框架的事務管理有哪些優點?

答:-- 它為不同的事務API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一個不變的編程模式。

-- 它為編程式事務管理提供了一套簡單的API而不是一些復雜的事務API如

-- 它支持聲明式事務管理。

-- 它和Spring各種數據訪問抽象層很好得集成。

52、Spring MVC工作機制?

答: 1.spring mvc請所有的請求都提交給DispatcherServlet,它會委托應用系統的其他模塊負責負責對請求進行真正的處理工作。 2.DispatcherServlet查詢一個或多個HandlerMapping,找到處理請求的Controller. 3.DispatcherServlet請請求提交到目標Controller 4.Controller進行業務邏輯處理后,會返回一個ModelAndView 5.Dispathcher查詢一個或多個ViewResolver視圖解析器,找到ModelAndView對象指定的視圖對象 6.視圖對象負責渲染返回給客戶端。

53、Hibernate的一級緩存與二級緩存的區別?

答:一級緩存就是Session級別的緩存,一個Session做了一個查詢操作,它會把這個操作的結果放在一級緩存中,如果短時間內這個session(一定要同一個session)又做了同一個操作,那么hibernate直接從一級緩存中拿,而不會再去連數據庫,取數據。二級緩存就是SessionFactory級別的緩存,顧名思義,就是查詢的時候會把查詢結果緩存到二級緩存中,如果同一個sessionFactory創建的某個session執行了相同的操作,hibernate就會從二級緩存中拿結果,而不會再去連接數據庫。

54、Spring框架中的單例Beans是線程安全的么?

答:Spring框架并沒有對單例bean進行任何多線程的封裝處理。關于單例bean的線程安全和并發問題需要開發者自行去搞定。但實際上,大部分的Spring bean并沒有可變的狀態(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀態的話(比如 View Model 對象),就需要自行保證線程安全。

55、Spring事務是如何傳播的?

答:1) PROPAGATION_REQUIRED ,默認的spring事務傳播級別,使用該級別的特點是,如果上下文中已經存在事務,那么就加入到事務中執行,如果當前上下文中不存在事務,則新建事務執行。所以這個級別通常能滿足處理大多數的業務場景。

2)PROPAGATION_SUPPORTS ,從字面意思就知道,supports,支持,該傳播級別的特點是,如果上下文存在事務,則支持事務加入事務,如果沒有事務,則使用非事務的方式執行。所以說,并非所有的包在transactionTemplate.execute中的代碼都會有事務支持。這個通常是用來處理那些并非原子性的非核心業務邏輯操作。應用場景較少。

3)PROPAGATION_MANDATORY , 該級別的事務要求上下文中必須要存在事務,否則就會拋出異常!配置該方式的傳播級別是有效的控制上下文調用代碼遺漏添加事務控制的保證手段。比如一段代碼不能單獨被調用執行,但是一旦被調用,就必須有事務包含的情況,就可以使用這個傳播級別。

4)PROPAGATION_REQUIRES_NEW ,從字面即可知道,new,每次都要一個新事務,該傳播級別的特點是,每次都會新建一個事務,并且同時將上下文中的事務掛起,執行當前新建事務完成以后,上下文事務恢復再執行。

這是一個很有用的傳播級別,舉一個應用場景:現在有一個發送100個紅包的操作,在發送之前,要做一些系統的初始化、驗證、數據記錄操作,然后發送100封紅包,然后再記錄發送日志,發送日志要求100%的準確,如果日志不準確,那么整個父事務邏輯需要回滾。
怎么處理整個業務需求呢?就是通過這個PROPAGATION_REQUIRES_NEW 級別的事務傳播控制就可以完成。發送紅包的子事務不會直接影響到父事務的提交和回滾。

5)PROPAGATION_NOT_SUPPORTED ,這個也可以從字面得知,not supported ,不支持,當前級別的特點就是上下文中存在事務,則掛起事務,執行當前邏輯,結束后恢復上下文的事務。

這個級別有什么好處?可以幫助你將事務極可能的縮小。我們知道一個事務越大,它存在的風險也就越多。所以在處理事務的過程中,要保證盡可能的縮小范圍。比如一段代碼,是每次邏輯操作都必須調用的,比如循環1000次的某個非核心業務邏輯操作。這樣的代碼如果包在事務中,勢必造成事務太大,導致出現一些難以考慮周全的異常情況。所以這個事務這個級別的傳播級別就派上用場了。用當前級別的事務模板抱起來就可以了。

6)PROPAGATION_NEVER ,該事務更嚴格,上面一個事務傳播級別只是不支持而已,有事務就掛起,而PROPAGATION_NEVER傳播級別要求上下文中不能存在事務,一旦有事務,就拋出runtime異常,強制停止執行!這個級別上輩子跟事務有仇。

7)PROPAGATION_NESTED ,字面也可知道,nested,嵌套級別事務。該傳播級別特征是,如果上下文中存在事務,則嵌套事務執行,如果不存在事務,則新建事務。

56、Spring AOP實現原理?

答:java動態代理。接下來描述動態代理(考生自由發揮)。

57、Spring是如何管理事務的?

答:Spring既支持編程式事務管理(也稱編碼式事務),也支持聲明式的事務管理

-- 編程式事務管理:將事務管理代碼嵌入到業務方法中來控制事務的提交和回滾,在編程式事務中,必須在每個業務操作中包含額外的事務管理代碼。

-- 聲明式事務管理建立在AOP之上的。其本質是對方法前后進行攔截,然后在目標方法開始之前創建或者加入一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。聲明式事務最大的優點就是不需要通過編程的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明(或通過基于@Transactional注解的方式),便可以將事務規則應用到業務邏輯中。顯然聲明式事務管理要優于編程式事務管理,這正是spring倡導的非侵入式的開發方式。聲明式事務管理使業務代碼不受污染,一個普通的POJO對象,只要加上注解就可以獲得完全的事務支持。和編程式事務相比,聲明式事務唯一不足地方是,后者的最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進行事務管理的代碼塊獨立為方法等等。

聲明式事務管理也有兩種常用的方式,一種是基于tx和aop名字空間的xml配置文件,另一種就是基于@Transactional注解。顯然基于注解的方式更簡單易用,更清爽。

@Transactional屬性

屬性 類型 描述
value String 可選的限定描述符,指定使用的事務管理器
propagation enum: Propagation 可選的事務傳播行為設置
isolation enum: Isolation 可選的事務隔離級別設置
readOnly boolean 讀寫或只讀事務,默認讀寫
timeout int (in seconds granularity) 事務超時時間設置
rollbackFor Class對象數組,必須繼承自Throwable 導致事務回滾的異常類數組
rollbackForClassName 類名數組,必須繼承自Throwable 導致事務回滾的異常類名字數組
noRollbackFor Class對象數組,必須繼承自Throwable 不會導致事務回滾的異常類數組
noRollbackForClassName 類名數組,必須繼承自Throwable 不會導致事務回滾的異常類名字數組

58、Spring MVC的工作原理?

答:

客戶端請求提交到DispatcherServlet

由DispatcherServlet控制器查詢一個或多個HandlerMapping,找到處理請求的Controller

DispatcherServlet將請求提交到Controller

Controller調用業務邏輯處理后,返回ModelAndView

DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖

視圖負責將結果顯示到客戶端

59、Spring MVC與Struts有什么區別?

答:

  1. 機制:spring mvc的入口是servlet,而struts2是filter,這樣就導致了二者的機制不同。

  2. 性能:spring會稍微比struts快。spring mvc是基于方法的設計,而sturts是基于類,每次發一次請求都會實例一個action,每個action都會被注入屬性,而spring基于方法,粒度更細,但要小心把握像在servlet控制數據一樣。spring3 mvc是方法級別的攔截,攔截到方法后根據參數上的注解,把request數據注入進去,在spring3 mvc中,一個方法對應一個request上下文。而struts2框架是類級別的攔截,每次來了請求就創建一個Action,然后調用setter getter方法把request中的數據注入;struts2實際上是通 setter getter方法與request打交道的;struts2中,一個Action對象對應一個request上下文。

  3. 參數傳遞:struts是在接受參數的時候,可以用屬性來接受參數,這就說明參數是讓多個方法共享的。

  4. 設計思想上:struts更加符合oop(面向對象編程)的編程思想, spring就比較謹慎,在servlet上擴展。

  5. intercepter的實現機制:struts有自己的interceptor機制,spring mvc用的是獨立的AOP方式。這樣導致struts的配置文件量還是比spring mvc大,雖然struts的配置能繼承,所以我覺得論使用上來講,spring mvc使用更加簡潔,開發效率Spring MVC確實比struts2高。spring mvc是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從架構本身上spring3 mvc就容易實現restful url。struts2是類級別的攔截,一個類對應一個request上下文;實現restful url要費勁,因為struts2 action的一個方法可以對應一個url;而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標識其所屬方法了。spring3 mvc的方法之間基本上獨立的,獨享request response數據,請求數據通過參數獲取,處理結果通過ModelMap交回給框架方法之間不共享變量,而struts2搞的就比較亂,雖然方法之間也是獨立的,但其所有Action變量是共享的,這不會影響程序運行,卻給我們編碼,讀程序時帶來麻煩。

  6. 另外,spring3 mvc的驗證也是一個亮點,支持JSR303,處理ajax的請求更是方便,只需一個注解@ResponseBody ,然后直接返回響應文本即可。

60、簡單描述Spring的啟動過程?

答:

首先,對于一個web應用,其部署在web容器中,web容器提供其一個全局的上下文環境,這個上下文就是ServletContext,其為后面的spring IoC容器提供宿主環境;

其次,在web.xml中會提供有contextLoaderListener。在web容器啟動時,會觸發容器初始化事件,此時contextLoaderListener會監聽到這個事件,其contextInitialized方法會被調用,在這個方法中,spring會初始化一個啟動上下文,這個上下文被稱為根上下文,即WebApplicationContext,這是一個接口類,確切的說,其實際的實現類是XmlWebApplicationContext。這個就是spring的IoC容器,其對應的Bean定義的配置由web.xml中的context-param標簽指定。在這個IoC容器初始化完畢后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為屬性Key,將其存儲到ServletContext中,便于獲?。?/p>

再次,contextLoaderListener監聽器初始化完畢后,開始初始化web.xml中配置的Servlet,這個servlet可以配置多個,以最常見的DispatcherServlet為例,這個servlet實際上是一個標準的前端控制器,用以轉發、匹配、處理每個servlet請求。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文,用以持有spring mvc相關的bean。在建立DispatcherServlet自己的IoC上下文時,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文。有了這個parent上下文之后,再初始化自己持有的上下文。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化處理器映射、視圖解析等。這個servlet自己持有的上下文默認實現類也是mlWebApplicationContext。初始化完畢后,spring以與servlet的名字相關(此處不是簡單的以servlet名為Key,而是通過一些轉換,具體可自行查看源碼)的屬性為屬性Key,也將其存到ServletContext中,以便后續使用。這樣每個servlet就持有自己的上下文,即擁有自己獨立的bean空間,同時各個servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定義的那些bean。

61、Mybatis中#與$的區別?

答:1. #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號,類似于PreparedStatmte的動態綁定參數。

  1. $將傳入的數據直接顯示生成在sql中,類似于直接拼SQL。

  2. #方式能夠很大程度防止sql注入。

4.$方式無法防止Sql注入。

5.$方式一般用于傳入數據庫對象,例如傳入表名。

6.一般能用#的就別用$。

62、簡單描述Mybatis緩存?

答:mybaits提供一級緩存,和二級緩存。

-- 一級緩存是SqlSession級別的緩存。在操作數據庫時需要構造 sqlSession對象,在對象中有一個(內存區域)數據結構(HashMap)用于存儲緩存數據。不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。一級緩存的作用域是同一個SqlSession,在同一個sqlSession中兩次執行相同的sql語句,第一次執行完畢會將數據庫中查詢的數據寫到緩存(內存),第二次會從緩存中獲取數據將不再從數據庫查詢,從而提高查詢效率。當一個sqlSession結束后該sqlSession中的一級緩存也就不存在了。Mybatis默認開啟一級緩存。

-- 二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession去操作數據庫得到數據會存在二級緩存區域,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的,是多個SqlSession共享的,其作用域是mapper的同一個namespace,不同的sqlSession兩次執行相同namespace下的sql語句且向sql中傳遞參數也相同即最終執行相同的sql語句,第一次執行完畢會將數據庫中查詢的數據寫到緩存(內存),第二次會從緩存中獲取數據將不再從數據庫查詢,從而提高查詢效率。Mybatis默認沒有開啟二級緩存需要在setting全局參數中配置開啟二級緩存。

63、使用Mybatis的好處?

答:mybatis把sql語句從Java源程序中獨立出來,放在單獨的XML文件中編寫,給程序的維護帶來了很大便利。mybatis封裝了底層JDBC API的調用細節,并能自動將結果集轉換成Java Bean對象,大大簡化了Java數據庫編程的重復工作。因為mybatis需要程序員自己去編寫sql語句,程序員可以結合數據庫自身的特點靈活控制sql語句,因此能夠實現比hibernate等全自動orm框架更高的查詢效率,能夠完成復雜查詢。

64、Mybatis是如何與java bean進行映射的?

答:使用resultMap關鍵字映射數據庫字段和java字段。比如:

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

type關鍵字為對應的java bean的路徑,使用result把具體的字段綁定到java bean中。

65、Mybatis中如何實現一對一、一對多的?

答:“關聯”(association)實現一對一的關系,“集合”(collection)實現一對多的關系。

66、MySQL都有哪些存儲引擎,有什么區別?

答:主要存儲引擎:MyISAM、InnoDB、MEMORY和MERGE,MySQL5.5以后默認使用InnoDB存儲引擎。

-- MyISAM不支持事務、也不支持外鍵,但其訪問速度快,對事務完整性沒有要求。

-- InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全。但是比起MyISAM存儲引擎,InnoDB寫的處理效率差一些并且會占用更多的磁盤空間以保留數據和索引。

-- MEMORY存儲引擎使用存在內存中的內容來創建表。每個MEMORY表只實際對應一個磁盤文件。MEMORY類型的表訪問非常得快,因為它的數據是放在內存中的,并且默認使用HASH索引。但是一旦服務關閉,表中的數據就會丟失掉。

-- MERGE存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結構完全相同。MERGE表本身沒有數據,對MERGE類型的表進行查詢、更新、刪除的操作,就是對內部的MyISAM表進行的。

67、說說常見的數據庫優化?

答:1>創建索引,建索引的字段應滿足以下條件:

    -- 字段出現在查詢條件中,并且查詢條件可以使用索引;

    -- 語句執行頻率高,一天會有幾千次以上;

    -- 通過字段條件可篩選的記錄集很小;

2>使用分頁

3>只返回必要字段以減少數據在網絡上傳輸開銷

4>使用BATCH操作,減少交互的次數

5>加大fetch_size,這樣可以減少結果數據傳輸的交互次數及服務器數據準備時間,提高性能。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,740評論 18 399
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,341評論 11 349
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • 飛機上閑來無事讀了向死而生,一本講述李開復先生是怎么在人生最灰暗的時候戰勝病魔的書。 這本書很容易讀,比較感觸的就...
    Ostrom閱讀 575評論 1 0
  • 在聽到《七月與安生》被拍成電影的時候,我帶著一絲期待,卻又有一些不舒服。 或許是改編出來的電影太過粗糙,甚至讓準備...
    Simple李閱讀 593評論 0 2