[轉改]Java研發方向如何準備BAT技術面試答案(上)

1. 面向對象和麪向過程的區別

面向過程 
優點:性能比面向對象高,因爲類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般採用面向過程開發,性能是最重要的因素。 
缺點:沒有面向對象易維護、易複用、易擴展 
面向對象 
優點:易維護、易複用、易擴展,由於面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護 
缺點:性能比面向過程低

2. Java的四個基本特性(抽象、封裝、繼承,多態)

抽象:就是把現實生活中的某一類東西提取出來,用程序代碼表示,我們通常叫做類或者接口。抽象包括兩個方面:一個是數據抽象,一個是過程抽象。數據抽象也就是對象的屬性。過程抽象是對象的行爲特徵。 
封裝:把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行封裝隱藏。封裝分爲屬性的封裝和方法的封裝。 
繼承:是對有着共同特性的多類事物,進行再抽象成一個類。這個類就是多類事物的父類。父類的意義在於抽取多類事物的共性。 
多態:允許不同類的對象對同一消息做出響應。方法的重載、類的覆蓋正體現了多態。

3. 重載和重寫的區別

重載:發生在同一個類中,方法名必須相同,參數類型不同、個數不同、順序不同,方法返回值和訪問修飾符可以不同,發生在編譯時。 
重寫:發生在父子類中,方法名、參數列表必須相同,返回值小於等於父類,拋出的異常小於等於父類,訪問修飾符大於等於父類;如果父類方法訪問修飾符爲private則子類中就不是重寫。

4. 構造器Constructor是否可被override

構造器不能被重寫,不能用static修飾構造器,只能用 public private protected這三個權限修飾符,且不能有返回語句。

5. 訪問控制符public,protected,private,以及默認的區別

private只有在本類中才能訪問; 
public在任何地方都能訪問; 
protected在同包內的類及包外的子類能訪問; 
默認不寫在同包內能訪問。

6. 是否可以繼承String類

String類是final類故不可以繼承,一切由final修飾過的都不能繼承

7. String和StringBuffer、StringBuilder的區別

可變性: 
String類中使用字符數組保存字符串,private final char value[],所以string對象是不可變的。 
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,char[] value,這兩種對象都是可變的。
 

線程安全性: 
String中的對象是不可變的,也就可以理解爲常量,線程安全。 
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。 

性能: 
每次對String 類型進行改變的時候,都會生成一個新的 String 對象,然後將指針指向新的 String 對象。StringBuffer每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象並改變對象引用。相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。

8. hashCode和equals方法的關係

equals相等,hashcode必相等;hashcode相等,equals可能不相等。

9. 抽象類和接口的區別

①接口是對動作抽象,抽象類是對根源的抽象。你關注事物的本質的時候,請用抽象類;當你關注一種操作的時候,用接口。

②抽象類要被子類繼承,接口要被子類實現。

③接口裏面只能對方法進行聲明,抽象類既可以對方法進行聲明也可以對方法進行實現。

④接口(類)可以實現接口,甚至可以實現多個接口。但是類只能繼承一個類。

⑤抽象級別(從高到低):接口>抽象類>實現類。

10. 自動裝箱與拆箱

裝箱:將基本類型用它們對應的引用類型包裝起來; 
拆箱:將包裝類型轉換爲基本數據類型; 
Java使用自動裝箱和拆箱機制,節省了常用數值的內存開銷和創建對象的開銷,提高了效率,由編譯器來完成,編譯器會在編譯期根據語法決定是否進行裝箱和拆箱動作。

11. 什麼是泛型、爲什麼要使用以及泛型擦除

泛型,即“參數化類型”。 
創建集合時就指定集合元素的類型,該集合只能保存其指定類型的元素,避免使用強制類型轉換。 
泛型類型信息將在編譯處理是被擦除,Java編譯器生成的字節碼是不包涵泛型信息的,這個編譯器處理的過程即類型擦除。 
泛型擦除可以簡單的理解爲將泛型java代碼轉換爲普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java字節碼。 

類型擦除的主要過程如下:

  • 將所有的泛型參數用其最左邊界(最頂級的父類型)類型替換。

  • 移除所有的類型參數。

12. Java中的集合類及關係圖

List和Set繼承自Collection接口。 
Set無序不允許元素重複。HashSet和TreeSet是兩個主要的實現類。 
List有序且允許元素重複。ArrayList、LinkedList和Vector是三個主要的實現類。 
Map也屬於集合系統,但和Collection接口沒關係。Map是key對value的映射集合,其中key列就是一個集合。key不能重複,但是value可以重複。 HashMap、TreeMap和Hashtable是三個主要的實現類。 
SortedSet和SortedMap接口對元素按指定規則排序,SortedMap是對key列進行排序。

13. HashMap實現原理

具體原理一句兩句也說不清楚,網絡文章: 
http://zhangshixi.iteye.com/blog/672697 
http://www.admin10000.com/document/3322.html

14. HashTable實現原理

具體原理一句兩句也說不清楚,網絡文章: 
http://www.cnblogs.com/skywang12345/p/3310887.html 
http://blog.csdn.net/chdjj/article/details/38581035

15. HashMap和HashTable區別

  • HashTable的方法前面都有synchronized來同步,是線程安全的;HashMap未經同步,是非線程安全的。

  • HashTable不允許null值(key和value都不可以) ;HashMap允許null值(key和value都可以)。

  • HashTable有一個contains(Object value)功能和containsValue(Object value)功能一樣。

  • HashTable使用Enumeration進行遍歷;HashMap使用Iterator進行遍歷。

  • HashTable中hash數組默認大小是11,增加的方式是 old*2+1;HashMap中hash數組的默認大小是16,而且一定是2的指數。

  • 哈希值的使用不同,HashTable直接使用對象的hashCode; HashMap重新計算hash值,而且用與代替求模。

16. ArrayList和vector區別

  • ArrayList和 Vector都實現了List接口, 都是通過數組實現的。

  • Vector是線程安全的,而ArrayList是非線程安全的。

  • List第一次創建的時候,會有一個初始大小,隨着不斷向List中增加元素,當 List 認爲容量不夠的時候就會進行擴容。Vector缺省情況下自動增長原來一倍的數組長度,ArrayList增長原來的50%。

17. ArrayList和LinkedList區別及使用場景

  • ArrayList底層是用數組實現的,LinkedList底層是一個雙向鏈表。
  • ArrayList添加元素的時候可能促發擴容(1.5倍數擴容),刪除的元素的時候會促發arraycopy,所以對於ArrayList來說,其添加、刪除元素的時候,整體效率會比LinkedList更低一些。而ArrayList查詢和根據index修改元素的速度相當快。
  • LinkedList添加、刪除元素的速度較快。 但是查詢和修改值的速度較慢。

18. Collection和Collections的區別

  • java.util.Collection 是一個集合接口。它提供了對集合對象進行基本操作的通用接口方法。Collection接口在Java 類庫中有很多具體的實現。Collection接口的意義是爲各種具體的集合提供了最大化的統一操作方式。

  • java.util.Collections 是一個包裝類。它包含有各種有關集合操作的靜態多態方法。此類不能實例化,就像一個工具類,服務於Java的Collection框架。

19. Concurrenthashmap實現原理

具體原理一句兩句也說不清楚,網絡文章: 
http://www.cnblogs.com/ITtangtang/p/3948786.html 
http://ifeve.com/concurrenthashmap/

20. Error、Exception區別

Error類和Exception類的父類都是throwable類,他們的區別是:

  • Error類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢等。對於這類錯誤的導致的應用程序中斷,僅靠程序本身無法恢復和和預防,遇到這樣的錯誤,建議讓程序終止。

  • Exception類表示程序可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該儘可能處理異常,使程序恢復運行,而不應該隨意終止異常。

21.Unchecked Exception和Checked Exception,各列舉幾個

Unchecked Exception:

  • 指的是程序的瑕疵或邏輯錯誤,並且在運行時無法恢復。

  • 包括Error與RuntimeException及其子類,如:OutOfMemoryError, UndeclaredThrowableException,IllegalArgumentException,IllegalMonitorStateException, NullPointerException, IllegalStateException, IndexOutOfBoundsException等。

  • 語法上不需要聲明拋出異常。

Checked Exception:

  • 代表程序不能直接控制的無效外界情況(如用戶輸入,數據庫問題,網絡異常,文件丟失等)

  • 除了Error和RuntimeException及其子類之外,如:ClassNotFoundException, NamingException, ServletException, SQLException, IOException等。

  • 需要try catch處理或throws聲明拋出異常。

22. Java中如何實現代理機制(JDK、CGLIB)

  • JDK動態代理:代理類和目標類實現了共同的接口,用到InvocationHandler接口。

  • CGLIB動態代理:代理類是目標類的子類, 用到MethodInterceptor接口

23. 多線程的實現方式

*繼承Thread類

*實現Runnable接口

*使用ExecutorService、Callable、Future實現有返回結果的多線程。

24. 線程的狀態轉換

《一張圖讓你看懂JAVA線程間的狀態轉換》文章

http://my.oschina.net/mingdongcheng/blog/139263

25. 如何停止一個線程

這個問題簡單總結不一定說的清,看一篇網絡文章: 
http://www.cnblogs.com/greta/p/5624839.html

26. 什麼是線程安全

線程安全就是多線程訪問同一代碼,不會產生不確定的結果。

27. 如何保證線程安全

  • 對非安全的代碼進行加鎖控制;

  • 使用線程安全的類;

  • 多線程併發情況下,線程共享的變量改爲方法級的局部變量

28. Synchronized如何使用

synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:

  • 修飾一個代碼塊,被修飾的代碼塊稱爲同步語句塊,其作用的範圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;

  • 修飾一個方法,被修飾的方法稱爲同步方法,其作用的範圍是整個方法,作用的對象是調用這個方法的對象;

  • 修飾一個靜態的方法,其作用的範圍是整個靜態方法,作用的對象是這個類的所有對象;

  • 修飾一個類,其作用的範圍是synchronized後面括號括起來的部分,作用主的對象是這個類的所有對象。

29. synchronized和Lock的區別

主要相同點:Lock能完成synchronized所實現的所有功能 
主要不同點:

①Lock的鎖定是通過代碼實現的,而synchronized是在JVM層面上實現的,synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,並且必須在finally從句中釋放。

②Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。

③Lock鎖的範圍有侷限性,塊範圍,而synchronized可以鎖住塊、對象、類。

30. 多線程如何進行信息交互

  • void notify() 喚醒在此對象監視器上等待的單個線程。

  • void notifyAll() 喚醒在此對象監視器上等待的所有線程。

  • void wait() 導致當前的線程等待,直到其他線程調用此對象的notify()方法或notifyAll()方法。

  • void wait(long timeout) 導致當前的線程等待,直到其他線程調用此對象的notify()方法或notifyAll()方法,或者超過指定的時間量。

  • void wait(long timeout, int nanos) 導致當前的線程等待,直到其他線程調用此對象的notify()方法或notifyAll()方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量。

31. sleep和wait的區別(考察的方向是是否會釋放鎖)

①sleep()方法是Thread類中方法,而wait()方法是Object類中的方法。 
②sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復運行狀態,在線程sleep的過程中,線程不會釋放對象鎖

而當線程調用wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象調用notify()方法後本線程才進入對象鎖定池準備。

32. 多線程與死鎖

死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。 
產生死鎖的原因:

  • 因爲系統資源不足。

  • 進程運行推進的順序不合適。

  • 資源分配不當。

33. 如何才能產生死鎖(參考操作系統的死鎖概念)

產生死鎖的四個必要條件:

  • 互斥條件:所謂互斥就是進程在某一時間內獨佔資源。

  • 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。

  • 不剝奪條件:進程已獲得資源,在末使用完之前,不能強行剝奪。

  • 循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關係。

34. 死鎖的預防

打破產生死鎖的四個必要條件中的一個或幾個,保證系統不會進入死鎖狀態。

  • 打破互斥條件。即允許多個進程同時訪問某些資源。但是,有的資源是不允許被同時訪問的,像打印機等等,這是由資源本身的屬性所決定的。所以,這種辦法並無實用價值。

  • 打破佔有且申請條件。可以實行資源預先分配策略。即進程在運行前一次性地向系統申請它所需要的全部資源。如果某個進程所需的全部資源得不到滿足,則不分配任何資源,此進程暫不運行。只有當系統能夠滿足當前進程的全部資源需求時,才一次性地將所申請的資源全部分配給該進程。由於運行的進程已佔有了它所需的全部資源,所以不會發生佔有資源又申請資源的現象,因此不會發生死鎖。

  • 打破循環等待條件,實行資源有序分配策略。採用這種策略,即把資源事先分類編號,按號分配,使進程在申請,佔用資源時不會形成環路。所有進程對資源的請求必須嚴格按資源序號遞增的順序提出。進程佔用了小號資源,才能申請大號資源,就不會產生環路,從而預防了死鎖。

35. 什麼叫守護線程,用什麼方法實現守護線程

守護線程是爲其他線程的運行提供服務的線程。 
setDaemon(boolean on)方法可以方便的設置線程的Daemon模式,true爲守護模式,false爲用戶模式。

在Java中,最典型的守護線程就是GC線程。

36. Java線程池技術及原理

這個有點長,還是看一篇文章吧: 
http://www.importnew.com/19011.html 
http://www.cnblogs.com/dolphin0520/p/3932921.html

37. java併發包concurrent及常用的類

這個內容有點多,需要仔細看: 
併發包諸類概覽:http://www.raychase.net/1912 
線程池:http://www.cnblogs.com/dolphin0520/p/3932921.html 
鎖:http://www.cnblogs.com/dolphin0520/p/3923167.html 
集合:http://www.cnblogs.com/huangfox/archive/2012/08/16/2642666.html

38. volatile關鍵字

用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改後的最的值。volatile很容易被誤用,用來進行原子性操作。 
Java語言中的volatile變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,並且運行時開銷也較少,但是它所能實現的功能也僅是synchronized的一部分。鎖提供了兩種主要特性:互斥(mutual exclusion)和可見性(visibility)。互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現對共享數據的協調訪問協議,這樣,一次就只有一個線程能夠使用該共享數據。可見性必須確保釋放鎖之前對共享數據做出的更改對於隨後獲得該鎖的另一個線程是可見的,如果沒有同步機制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發許多嚴重問題。Volatile變量具有synchronized的可見性特性,但是不具備原子特性。這就是說線程能夠自動發現 volatile 變量的最新值。

要使volatile變量提供理想的線程安全,必須同時滿足下面兩個條件:對變量的寫操作不依賴於當前值;該變量沒有包含在具有其他變量的不變式中。 
第一個條件的限制使volatile變量不能用作線程安全計數器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀取-修改-寫入操作序列組成的組合操作,必須以原子方式執行,而volatile不能提供必須的原子特性。實現正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實現這點。 
每一個線程運行時都有一個線程棧,線程棧保存了線程運行時候變量值信息。當線程訪問某一個對象時候值的時候,首先通過對象的引用找到對應在堆內存的變量的值,然後把堆內存變量的具體值load到線程本地內存中,建立一個變量副本,之後線程就不再和對象在堆內存變量值有任何關係,而是直接修改副本變量的值,在修改完之後的某一個時刻(線程退出之前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就產生變化了。 
read and load 從主存複製變量到當前工作內存 
use and assign 執行代碼,改變共享變量值 
store and write 用工作內存數據刷新主存相關內容 
其中use and assign 可以多次出現,但是這一些操作並不是原子性,也就是 在read load之後,如果主內存count變量發生修改之後,線程工作內存中的值由於已經加載,不會產生對應的變化,所以計算出來的結果會和預期不一樣。

39. Java中的NIO,BIO,AIO分別是什麼

  • BIO:同步並阻塞,服務器實現模式爲一個連接一個線程,即客戶端有連接請求時服務器端就需要啓動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。BIO方式適用於連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。

  • NIO:同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的連接請求都會註冊到多路複用器上,多路複用器輪詢到連接有I/O請求時才啓動一個線程進行處理。NIO方式適用於連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4開始支持。NIO的3個重要概念是Buffer、Channel、Selector。

  • AIO:異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啓動線程進行處理.AIO方式使用於連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與併發操作,編程比較複雜,JDK7開始支持。

40. IO和NIO區別

  • IO是面向流的,NIO是面向緩衝區的。

  • IO的各種流是阻塞的,NIO是非阻塞模式。

  • Java NIO的選擇器允許一個單獨的線程來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的線程來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。

41. 序列化與反序列化

把對象轉換爲字節序列的過程稱爲對象的序列化。 
把字節序列恢復爲對象的過程稱爲對象的反序列化。

對象的序列化主要有兩種用途:

  • 把對象的字節序列永久地保存到硬盤上,通常存放在一個文件中;

  • 在網絡上傳送對象的字節序列。

  • 當兩個進程在進行遠程通信時,彼此可以發送各種類型的數據。無論是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方需要把這個Java對象轉換爲字節序列,才能在網絡上傳送;接收方則需要把字節序列再恢復爲Java對象。

42. 常見的序列化協議有哪些

Protobuf, Thrift, Hessian, Kryo

43. 內存溢出和內存泄漏的區別

內存溢出是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory。 
內存泄漏是指分配出去的內存不再使用,但是無法回收

44. Java內存模型及各個區域的OOM,如何重現OOM

這部分內容很重要,詳細閱讀《深入理解Java虛擬機》,也可以詳細閱讀這篇網絡文章http://hllvm.group.iteye.com/group/wiki/2857-JVM

45. 出現OOM如何解決

  • 可通過命令定期抓取heap dump或者啓動參數OOM時自動抓取heap dump文件。

  • 通過對比多個heap dump,以及heap dump的內容,分析代碼找出內存佔用最多的地方。

  • 分析佔用的內存對象,是否是因爲錯誤導致的內存未及時釋放,或者數據過多導致的內存溢出。

46. 用什麼工具可以查出內存泄漏

  • Memory Analyzer-是一款開源的JAVA內存分析軟件,查找內存泄漏,能容易找到大塊內存並驗證誰在一直佔用它,它是基於Eclipse RCP(Rich Client Platform),可以下載RCP的獨立版本或者Eclipse的插件。

  • JProbe-分析Java的內存泄漏。

  • JProfiler-一個全功能的Java剖析工具,專用於分析J2SE和J2EE應用程序。它把CPU、執行緒和內存的剖析組合在一個強大的應用中,GUI可以找到效能瓶頸、抓出內存泄漏、並解決執行緒的問題。

  • JRockit-用來診斷Java內存泄漏並指出根本原因,專門針對Intel平臺並得到優化,能在Intel硬件上獲得最高的性能。

  • YourKit .NET & Java Profiling業界領先的Java和.NET程序性能分析工具。

  • AutomatedQA -AutomatedQA的獲獎產品performance profiling和memory debugging工具集的下一代替換產品,支持Microsoft, Borland, Intel, Compaq 和 GNU編譯器。可以爲.NET和Windows程序生成全面細緻的報告,從而幫助您輕鬆隔離並排除代碼中含有的性能問題和內存/資源泄露問題。支持.Net 1.0,1.1,2.0,3.0和Windows 32/64位應用程序。

  • Compuware DevPartner Java Edition-包含Java內存檢測,代碼覆蓋率測試,代碼性能測試,線程死鎖,分佈式應用等幾大功能模塊

47. Java內存管理及回收算法

閱讀這篇文章:http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html

48. Java類加載器及如何加載類(雙親委派)

閱讀文章:https://www.ibm.com/developerworks/cn/java/j-lo-classloader/(推薦) 
http://blog.csdn.net/zhoudaxia/article/details/35824249

49. xml解析方式

  • DOM(JAXP Crimson解析器)

  • SAX

  • JDOM

  • DOM4J

區別:

  • DOM4J性能最好,連Sun的JAXM也在用DOM4J。目前許多開源項目中大量採用DOM4J,例如大名鼎鼎的hibernate也用DOM4J來讀取XML配置文件。如果不考慮可移植性,那就採用DOM4J.

  • JDOM和DOM在性能測試時表現不佳,在測試10M文檔時內存溢出。在小文檔情況下還值得考慮使用DOM和JDOM。雖然JDOM的開發者已經說明他們期望在正式發行版前專注性能問題,但是從性能觀點來看,它確實沒有值得推薦之處。另外,DOM仍是一個非常好的選擇。DOM實現廣泛應用於多種編程語言。它還是許多其它與XML相關的標準的基礎,因爲它正式獲得W3C推薦(與基於非標準的Java模型相對),所以在某些類型的項目中可能也需要它(如在JavaScript中使用DOM)。

  • SAX表現較好,這要依賴於它特定的解析方式-事件驅動。一個SAX檢測即將到來的XML流,但並沒有載入到內存(當然當XML流被讀入時,會有部分文檔暫時隱藏在內存中)。

50. Statement和PreparedStatement之間的區別

  • ①從程序本身的角度來看,PreparedStatement更具效率。
    我們通過connection.preparedStatement(sql)方法來獲得PreparedStatment對象,然後通過preStatement.setXXX來設置查詢參數。
    如果我有2個查詢,SQL語句都一樣,但是參數不同,使用PreparedStatment的話只需setXXX不同的參數、再次查詢即可,而如果使用Statement的話,需要重新創建Statement對象,connection.createStatement(sql)

    ②從數據庫層面來講,PreparedStatment使用預編譯處理,更具效率。
    在使用PreparedStatement時,數據庫系統會對sql語句進行預編譯處理(前提是JDBC驅動支持),具體包括SQL語句的分析,編譯,優化等過程,預編譯後會緩存起來,執行計劃同樣也會緩存起來,編譯的sql查詢語句能在將來的查詢中重用(同樣的查詢,哪怕參數值不同)。
    需要注意的是,使用PreparedStatement時,SQL不要用String追加參數值,而應該使用preStatement.setXXX來設置查詢參數。

    ③PreparedStatment可以防止SQL注入。
    如:String sql = "SELECT * FROM user WHERE name = '" + userName + "' and password = '"+ passWord +"';"
    惡意輸入參數值:userName = "1' OR '1'='1";    passWord = "1' OR '1'='1";
    最終sql會變成:String sql = "SELECT * FROM user WHERE name = '1' OR '1'='1' and  password = '1' OR '1'='1';"
    這條語句相當於select * from user。
    如果用戶再加上drop table user,後果將不堪設想。
    所以使用PreparedStatement能避免此種情況,因爲數據庫系統不會將參數的內容視爲SQL指令的一部分來處理,只有在數據庫完成SQL指令的編譯後,才套用參數運行。因此就算參數中含有破壞性的指令,也不會被數據庫所運行。

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