面試題

Java SE

Finally
finally 語句塊在 try 語句塊中的 return 語句之前執行
finally 語句塊在 catch 語句塊中的 return 語句之前執行

serializable
把該字節序列保存起來(例如:保存在一個文件裏),以後可以隨時將該字節序列恢復爲原來的對象。甚至可以將該字節序列放到其他計算機上或者通過網絡傳輸到其他計算機上恢復,只要該計算機平臺存在相應的類就可以正常恢復爲原來的對象。
實現:要序列化一個對象,先要創建某些OutputStream對象,然後將其封裝在一個ObjectOutputStream對象內,再調用writeObject()方法即可序列化一個對象;反序列化也類似。

object類中有什麼方法?
Equals,getClass,hashCode,wait(有三個),notify,notifyall,toString

String,StringBuffer, StringBuilder 的區別是什麼?String爲什麼是不可變的?
答:
1、String是字符串常量,StringBuffer和StringBuilder都是字符串變量。後兩者的字符內容可變,而前者創建後內容不可變。
2、String不可變是因爲在JDK中String類被聲明爲一個final類。
3、StringBuffer是線程安全的,而StringBuilder是非線程安全的。
ps:線程安全會帶來額外的系統開銷,所以StringBuilder的效率比StringBuffer高。如果對系統中的線程是否安全很掌握,可用StringBuffer,在線程不安全處加上關鍵字Synchronize。

接口和抽象類的區別
1.語法層面上的區別
  1)抽象類可以提供成員方法的實現細節,而接口中只能存在public abstract 方法;
  2)抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的;
  3)接口中不能含有靜態代碼塊以及靜態方法,而抽象類可以有靜態代碼塊和靜態方法;
  4)一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
2.設計層面上的區別
  1)抽象類是對一種事物的抽象,即對類抽象,而接口是對行爲的抽象。抽象類是對整個類整體進行抽象,包括屬性、行爲,但是接口卻是對類局部(行爲)進行抽象。舉個簡單的例子,飛機和鳥是不同類的事物,但是它們都有一個共性,就是都會飛。那麼在設計的時候,可以將飛機設計爲一個類Airplane,將鳥設計爲一個類Bird,但是不能將 飛行 這個特性也設計爲類,因此它只是一個行爲特性,並不是對一類事物的抽象描述。此時可以將 飛行 設計爲一個接口Fly,包含方法fly( ),然後Airplane和Bird分別根據自己的需要實現Fly這個接口。然後至於有不同種類的飛機,比如戰鬥機、民用飛機等直接繼承Airplane即可,對於鳥也是類似的,不同種類的鳥直接繼承Bird類即可。從這裏可以看出,繼承是一個 “是不是”的關係,而 接口 實現則是 “有沒有”的關係。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而接口實現則是有沒有、具備不具備的關係,比如鳥是否能飛(或者是否具備飛行這個特點),能飛行則可以實現這個接口,不能飛行就不實現這個接口。

2)設計層面不同,抽象類作爲很多子類的父類,它是一種模板式設計。而接口是一種行爲規範,它是一種輻射式設計。什麼是模板式設計?最簡單例子,大家都用過ppt裏面的模板,如果用模板A設計了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它們的公共部分需要改動,則只需要改動模板A就可以了,不需要重新對ppt B和ppt C進行改動。而輻射式設計,比如某個電梯都裝了某種報警器,一旦要更新報警器,就必須全部更新。也就是說對於抽象類,如果需要添加新的方法,可以直接在抽象類中添加具體的實現,子類可以不進行變更;而對於接口則不行,如果接口進行了變更,則所有實現這個接口的類都必須進行相應的改動。

socket編程相關,如果服務器這邊調用write寫了100個字節的數據,客戶端想要獲得這個數據,是直接用read系統調用,參數也是100嗎?

容器
1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因爲LinkedList要移動指針。
3.對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據。

Hashmap,hashtable,hashset
第一,繼承不同。
public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map
第二
Hashtable 中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。在多線程併發的環境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。
第三
Hashtable中,key和value都不允許出現null值。
在HashMap中,null可以作爲鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值爲null。當get()方法返回null值時,即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應的值爲null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。
第四,兩個遍歷方式的內部實現上不同。
Hashtable、HashMap都使用了 Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。
第五
哈希值的使用不同,HashTable直接使用對象的hashCode。而HashMap重新計算hash值。
第六
Hashtable和HashMap它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTable中hash數組默認大小是11,增加的方式是 old*2+1。HashMap中hash數組的默認大小是16,而且一定是2的指數,增加方式是翻倍

modCount是用來實現fail-fast機制的
fail-fast解決辦法
方案一:在遍歷過程中所有涉及到改變modCount值得地方全部加上synchronized或者直接使用Collections.synchronizedList,這樣就可以解決。但是不推薦,因爲增刪造成的同步鎖可能會阻塞遍歷操作。
方案二:使用CopyOnWriteArrayList來替換ArrayList。推薦使用該方案。
CopyOnWriteArrayList爲何物?ArrayList 的一個線程安全的變體,其中所有可變操作(add、set 等等)都是通過對底層數組進行一次新的複製來實現的。 該類產生的開銷比較大,但是在兩種情況下,它非常適合使用。1:在不能或不想進行同步遍歷,但又需要從併發線程中排除衝突時。2:當遍歷操作的數量大大超過可變操作的數量時。遇到這兩種情況使用CopyOnWriteArrayList來替代ArrayList再適合不過了。那麼爲什麼CopyOnWriterArrayList可以替代ArrayList呢?
第一、CopyOnWriterArrayList的無論是從數據結構、定義都和ArrayList一樣。它和ArrayList一樣,同樣是實現List接口,底層使用數組實現。在方法上也包含add、remove、clear、iterator等方法。
第二、CopyOnWriterArrayList根本就不會產生ConcurrentModificationException異常,也就是它使用迭代器完全不會產生fail-fast機制

java web

Spring MVC的工作原理是怎樣的?
答:Spring MVC的工作原理如下圖所示:

① 客戶端的所有請求都交給前端控制器DispatcherServlet來處理,它會負責調用系統的其他模塊來真正處理用戶的請求。
② DispatcherServlet收到請求後,將根據請求的信息(包括URL、HTTP協議方法、請求頭、請求參數、Cookie等)以及HandlerMapping的配置找到處理該請求的Handler(任何一個對象都可以作爲請求的Handler)。
③在這個地方Spring會通過HandlerAdapter對該處理器進行封裝。
④ HandlerAdapter是一個適配器,它用統一的接口對各種Handler中的方法進行調用。
⑤ Handler完成對用戶請求的處理後,會返回一個ModelAndView對象給DispatcherServlet,ModelAndView顧名思義,包含了數據模型以及相應的視圖的信息。
⑥ ModelAndView的視圖是邏輯視圖,DispatcherServlet還要藉助ViewResolver完成從邏輯視圖到真實視圖對象的解析工作。
⑦ 當得到真正的視圖對象後,DispatcherServlet會利用視圖對象對模型數據進行渲染。
⑧ 客戶端得到響應,可能是一個普通的HTML頁面,也可以是XML或JSON字符串,還可以是一張圖片或者一個PDF文件。

servlet線程安全
要根據servlet具體的實現來看,
如果存在全局變量,則是不安全,如果是局部變量,多線程間不存在數據共享,就是安全的。
不安全可以通過:將全局變量改爲局部變量,或者使用同步,或實現 SingleThreadModel 接口該接口指定了系統如何處理對同一個Servlet的調用。如果一個Servlet被這個接口指定,那麼在這個Servlet中的service方法將不會有兩個線程被同時執行,當然也就不存在線程安全的問題。

ssh 框架
我開始按自己的理解按Hibernate、Struts、Spring的順序開始講,Hibernate講到它的使用原理及與iBATIS的對比,順便說了下現在似乎大家更傾向於使用iBATIS、myBATIS這樣更加靈活的輕量級框架。struts講了下它的作用就是“將請求與視圖分開”,然後講述從輸入url到使用struts處理的控制流程(struts從tomcat那接管、action處理),然後也說struts現在似乎也不那麼傾向於使用因爲它有漏洞。最後重點講了下重頭戲Spring,詳細講述了它解耦的功能、AOP原理及自己有利用動態代理簡單模擬實現過一個簡單的AOP功能、IOC(DI)等。最後說,從web應用層面上看,Hibernate屬於持久層,struts屬於表示層,而Spring卻貫穿所有於所有層(表示層、業務層、持久層),Spring也有自己的MVC模塊、web模塊及JDBC和DAO模塊,只是很少使用,也就是隻用一個Spring也是完全可以的。

描述struts的工作流程
答: 1、在web應用啓動時,加載並初始化ActionServlet,ActionServlet從struts-config.xml文件中讀取配置信息,將它們存放到各個配置對象中。
2、當ActionServlet接收到一個客戶請求時,首先檢索和用戶請求相匹配的ActionMapping實例,如果不存在,就返回用戶請求路徑無效信息。
3、如果ActionForm實例不存在,就創建一個ActionForm對象,把客戶提交的表單數據保存到ActionForm對象中。
4、根據配置信息決定是否需要驗證表單,如果需要,就調用ActionForm的validate()方法,如果ActionForm的validate()方法返回null或返回一個不包含ActionMessage的ActionErrors對象,就表示表單驗證成功。
5、ActionServlet根據ActionMapping實例包含的映射信息決定請求轉發給哪個Action,如果相應的Action實例不存在,就先創建一個實例,然後調用Action的execute()方法。
6、Action的execute()方法返回一個ActionForward對象,ActionServlet再把客戶請求轉發給ActionForward對象指向的JSP組件。
7、ActionForward對象指向的JSP組件生成動態網頁,返回給客戶。
Jvm 虛擬機

描述一下JVM加載class文件的原理機制?
答:JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現的,Java中的類加載器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。
由於Java的跨平臺性,經過編譯的Java源程序並不是一個可執行程序,而是一個或多個類文件。當Java程序需要使用某個類時,JVM會確保這個類已經被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的.class文件中的數據讀入到內存中,通常是創建一個字節數組讀入.class文件,然後產生與所加載類對應的Class對象。加載完成後,Class對象還不完整,所以此時的類還不可用。當類被加載後就進入連接階段,這一階段包括驗證、準備(爲靜態變量分配內存並設置默認的初始值)和解析(將符號引用替換爲直接引用)三個步驟。最後JVM對類進行初始化,包括:1)如果類存在直接的父類並且這個類還沒有被初始化,那麼就先初始化父類;2)如果類中存在初始化語句,就依次執行這些初始化語句。

四種引用類型
⑴強引用(StrongReference)
強引用是使用最普遍的引用。如果一個對象具有強引用,那垃圾回收器絕不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題。 ps:強引用其實也就是我們平時A a = new A()這個意思。
⑵軟引用(SoftReference)
如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存
⑶弱引用(WeakReference)
WeakReference可以用來實現一些規範化映射(WeakHashMap),其中key或者value當它們不再被引用時可以自動被回收。當你想引用一個對象,但是這個對象有自己的生命週期,你不想介入這個對象的生命週期,這時候你就是用弱引用。這個引用不會在對象的垃圾回收判斷中產生任何附加的影響。
⑷虛引用(PhantomReference)
PlantomReference和WeakReference一樣,也不會介入引用對象的生命週期。PhantomReference用來調度一些預驗清理動作,提供比Java清理機制更靈活的處理方式。(Phantom references are for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.)PlantomReference比較特殊,它的get方法總是返回null,所以你得不到它引用的對象。它保存ReferenceQueue中的軌跡。它允許你知道對象何時從內存中移除。
Java內存模型

來由:1.高速處理器與低俗IO的矛盾2.
圍繞原子性,有序性,可見性

虛擬機運行數據區

• 程序計數器
是一塊較小的內存區域,存放記錄字節碼指令的地址(如果執行的是native方法,則爲空),此內存區域是唯一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。
• 虛擬機棧
存放是的棧元素是棧幀,棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。會拋出StackOverflowError異常和OutOfMemoryError異常。
• 本地方法棧
與虛擬機棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的 Native方法服務。有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一。的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一
• 堆
此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裏分配內存。會拋出OutOfMemoryError異常。
• 方法區
用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。這區域的內存回收目標主要是針對常量池的回收和對類型的卸載。拋出OutOfMemoryError異常。
o 運行時常量池
是方法區的一部分,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。一般來說,除了保存Class文件中描述的符號引用外,還會把翻譯出來的直接引用也存儲在運行時常量池中。
• 直接內存
並不是虛擬機運行時數據區的一部分,它可以使用Native函數庫直接分配堆外內存,然後通過一個存儲在Java堆中的DirectByteBuffer對象作爲這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因爲避免了在Java堆和Native堆中來回複製數據。
垃圾回收
三個問題
1.哪些內存需要回收?
2.什麼時候回收?
3.如何回收?

java的垃圾回收機制是Java虛擬機提供的能力,用於在空閒時間以不定時的方式動態回收無任何引用的對象佔據的內存空間。
需要注意的是:垃圾回收回收的是無任何引用的對象佔據的內存空間而不是對象本身,很多人來我公司面試時,我都會問這個問題的,70%以上的人回答的含義是回收對象,實際上這是不正確的。
System.gc()
Runtime.getRuntime().gc()
上面的方法調用時用於顯式通知JVM可以進行一次垃圾回收,但真正垃圾回收機制具體在什麼時間點開始發生動作這同樣是不可預料的,這和搶佔式的線程在發生作用時的原理一樣。

1.哪些內存需要回收?
程序計數器、虛擬機棧、本地方法棧3個區域隨線程而生,隨線程而滅;棧中的棧幀隨着方法的進入和退出而有條不紊地執行着出棧和入棧操作。每一個棧幀 中分配多少內存基本上是在類結構確定下來時就已知的,因此這幾個區域的內存分配和回收都具備確定性,在這幾個區域內就不需要過多考慮回收的問題,因爲方法 結束或者線程結束時,內存自然就跟隨着回收了。Java堆和方法區則不一樣,一個接口中的多個實現類需要的內存可能不一樣,一個方法中的多個分支需要的內存也可能不一樣,我們只有在程序處於運行期間時才能知道會創建哪些對象,這部分內存的分配和回收都是動態的,垃圾收集器所關注的是這部分內存。
2.什麼時候回收
回收Java堆
當對象死亡時,我們可以回收其所佔用的內存
對象死亡判定:
• 引用計數算法
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器爲0的對象就是不可能再被使用的。
侷限性是:不能解決循環引用的問題。
• 可達算法
基本思路就是通過一系列的稱爲”GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連(用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的。
GC Roots:
虛擬機棧(棧幀中的本地變量表)中引用的對象。
方法區中類靜態屬性引用的對象。
方法區中常量引用的對象。
本地方法棧中JNI(即一般說的Native方法)引用的對象。
回收方法區
廢棄常量和無用的類。
回收廢棄常量與回收Java堆中的對象非常類似,用引用來判定。
判定一個類是否是“無用的類”的條件則相對苛刻許多。類需要同時滿足下面3個條件才能算是“無用的類”:
1.該類所有的實例都已經被回收,也就是Java堆中不存在該類的任何實例。
2.加載該類的ClassLoader已經被回收。
3.該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。
3.如何回收?
垃圾收集算法
• 標記-清除
• 複製算法
• 標記-整理
• 分代收集
比較常用。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用複製算法,只需要付出少量存活對象的複製成本就可以完成收集。而老年代中因爲對象存活率高、沒有額外空間對它進行分配擔保,就必須使用“標記—清理”或者“標記—整理”算法來進行回收。
Hotspot的算法實現
如何去發起內存回收
• 枚舉根節點
• 安全點
• 安全區域
內存回收動作的執行者是實現了回收算法的垃圾收集器,通常虛擬機中往往不止有一種GC收集器。
按線程處理方式可分爲單線程,多線程收集器
按收集的內存區域可分爲新生代、老年代的收集器
最普遍的內存分配規則
1.對象優先在Eden分配
2.大對象直接進入老年代
3.長期存活的對象將進入老年代
4.動態對象年齡判定
5.空間分配擔保

伊甸園(Eden):這是對象最初誕生的區域,並且對大多數對象來說,這裏是它們唯一存在過的區域。
- 倖存者樂園(Survivor)兩個:從伊甸園倖存下來的對象會被挪到這裏。
- 終身頤養園(Tenured):這是足夠老的倖存對象的歸宿。年輕代收集(Minor-GC)過程是不會觸及這個地方的。當年輕代收集不能把對象放進終身頤養園時,就會觸發一次完全收集(Major-GC),這裏可能還會牽扯到壓縮,以便爲大對象騰出足夠的空間。
上述區域都是在heap區, Eden survivor屬於新生代,Tenured老年代

垃圾收集器
新生代串行收集器
它僅僅使用單線程進行垃圾回收;它獨佔式的垃圾回收。
老年代串行收集器
它也是一個串行的、獨佔式的垃圾回收器。由於老年代垃圾回收通常會使用比新生代垃圾回收更長的時間,
並行收集器
並行收集器是工作在新生代的垃圾收集器,它只簡單地將串行回收器多線程化。它的回收策略、算法以及參數和串行回收器一樣。
並行回收器也是獨佔式的回收器,在收集過程中,應用程序會全部暫停。但由於並行回收器使用多線程進行垃圾回收,因此,在併發能力比較強的 CPU 上,它產生的停頓時間要短於串行回收器,而在單 CPU 或者併發能力較弱的系統中,並行回收器的效果不會比串行回收器好,由於多線程的壓力,它的實際表現很可能比串行回收器差。
Serial收集器:單線程收集器,必須暫停其他所有的工作線程,默認client模式下新生代的收集器
ParNew收集器:Serial 的多線程版本,一般在Servr模式下的新生代首選收集器,除Serial外,目前只有它能與CMS收集器配合工作,ParNew收集器在單cpu的情況 下不會有比Serial收集器更好的效果,甚至由於存在線程交互的開銷,該收集器在通過超線程技術實現的兩個cpu的環境中都一定能超越 Serial收集器。
Parallel Scavenge收集器: 新生代收集器,使用複製算法,是並行的多線程收集器,跟其他收集器不一樣,CMS等收集器是關注儘可能的縮短垃圾收集時用戶線程的停頓時間,而 Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。吞吐量是cpu用於運行用戶代碼的時間與cpu總消耗時間的比值。
Serial Old收集器:單線程收集器,是Serial收集器老年代版本,使用“標記-整理”算法,主要用在client模式下,
Parallel Old收集器:Parallel Scavenge收集器的老年代版本,在注重吞吐量及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge收集器家Parallel Old收集器。
CMS收集器: 使用“標記-清除”算法,以獲取最短回收停頓時間爲目標,對於重視服務的相應速度,希望系統停頓時間最短的B/S系統的服務器端尤其有用。CMS收集器分 4個步驟:1,初始標記 2,併發標記 3,重新標記 4,併發清除 耗時最長的併發標記和併發清除都可以與用戶線程一起工作了。 還有三個缺點:1,對cpu資源敏感,默認啓動的回收線程數是(cpu數量+3)/4,當cpu數較少的時候,會分掉大部分的cpu去執行收集器線程,影 響用戶,降低吞吐量。 2,無法處理浮動垃圾,浮動垃圾即在併發清除階段因爲是併發執行,還會產生垃圾,這一部分垃圾即爲浮動垃圾,要等下次收集。3,因爲使用的是“標記-清 除”算法,會產生碎片。
G1收集器(Garbage First): 基於“標記-整理”算法,之前的垃圾收集器都是整個新生代或者老生代,而G1將整個java堆(包括新生代和老生代)劃分爲多個大小固定的獨立區域,化整爲零,並跟 蹤這些區域的垃圾堆積程度,在後臺維護一個優先列表,每次根據允許的收集時間,優先回收垃圾最多的區域(也是Garbage First的由來)。1,初始標記 2,併發標記 3,重新標記 4,併發清除

內存分配策略:
1. 對象優先在Eden區分配
2. 大對象直接進入老年代
3. 長期存活的對象將進入老年代(對象頭裏的Age判斷)
4. 動態對象年齡判斷(survivor空間相同年齡的所有對象大小超過了空間一半,則大於等於該年齡的對象進入老年代)
5. 空間分配擔保(從老年代借空間)

Out of memory異常及處理
堆:利用內存映像分析工具
如果是內存泄漏,看看所不需要的泄漏對象到GC roots的引用鏈,定位到泄漏代碼進行修改。
如果是內存溢出,調大虛擬機堆的參數
棧:
Stackoverflow outofMemory 棧內變量過大,或者線程數量太多棧的內存不夠容納新的線程開銷
解決:
前者可以通過調大每個棧的容量
後者可以減少線程數量,不能減少線程數量可以調小棧容量使得每個每個線程浪費的容量減少,也可以調小最大堆,使得棧的總容量增大
方法區和運行時常量池:
反射或者字節碼技術生成了大量的類導致溢出。
在寫相關產生類的代碼時注意。
計算機網絡

常見請求頭
Host
User-Agent
Accept
Accept-Language
Accept-Encoding
Referer
Cookie
Connection
If-Modified-Since

相應頭
Cache-Control
Connection
Content-Encoding
Expires
Last-Modified
Location
Date
ETag

200 OK
你最希望看到的,即處理成功!
301 Moved Permanently
客戶請求的文檔在其他地方,新的URL在Location頭中給出,瀏覽器應該自動地訪問新的URL。
302 Found
類似於301,但新的URL應該被視爲臨時性的替代,而不是永久性的。
303 See Other
我把你redirect到其它的頁面,目標的URL通過響應報文頭的Location告訴你。
304 Not Modified
告訴客戶端,你請求的這個資源至你上次取得後,並沒有更改,你直接用你本地的緩存吧,我很忙哦,你能不能少來煩我啊!
404 Not Found
你最不希望看到的,即找不到頁面。如你在google上找到一個頁面,點擊這個鏈接返回404,表示這個頁面已經被網站刪除了,google那邊的記錄只是美好的回憶。
500 Internal Server Error
看到這個錯誤,你就應該查查服務端的日誌了,肯定拋出了一堆異常,別睡了,起來改BUG去吧!
401 Unauthorized
客戶試圖未經授權訪問受密碼保護的頁面。應答中會包含一個WWW-Authenticate頭,瀏覽器據此顯示用戶名字/密碼對話框,然後在填寫合適的Authorization頭後再次發出請求。
403 Forbidden
資源不可用。
404 Not Found
無法找到指定位置的資源
405 Method Not Allowed
請求方法(GET、POST、HEAD、Delete、PUT、TRACE等)對指定的資源不適用。
501 Not Implemented
服務器不支持實現請求所需要的功能。例如,客戶發出了一個服務器不支持的PUT請求
502 Bad Gateway
服務器作爲網關或者代理時,爲了完成請求訪問下一個服務器,但該服務器返回了非法的應答
503 Service Unavailable
服務器由於維護或者負載過重未能應答。例如,Servlet可能在數據庫連接池已滿的情況下返回503。服務器返回503時可以提供一個Retry-After頭

TCP/IP的三次握手、四次揮手
數據結構
算法

各大排序算法信手拈來,優缺點
kmp算法
MySQL
1.MySQL中索引有哪些類型?

索引類型: B-TREE索引,哈希索引
•B-TREE索引加速了數據訪問,因爲存儲引擎不會掃描整個表得到需要的數據。相反,它從根節點開始。根節點保存了指向子節點的指針,並且存儲引擎會根據指針尋找數據。它通過查找節點頁中的值找到正確的指針,節點頁包含子節點的指針,並且存儲引擎會根據指針尋找數據。它通過查找節點頁中的值找到正確的指針,節點頁包含子節點中值的上界和下界。最後,存儲引擎可能無法找到需要的數據,也可能成功地找到包含數據的葉子頁面。
•例:B-TREE索引 對於以下類型查詢有用。匹配全名、匹配最左前綴、匹配列前綴、匹配範圍值、精確匹配一部分並且匹配某個範圍中的另一部分;
B-TREE索引的侷限:如果查找沒有從索引列的最左邊開始,它就沒什麼用處。不能跳過索引中的列,存儲引擎不能優先訪問任何在第一個範圍條件右邊的列。例:如果查詢是where last_name=’Smith’ AND first_name LIKE ‘J%’ AND dob=’1976-12-23’;訪問就只能使用索引的頭兩列,因爲LIKE是範圍條件。
•哈希索引建立在哈希表的基礎上,它只對使用了索引中的每一列的精確查找有用。對於每一行,存儲引擎計算出了被索引列的哈希碼,它是一個較小的值,並且有可能和其他行的哈希碼不同。它把哈希碼保存在索引中,並且保存了一個指向哈希表中每一行的指針。
•因爲索引只包含了哈希碼和行指針,而不是值自身,MYSQL不能使用索引中的值來避免讀取行。
•MYSQL不能使用哈希索引進行排序,因爲它們不會按序保存行。
•哈希索引不支持部分鍵匹配,因爲它們是由被索引的全部值計算出來的。也就是說,如果在(A,B)兩列上有索引,並且WHERE子句中只使用了A,那麼索引就不會起作用。
•哈希索引只支持使用了= IN()和<=>的相等比較。它們不能加快範圍查詢。例如WHERE price > 100;
•訪問哈希索引中的數據非常快,除非碰撞率很高。當發生碰撞的時候,存儲引擎必須訪問鏈表中的每一個行指針,然後逐行進行數據比較,以確定正確的數據。如果有很多碰撞,一些索引維護操作就有可能會變慢。

編寫高效 SQL 語句的最佳實踐
http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-1009qinw/

1、PreparedStatement支持動態設置參數,Statement不支持。
2、PreparedStatement可避免如類似 單引號 的編碼麻煩,Statement不可以。
3、PreparedStatement支持預編譯,Statement不支持。
4、在sql語句出錯時PreparedStatement不易檢查,而Statement則更便於查錯。
5、PreparedStatement可防止Sql助於,更加安全,而Statement不行。
詳見:http://blog.163.com/xiaokangzhijia@126/blog/static/1659548562010927222912/
什麼是SQL注入:
通過sql語句的拼接達到無參數查詢數據庫數據目的的方法。
如將要執行的sql語句爲 select * from table where name = “+appName+”,利用appName參數值的輸入,來生成惡意的sql語句,如將[‘or’1’=’1’] 傳入可在數據庫中執行。
因此可以採用PrepareStatement來避免Sql注入,在服務器端接收參數數據後,進行驗證,此時PrepareStatement會自動檢測,而Statement不 行,需要手工檢測。
併發
類鎖與對象鎖
類鎖和和該類的對象的對象鎖不會進行競爭
如果一個類的靜態方法和對象的實例方法在兩個線程裏對類的靜態變量進行訪問,這個變量是線程不安全的。
同步靜態方法時會獲取該類的“Class”對象,所以當一個線程進入同步的靜態方法中時,線程監視器獲取類本身的對象鎖,其它線程不能進入這個類的任何靜態同步方法。它不像實例方法,因爲多個線程可以同時訪問不同實例同步實例方法。

雙重檢查鎖定:
問題根源:在實例還沒初始化完成前,引用已經暴露
解決:將引用定義爲volatile,從而禁止實例初始化的重排序;

ConcurrentHashMap

讀操作不需要加鎖
static final class HashEntry

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章