Java面試300題(2020年版,3-5年面試題重點突破)

xuzhiyonggithubpers發表於2020-07-03

目錄

Java知識點彙總

1 JDK、JRE、JVM關係是什麼?

JDK(Java Development Kit)即為Java開發工具包,包含編寫Java程式所必須的編譯、
執行等開發工具以及JRE。開發工具如:用於編譯java程式的javac命令、用於啟動JVM運
行java程式的java命令、用於生成文件的javadoc命令以及用於打包的jar命令等等。
JRE(Java Runtime Environment)即為Java執行環境,提供了執行Java應用程式所
必須的軟體環境,包含有Java虛擬機器(JVM)和豐富的系統類庫。系統類庫即為java提前
封裝好的功能類,只需拿來直接使用即可,可以大大的提高開發效率。 
JVM(Java Virtual Machines)即為Java虛擬機器,提供了位元組碼檔案
(.class)的執行環境支援。簡單說,就是JDK包含JRE包含JVM。

2 繼承的的特點和好處,弊端?

  • 特點:可以從以下兩方面來講:
  • 類與類之間的繼承:只能單繼承不能多繼承,但是可以多層繼承。
  • 介面與介面之間的繼承:既可以單繼承也可以多繼承。
  • 好處:(1)提高了程式碼的複用性、維護性、可擴充套件性。(2)讓類與類產生了關係,
    是多型的前提。
  • 弊端:增強了類與類的耦合性。
  • 補充:物件導向的三大、四大
  • 物件導向的三大思想特徵:封裝、繼承、多型
  • 物件導向的四大特性:封裝、繼承、多型、抽象

3 區域性變數和成員變數的區別

  • 在類中的位置:成員變數定義在類中方法外,區域性變數定義在方法中或者方法的宣告上。
  • 在記憶體中的位置:成員變數存放在堆記憶體中,區域性變數存放在棧記憶體中。
  • 初始化值不同:區域性變數沒有預設值,必須先賦值才能使用;成員變數有預設初始化值。
  • 生命週期不同:成員變數隨著物件的存在而存在,隨著物件的消失而消失;區域性變數
    隨著方法的呼叫而存在,方法呼叫完畢而消失。

4 Java支援的資料型別有哪些?什麼是自動拆裝箱?

基本資料型別:整數值型:byte,short,int,long, 字元型:char 浮點型別:float
,double 布林型:boolean 整數預設int型,小數預設是double型。Float和long類
型的必須加字尾。
首先知道String是引用型別不是基本型別,引用型別宣告的變數是指該變數在記憶體中實
際儲存的是一個引用地址,實體在堆中。引用型別包括類、介面、陣列等。String類還
是final修飾的。 而包裝類就屬於引用型別,自動裝箱和拆箱就是基本型別和引用型別
之間的轉換,至於為什麼要轉換,因為基本型別轉換為引用型別後,就可以new物件,從
而呼叫包裝類中封裝好的方法進行基本型別之間的轉換或者toString(當然用類名直接
呼叫也可以,便於一眼看出該方法是靜態的),還有就是如果集合中想存放基本型別,
泛型的限定型別只能是對應的包裝型別。

5 類變數(靜態變數)和例項變數(物件變數,成員變數)的區別?

  • 所屬不同:類變數屬於類,是物件的共性內容;例項變數屬於物件,是物件的特性內容。
  • 在記憶體中位置不同:類變數存在方法區的靜態區;例項變數存在堆記憶體中。
  • 生命週期不同:類變數隨著類的載入而存在,隨著類的消失而消失;例項變數隨著對
    象的存在而存在,隨著物件的消失而消失。
  • 呼叫方式不同:類變數既能被類名點的形式呼叫,也能通過物件點的形式呼叫;而實
    例變數只能通過物件點的形式呼叫。

6 static關鍵字的特點?注意事項是什麼?有什麼好處和弊端?

  • 靜態成員隨著類的載入而載入,優於物件存在
  • 存在於方法區的位元組碼檔案中的靜態區
  • 被類中所有的物件所共享
  • 能夠通過“類名點”的形式呼叫
  • 靜態只能訪問靜態
  • 注意事項:
    • 靜態方法中不可以有this、super關鍵字(因為靜態優先於物件存在;靜態只
      能覆蓋靜態。)
    • 好處:能夠被類名點的形式呼叫,簡化書寫。被該類下所有的物件所共享。
    • 弊端:生命週期過長。

7 如何實現物件克隆?

  • 實現Cloneable介面並重寫Object類中的clone()方法;
  • 實現Serializable介面,通過物件的序列化和反序列化實現克隆,可以實現真正的
    深度克隆
  • 基於序列化和反序列化實現的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可
    以檢查出要克隆的物件是否支援序列化,這項檢查是編譯器完成的,不是在執行時丟擲
    異常,這種是方案明顯優於使用Object類的clone方法克隆物件。讓問題在編譯的時候
    暴露出來總是優於把問題留到執行時。

8 訪問修飾符public,private,protected,以及不寫(預設)時的區別

  • public:當前類、同包、子類、其他包
  • protected:當前類、同包、子類
  • private:當前類
  • default:當前類、同包

9 Java中如何實現序列化,有什麼意義?

序列化就是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化。可
以對流化後的物件進行讀寫操作,也可將流化後的物件傳輸於網路之間。序列化是為了
解決物件流讀寫操作時可能引發的問題(如果不進行序列化可能會存在資料亂序的問題)
。要實現序列化,需要讓一個類實現Serializable介面,該介面是一個標識性介面,
標註該類物件是可被序列化的,然後使用一個輸出流來構造一個物件輸出流並通過
writeObject(Object)方法就可以將實現物件寫出(即儲存其狀態);如果需要反
序列化則可以用一個輸入流建立物件輸入流,然後通過readObject方法從流中讀取對
象。序列化除了能夠實現物件的持久化之外,還能夠用於物件的深度克隆

10 抽象類和介面的區別

  • 抽象類只能被繼承,而且只能單繼承。介面需要被實現,而且可以多實現。
  • 抽象類中可以定義非抽象方法,子類可以直接繼承使用。介面中都有抽象方法,需要
    子類去實現。
  • 抽象類使用的是  is a 關係。介面使用的 like a 關係。
  • 抽象類的成員修飾符可以自定義。介面中的成員修飾符是固定的。全都是public的。

11 兩個物件值相同(x.equals(y) == true),但卻可有不同的 hash code,這句 話對不對?

不對,如果兩個物件 x 和 y 滿足 x.equals(y) == true,它們的雜湊碼
(hash code)應當相同。
Java 對於 eqauls 方法和hashCode方法是這樣規定的:

  • 如果兩個物件相同(equals 方法返回 true ),那麼它們的 h ashCode 值
    一定要相同;
  • 如果兩個物件的 hashCode相同,它們並不一定相同。當然,你未必要按照
    要求 去做,但是如果你違背了上述原則就會發現在使用容器時,相同的物件可
    以出現在 Set 集合中,同時增加新元素 的效率會大大下降(對於使用雜湊存
    儲的系統,如果雜湊碼頻繁的衝突將會造成存取效能急劇下降)。

12 類和物件的關係?

類是用來描述事物的屬性(事物的外在的特徵,成員變數)和行為(事物具有
的特性,成員方法)的一個抽象的概念。
物件是類的例項化。
比如:學生是一個類,具體某一個人就是物件。

13 封裝就是私有,對嗎?為什麼?

不對,private(私有)僅僅是封裝的一種體現形式。我們常用的類,方法,函式
也是封裝。只要是對外不可見,就能達到封裝的效果,比如:包與包之間的訪問。
補充:get/set訪問方式必須成對出現嗎?
答:不是,具體看需求,需要設定值就提供set方法,如果需要訪問值,就提供get方法

14 什麼是封裝?封裝的原則?好處

封裝就是隱藏物件的屬性和具體實現細節,僅對外提供公共的訪問方式。
原則:(1)將不需要對外暴露的資訊隱藏;(2)對外提供公共的訪問方式。
好處:將變化隔離;提高了安全性;提高了程式碼程式碼重用性(是對的),便於使用。

15 Java中引數傳遞的問題

Java中只有值傳遞。
如果是基本資料型別,傳遞的是值,
如果是引用資料型別,傳遞的地址值(但是String型別作為方法的形參時,傳
遞的是值),地址值也是值。

16 構造方法,set方法都可以給成員變數賦值,這兩種賦值方式有什麼區別?

構造方法主要作用是用來給物件初始化,賦值只是它的捎帶工作,也可以不用賦值。
Set方法只能用來賦值,在原有物件的基礎上賦值,可以用來修改值。
構造方法重新賦值,相對於重新建立物件。

17 靜態程式碼塊和構造程式碼塊的區別?

  • 靜態程式碼塊隨著類的載入而載入,一般是用來載入驅動的。只在類載入的時候
    執行一次,優先於構造方法執行
  • 構造程式碼塊裡邊放的是所有構造方法的共性內容,為了簡化書寫,調高效率。
    每建立一次物件,就執行一次,它是優先於構造方法執行的。

18 java 中實現多型的機制是什麼

靠的是父類或介面定義的引用變數可以指向子類或具體實現類的例項物件,而程
序呼叫的方法在執行期才動態繫結,就是引用變數所指向的具體例項物件的方法,
也就是記憶體里正在執行的那個物件的方法,而不是引用變數的型別中定義的方法。

19 String 是最基本的資料型別嗎?

不是。Java中的基本資料型別只有8個:byte、short、int、long、float、
double、char、boolean;除了基本型別(primitive type)和列舉型別
(enumeration type),剩下的都是引用型別(reference type)。

20 float f=3.4;是否正確

不正確。3.4是雙精度數,將雙精度型(double)賦值給浮點型(float)屬於
下轉型(down-casting,也稱為窄化)會造成精度損失,因此需要強制型別轉
換float f =(float)3.4; 或者寫成float f =3.4F;。

21 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

22 switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?

在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。
從Java 5開始,Java中引入了列舉型別,expr也可以是enum型別,從Java 7開始,
expr還可以是字串(String),但是長整型(long)在目前所有的版本中都是不可以的。

23 陣列有沒有length()方法?String有沒有length()方法?

陣列沒有length()方法,有length 的屬性。String 有length()方法。
JavaScript中,獲得字串的長度是通過length屬性得到的,這一點容易和Java混淆。

24 在Java中,如何跳出當前的多重巢狀迴圈?

在最外層迴圈前加一個標記如A,然後用break A;可以跳出多重迴圈。
(Java中支援帶標籤的break和continue語句,作用有點類似於C和C++中的goto語句,
但是就像要避免使用goto一樣,應該避免使用帶標籤的break和continue,因為它不
會讓你的程式變得更優雅,很多時候甚至有相反的作用,所以這種語法其實不知道更好)

25 構造器(constructor)是否可被重寫(override)

構造器不能被繼承,因此不能被重寫,但可以被過載。

26 是否可以繼承String類?

String 類是final類,不可以被繼承。

27 String和StringBuilder、StringBuffer的區別?

Java平臺提供了兩種型別的字串:String和StringBuffer/StringBuilder,
它們可以儲存和操作字串。其中String是隻讀字串,也就意味著String引用的
字串內容是不能被改變的。而StringBuffer/StringBuilder類表示的字串對
象可以直接進行修改。StringBuilder是Java 5中引入的,它和StringBuffer的
方法完全相同,區別在於它是在單執行緒環境下使用的,因為它的所有方面都沒有
被synchronized修飾,因此它的效率也比StringBuffer要高。

28 過載(Overload)和重寫(Override)的區別。過載的方法能否根據返回型別進行區分?

方法的過載和重寫都是實現多型的方式,區別在於前者實現的是編譯時的多型性,
而後者實現的是執行時的多型性。過載發生在一個類中,同名的方法如果有不同的
引數列表(引數型別不同、引數個數不同或者二者都不同)則視為過載;重寫發生
在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的返回型別,
比父類被重寫方法更好訪問,不能比父類被重寫方法宣告更多的異常(里氏代換原則)
。過載對返回型別沒有特殊的要求。

29 char 型變數中能不能存貯一箇中文漢字,為什麼?

char型別可以儲存一箇中文漢字,因為Java中使用的編碼是Unicode(不選擇任何
特定的編碼,直接使用字元在字符集中的編號,這是統一的唯一方法),
一個char型別佔2個位元組(16位元),所以放一箇中文是沒問題的。

30 抽象的(abstract)方法是否可同時是靜態的(static),是否可同時是本

地方法(native),是否可同時被synchronized修飾?
都不能。抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。
本地方法是由原生程式碼(如C程式碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。
synchronized和方法的實現細節有關,抽象方法不涉及實現細節,因此也是相互矛盾的。

31 是否可以從一個靜態(static)方法內部發出對非靜態(non-static)方法的呼叫?

不可以,靜態方法只能訪問靜態成員,因為非靜態方法的呼叫要先建立物件,
在呼叫靜態方法時可能物件並沒有被初始化。

32 String s = new String(“xyz”);建立了幾個字串物件?

兩個物件,一個是靜態區的”xyz”,一個是用new建立在堆上的物件。

33 介面是否可繼承(extends)介面?抽象類是否可實現(implements)介面?

抽象類是否可繼承具體類(concrete class)?
介面可以繼承介面,而且支援多重繼承。抽象類可以實現(implements)介面,
抽象類可繼承具體類也可以繼承抽象類。

34 一個”.java”原始檔中是否可以包含多個類(不是內部類)?有什麼限制?

可以,但一個原始檔中最多隻能有一個公開類(public class)而且檔案
名必須和公開類的類名完全保持一致。

35 Java 中的final關鍵字有哪些用法?

  • 修飾類:表示該類不能被繼承;
  • 修飾方法:表示方法不能被重寫;
  • 修飾變數:表示變數只能一次賦值以後值不能被修改(常量)。

36 比較一下Java和JavaSciprt。

JavaScript 與Java是兩個公司開發的不同的兩個產品。Java 是
原Sun Microsystems公司推出的物件導向的程式設計語言,特別
適合於網際網路應用程式開發;而JavaScript是Netscape公司的產品
,為了擴充套件Netscape瀏覽器的功能而開發的一種可以嵌入Web頁面中
執行的基於物件和事件驅動的解釋性語言。下面對兩種語言間的異同作
如下比較:- 基於物件和麵向物件:Java是一種真正的物件導向的語言
,即使是開發簡單的程式,必須設計物件;JavaScript是種指令碼語言,
它可以用來製作與網路無關的,與使用者互動作用的複雜軟體。它是一種基
於物件(Object-Based)和事件驅動(Event-Driven)的程式語言,因
而它本身提供了非常豐富的內部物件供設計人員使用。- 解釋和編譯:
Java的原始碼在執行之前,必須經過編譯。JavaScript是一種解釋性編
程語言,其原始碼不需經過編譯,由瀏覽器解釋執行。(目前的瀏覽器幾
乎都使用了JIT(即時編譯)技術來提升JavaScript的執行效率)- 強類
型變數和型別弱變數:Java採用強型別變數檢查,即所有變數在編譯之前
必須作宣告;JavaScript中變數是弱型別的,甚至在使用變數前可以不作
宣告,JavaScript的直譯器在執行時檢查推斷其資料型別。- 程式碼格式不一樣。

37 什麼時候用斷言(assert)?

斷言在軟體開發中是一種常用的除錯方式,很多開發語言中都支援這種機制。
一般來說,斷言用於保證程式最基本、關鍵的正確性。斷言檢查通常在開發和
測試時開啟。為了保證程式的執行效率,在軟體釋出後斷言檢查通常是關閉的。
斷言是一個包含布林表示式的語句,在執行這個語句時假定該表示式為true;
如果表示式的值為false,那麼系統會報告一個AssertionError。

38 闡述final、finally、finalize的區別。

final:修飾符(關鍵字)有三種用法:如果一個類被宣告為final,意味著它
不能再派生出新的子類,即不能被繼承,因此它和abstract是反義詞。將變數
宣告為final,可以保證它們在使用中不被改變,被宣告為final的變數必須在
宣告時給定初值,而在以後的引用中只能讀取不可修改。被宣告為final的方法
也同樣只能使用,不能在子類中被重寫。- finally:通常放在try…catch…的
後面構造總是執行程式碼塊,這就意味著程式無論正常執行還是發生異常,這裡的
程式碼只要JVM不關閉都能執行,可以將釋放外部資源的程式碼寫在finally塊中。
finalize:Object類中定義的方法,Java中允許使用finalize()方法在垃圾
收集器將物件從記憶體中清除出去之前做必要的清理工作。這個方法是由垃圾收集
器在銷燬物件時呼叫的,通過重寫finalize()方法可以整理系統資源或者執行其
他清理工作。

39 Java中是如何支援正規表示式操作的?

Java中的String類提供了支援正規表示式操作的方法,包括:matches()、
replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern
類表示正規表示式物件,它提供了豐富的API進行各種正規表示式操作,
請參考下面面試題的程式碼。

40 獲得一個類的類物件有哪些方式?

方法1:型別.class,例如:String.class- 方法2:物件.getClass(),
例如:”hello”.getClass()- 方法3:Class.forName(),例如:
Class.forName(“java.lang.String”)

41 什麼是值傳遞和引用傳遞?

值傳遞是對基本型變數而言的,傳遞的是該變數的一個副本,改變副本不影響
原變數. 引用傳遞一般是對於物件型變數而言的,傳遞的是該物件地址的一個
副本, 並不是原物件本身 。 一般認為,java內的傳遞都是值傳遞. java中實
例物件的傳遞是引用傳遞 。

42 Thread類的sleep()方法和物件的wait()方法都可以讓執行緒暫停執行,它們有什麼區別?

sleep()方法(休眠)是執行緒類(Thread)的靜態方法,呼叫此方法會讓當前
執行緒暫停執行指定的時間,將執行機會(CPU)讓給其他執行緒,但是物件的鎖
依然保持,因此休眠時間結束後會自動恢復。wait()是Object類的方法,調
用物件的wait()方法導致當前執行緒放棄物件的鎖(執行緒暫停執行),進入對
象的等待池(wait pool),只有呼叫物件的notify()方法(或notifyAll()方法)
時才能喚醒等待池中的執行緒進入等鎖池(lock pool),如果執行緒重新獲得物件的
鎖就可以進入就緒狀態。

43 執行緒的sleep()方法和yield()方法有什麼區別?

  • sleep()方法給其他執行緒執行機會時不考慮執行緒的優先順序,因此會給低優先順序的線
    程以執行的機會;yield()方法只會給相同優先順序或更高優先順序的執行緒以執行的機會;
  • 執行緒執行sleep()方法後轉入阻塞(blocked)狀態,而執行yield()方法後轉入就
    緒(ready)狀態;
  • sleep()方法宣告丟擲InterruptedException,而yield()方
    法沒有宣告任何異常;
  • sleep()方法比yield()方法(跟作業系統CPU排程相關)具有更好的可移植性。

44 當一個執行緒進入一個物件的synchronized方法A之後,其它執行緒是否可進入此物件的synchronized方法B?

不能。其它執行緒只能訪問該物件的非同步方法,同步方法則不能進入。
因為非靜態方法上的synchronized修飾符要求執行方法時要獲得物件的鎖,
如果已經進入A方法說明物件鎖已經被取走,那麼試圖進入B方法的執行緒就只能在
等鎖池(注意不是等待池哦)中等待物件的鎖。

45 請說出與執行緒同步以及執行緒排程相關的方法。

wait():使一個執行緒處於等待(阻塞)狀態,並且釋放所持有的物件的鎖;
sleep():使一個正在執行的執行緒處於睡眠狀態,是一個靜態方法,呼叫此方
法要處理InterruptedException異常;- notify():喚醒一個處於等待狀態
的執行緒,當然在呼叫此方法的時候,並不能確切的喚醒某一個等待狀態的執行緒,
而是由JVM確定喚醒哪個執行緒,而且與優先順序無關;- notityAll():喚醒所有
處於等待狀態的執行緒,該方法並不是將物件的鎖給所有執行緒,而是讓它們競爭,
只有獲得鎖的執行緒才能進入就緒狀態;

46 編寫多執行緒程式有幾種實現方式?

Java 5以前實現多執行緒有兩種實現方法:一種是繼承Thread類;
另一種是實現Runnable介面。兩種方式都要通過重寫run()方法來定義執行緒的行為,
推薦使用後者,因為Java中的繼承是單繼承,一個類有一個父類,
如果繼承了Thread類就無法再繼承其他類了,顯然使用Runnable介面更為靈活。

47 synchronized關鍵字的用法?

synchronized關鍵字可以將物件或者方法標記為同步,以實現對物件和方法的互斥訪問,
可以用synchronized(物件) { … }定義同步程式碼塊,或者在宣告方法時將synchronized
作為方法的修飾符。

48 舉例說明同步和非同步。

如果系統中存在臨界資源(資源數量少於競爭資源的執行緒數量的資源),例如正在寫的資料以後
可能被另一個執行緒讀到,或者正在讀的資料可能已經被另一個執行緒寫過了,那麼這些資料就必須
進行同步存取(資料庫操作中的排他鎖就是最好的例子)。當應用程式在物件上呼叫了一個需
要花費很長時間來執行的方法,並且不希望讓程式等待方法的返回時,就應該使用非同步程式設計,
在很多情況下采用非同步途徑往往更有效率。事實上,所謂的同步就是指阻塞式操作,而非同步就
是非阻塞式操作。

49 啟動一個執行緒是呼叫run()還是start()方法?

啟動一個執行緒是呼叫start()方法,使執行緒所代表的虛擬處理機處於可執行狀態,這意味著它
可以由JVM 排程並執行,這並不意味著執行緒就會立即執行。run()方法是執行緒啟動後要進行回
調(callback)的方法。

50 什麼是執行緒池(thread pool)?

在物件導向程式設計中,建立和銷燬物件是很費時間的,因為建立一個物件要獲取記憶體資源或者其
它更多資源。在Java中更是如此,虛擬機器將試圖跟蹤每一個物件,以便能夠在物件銷燬後進行
垃圾回收。所以提高服務程式效率的一個手段就是儘可能減少建立和銷燬物件的次數,特別是
一些很耗資源的物件建立和銷燬,這就是”池化資源”技術產生的原因。執行緒池顧名思義就是事
先建立若干個可執行的執行緒放入一個池(容器)中,需要的時候從池中獲取執行緒不用自行建立,
使用完畢不需要銷燬執行緒而是放回池中,從而減少建立和銷燬執行緒物件的開銷。Java 5+中的
Executor介面定義一個執行執行緒的工具。它的子型別即執行緒池介面是ExecutorService。要配
置一個執行緒池是比較複雜的,尤其是對於執行緒池的原理不是很清楚的情況下,因此在工具類
Executors面提供了一些靜態工廠方法,生成一些常用的執行緒池,
如下所示:- newSingleThreadExecutor:建立一個單執行緒的執行緒池。
這個執行緒池只有一個執行緒在工作,也就是相當於單執行緒序列執行所有任務。
如果這個唯一的執行緒因為異常結束,那麼會有一個新的執行緒來替代它。此執行緒池保證所有任務
的執行順序按照任務的提交順序執行。- newFixedThreadPool:建立固定大小的執行緒池。
每次提交一個任務就建立一個執行緒,直到執行緒達到執行緒池的最大大小。執行緒池的大小一旦達
到最大值就會保持不變,如果某個執行緒因為執行異常而結束,那麼執行緒池會補充一個新執行緒。
newCachedThreadPool:建立一個可快取的執行緒池。如果執行緒池的大小超過了處理任務所需
要的執行緒,那麼就會回收部分空閒(60秒不執行任務)的執行緒,當任務數增加時,此執行緒池又
可以智慧的新增新執行緒來處理任務。此執行緒池不會對執行緒池大小做限制,執行緒池大小完全依賴
於作業系統(或者說JVM)能夠建立的最大執行緒大小。- newScheduledThreadPool:建立一個
大小無限的執行緒池。此執行緒池支援定時以及週期性執行任務的需求。
newSingleThreadExecutor:建立一個單執行緒的執行緒池。此執行緒池支援定時以及週期性執行任務的需求。

51 執行緒的基本狀態以及狀態之間的關係?

其中Running表示執行狀態,Runnable表示就緒狀態(萬事俱備,只欠CPU),Blocked表
示阻塞狀態,阻塞狀態又有多種情況,可能是因為呼叫wait()方法進入等待池,也可能是執
行同步方法或同步程式碼塊進入等鎖池,或者是呼叫了sleep()方法或join()方法等待休眠或
其他執行緒結束,或是因為發生了I/O中斷。

52 簡述synchronized 和java.util.concurrent.locks.Lock的異同?

Lock是Java 5以後引入的新的API,和關鍵字synchronized相比主要相同點:Lock 能完
成synchronized所實現的所有功能;主要不同點:Lock有比synchronized更精確的執行緒
語義和更好的效能,而且不強制性的要求一定要獲得鎖。synchronized會自動釋放鎖,而
Lock一定要求程式設計師手工釋放,並且最好在finally 塊中釋放(這是釋放外部資源的最好
的地方)。

53 執行緒和程式有什麼區別?

執行緒是程式的子集,一個程式可以有很多執行緒,每條執行緒並行執行不同的任務。不同的程式
使用不同的記憶體空間,而所有的執行緒共享一片相同的記憶體空間。別把它和棧記憶體搞混,每個
執行緒都擁有單獨的棧記憶體用來儲存本地資料。

54 用Runnable還是Thread?

這個問題是上題的後續,大家都知道我們可以通過繼承Thread類或者呼叫Runnable介面來
實現執行緒,問題是,那個方法更好呢?什麼情況下使 用它?這個問題很容易回答,如果你
知道Java不支援類的多重繼承,但允許你呼叫多個介面。所以如果你要繼承其他類,當然是
呼叫Runnable介面好 了。

55 Thread 類中的start() 和 run() 方法有什麼區別?

這個問題經常被問到,但還是能從此區分出面試者對Java執行緒模型的理解程度。start()方
法被用來啟動新建立的執行緒,而且start()內部 呼叫了run()方法,這和直接呼叫run()方
法的效果不一樣。當你呼叫run()方法的時候,只會是在原來的執行緒中呼叫,沒有新的執行緒
啟動,start()方法才會啟動新執行緒。

56  Java中Runnable和Callable有什麼不同?

Runnable和Callable都代表那些要在不同的執行緒中執行的任務。Runnable從JDK1.0開始就
有了,Callable是在 JDK1.5增加的。它們的主要區別是Callable的 call() 方法可以返
回值和丟擲異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計算結
果的Future物件。

57 Java中的volatile 變數是什麼?

volatile是一個特殊的修飾符,只有成員變數才能使用它。在Java併發程式缺少同步類的情
況下,多執行緒對成員變數的操作對其它執行緒是透明的。volatile變數可以保證下一個讀取操
作會在前一個寫操作之後發生,就是上一題的volatile變數規則。

58 什麼是執行緒安全?Vector是一個執行緒安全類嗎?

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

59 一個執行緒執行時發生異常會怎樣?

這是我在一次面試中遇到的一個很刁鑽的Java面試題, 簡單的說,如果異常沒有被捕獲該線
程將會停止執行。Thread.UncaughtExceptionHandler是用於處理未捕獲異常造成執行緒突
然中 斷情況的一個內嵌介面。當一個未捕獲異常將造成執行緒中斷的時候JVM會使用
Thread.getUncaughtExceptionHandler()來 查詢執行緒的UncaughtExceptionHandler
並將執行緒和異常作為引數傳遞給handler的uncaughtException()方法 進行處理。

60 如何在兩個執行緒間共享資料?

你可以通過共享物件來實現這個目的,或者是使用像阻塞佇列這樣併發的資料結構。
(涉及到在兩個執行緒間共享物件)用wait和notify方法實現了生產者消費者模型。

61 Java中notify 和 notifyAll有什麼區別?

這又是一個刁鑽的問題,因為多執行緒可以等待單監控鎖,Java API 的設計人員提供了
一些方法當等待條件改變的時候通知它們,但是這些方法沒有完全實現。notify()方法
不能喚醒某個具體的執行緒,所以只有一個執行緒在等 待的時候它才有用武之地。而notifyAll()
喚醒所有執行緒並允許他們爭奪鎖確保了至少有一個執行緒能繼續執行。

62 什麼是ThreadLocal變數?

ThreadLocal是Java裡一種特殊的變數。每個執行緒都有一個ThreadLocal就是每個執行緒都
擁有了自己獨立的一個變數,競爭條件被 徹底消除了。它是為建立代價高昂的物件獲取線
程安全的好方法,比如你可以用ThreadLocal讓SimpleDateFormat變成執行緒安全的,因
為那個類建立代價高昂且每次呼叫都需要建立不同的例項所以不值得在區域性範圍使用它,
如果為每個執行緒提供一個自己獨有的變數拷貝,將大大提高效率。首先,通 過複用減少了
代價高昂的物件的建立個數。其次,你在沒有使用高代價的同步或者不變性的情況下獲得
了執行緒安全。執行緒區域性變數的另一個不錯的例子是 ThreadLocalRandom類,它在多執行緒
環境中減少了建立代價高昂的Random物件的個數。

63 什麼是FutureTask?

在Java併發程式中FutureTask表示一個可以取消的非同步運算。它有啟動和取消運算、查詢
運算是否完成和取回運算結果等方法。只有當運算完 成的時候結果才能取回,如果運算尚
未完成get方法將會阻塞。一個FutureTask物件可以對呼叫了Callable和Runnable的物件
進行包 裝,由於FutureTask也是呼叫了Runnable介面所以它可以提交給Executor來執行。

64 如何避免死鎖?

java多執行緒中的死鎖死鎖是指兩個或兩個以上的程式在執行過程中,因爭奪資源而造成的一
種互相等待的現象,若無外力作用,它們都將無法推進下去。這是一個嚴重的問題,因為死
鎖會讓你的程式掛起無法完成任務,死鎖的發生必須滿足以下四個條件:
互斥條件:一個資源每次只能被一個程式使用。
請求與保持條件:一個程式因請求資源而阻塞時,對已獲得的資源保持不放。
不剝奪條件:程式已獲得的資源,在末使用完之前,不能強行剝奪。
迴圈等待條件:若干程式之間形成一種頭尾相接的迴圈等待資源關係。
避免死鎖最簡單的方法就是阻止迴圈等待條件,將系統中所有的資源設定標誌位、排序,
規定所有的程式申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。

65 Java中活鎖和死鎖有什麼區別

這是上題的擴充套件,活鎖和死鎖類似,不同之處在於處於活鎖的執行緒或程式的狀態是不斷改
變的,活鎖可以認為是一種特殊的飢餓。一個現實的活鎖例子是兩個 人在狹小的走廊碰到,
兩個人都試著避讓對方好讓彼此通過,但是因為避讓的方向都一樣導致最後誰都不能通過走
廊。簡單的說就是,活鎖和死鎖的主要區別是前者 程式的狀態可以改變但是卻不能繼續執行。

66 怎麼檢測一個執行緒是否擁有鎖?

在java.lang.Thread中有一個方法叫holdsLock(),它返回true如果當且僅當當前執行緒
擁有某個具體物件的鎖。

67 你如何在Java中獲取執行緒堆疊?

對於不同的作業系統,有多種方法來獲得Java程式的執行緒堆疊。當你獲取執行緒堆疊時,
JVM會把所有執行緒的狀態存到日誌檔案或者輸出到控制檯。在 Windows你可以使用
Ctrl + Break組合鍵來獲取執行緒堆疊,Linux下用kill -3命令。你也可以用jstack這
個工具來獲取,它對執行緒id進行操作,你可以用jps這個工具找到id。

68 有三個執行緒T1,T2,T3,怎麼確保它們按順序執行?

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

69 如果你提交任務時,執行緒池佇列已滿。會時發會生什麼?

這個問題問得很狡猾,許多程式設計師會認為該任務會阻塞直到執行緒池佇列有空位。事實上如
果一個任務不能被排程執行那麼ThreadPoolExecutor’s submit()方法將會丟擲一個
RejectedExecutionException異常。

70 Java執行緒池中submit() 和 execute()方法有什麼區別?

兩個方法都可以向執行緒池提交任務,execute()方法的返回型別是void,它定義在
Executor介面中, 而submit()方法可以返回持有計算結果的Future物件,它定義在
ExecutorService介面中,它擴充套件了Executor介面,其它線 程池類像ThreadPoolExecutor
和ScheduledThreadPoolExecutor都有這些方法。

71 什麼是阻塞式方法?

阻塞式方法是指程式會一直等待該方法完成期間不做其他事情,ServerSocket的accept()
方法就是一直等待客戶端連線。這裡的阻塞是 指呼叫結果返回之前,當前執行緒會被掛起,
直到得到結果之後才會返回。此外,還有非同步和非阻塞式方法在任務完成前就返回。

72 多執行緒中的忙迴圈是什麼?

忙迴圈就是程式設計師用迴圈讓一個執行緒等待,不像傳統方法wait(), sleep() 或 yield()
它們都放棄了CPU控制,而忙迴圈不會放棄CPU,它就是在執行一個空迴圈。這麼做的目的是
為了保留CPU快取,在多核系統中,一個等待執行緒醒來的時候可 能會在另一個核心執行,這
樣會重建快取。為了避免重建快取和減少等待重建的時間就可以使用它

73 如何在Java中建立執行緒安全的Singleton?

這是上面那個問題的後續,如果你不喜歡雙檢鎖而面試官問了建立Singleton類的替代方法,
你可以利用JVM的類載入和靜態變數初始化特徵來建立Singleton例項,或者是利用列舉型別
來建立Singleton,我很喜歡用這種方法

74 寫出3條你遵循的多執行緒最佳實踐

給你的執行緒起個有意義的名字。這樣可以方便找bug或追蹤。OrderProcessor, QuoteProcessor
or TradeProcessor 這種名字比 Thread-1. Thread-2 and Thread-3 好多了,給執行緒起一
個和它要完成的任務相關的名字,所有的主要框架甚至JDK都遵循這個最佳實踐。
避免鎖定和縮小同步的範圍鎖花費的代價高昂且上下文切換更耗費時間空間,試試最低限度的使
用同步和鎖,縮小臨界區。因此相對於同步方法我更喜歡同步塊,它給我擁有對鎖的絕對控制權。
多用同步類少用wait 和 notify首先,CountDownLatch, Semaphore, CyclicBarrier
和 Exchanger 這些同步類簡化了編碼操作,而用wait和notify很難實現對複雜控制流的控制。
其次,這些類是由最好的企業編寫和維護在後續的JDK中它們還會不斷 優化和完善,使用這些更高
等級的同步工具你的程式可以不費吹灰之力獲得優化。
多用併發集合少用同步集合這是另外一個容易遵循且受益巨大的最佳實踐,併發集合比同步
集合的可擴充套件性更好,所以在併發程式設計時使用併發集合效果更好。如果下一次你需要用到map,
你應該首先想到用ConcurrentHashMap。

75 如何強制啟動一個執行緒?

這個問題就像是如何強制進行Java垃圾回收,目前還沒有覺得方法,雖然你可以使用
System.gc()來進行垃圾回收,但是不保證能成功。在Java裡面沒有辦法強制啟動一個
執行緒,它是被執行緒排程器控制著且Java沒有公佈相關的API。

76 Java中用到的執行緒排程演算法是什麼

搶佔式。一個執行緒用完CPU之後,作業系統會根據執行緒優先順序、執行緒飢餓情況等資料
算出一個總的優先順序並分配下一個時間片給某個執行緒執行。

77 List、Set、Map是否繼承自Collection介面?

List、Set 是,Map 不是。Map是鍵值對對映容器,與List和Set有明顯的區別,而Set
儲存的零散的元素且不允許有重複元素(數學中的集合也是如此),List是線性結構的容器,
適用於按數值索引訪問元素的情形。

78 闡述ArrayList、Vector、LinkedList的儲存效能和特性。

ArrayList 和Vector都是使用陣列方式儲存資料,此陣列元素數大於實際儲存的資料以便增
加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及陣列元素移動等記憶體
操作,所以索引資料快而插入資料慢,Vector中的方法由於新增了synchronized修飾,因
此Vector是執行緒安全的容器,但效能上較ArrayList差,因此已經是Java中的遺留容器。
LinkedList使用雙向連結串列實現儲存(將記憶體中零散的記憶體單元通過附加的引用關聯起來,形
成一個可以按序號索引的線性結構,這種鏈式儲存方式與陣列的連續儲存方式相比,記憶體的利
用率更高),按序號索引資料需要進行前向或後向遍歷,但是插入資料時只需要記錄本項的前後
項即可,所以插入速度較快。Vector屬於遺留容器(Java早期的版本中提供的容器,除此之外
,Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器),已經不推薦使用,
但是由於ArrayList和LinkedListed都是非執行緒安全的,如果遇到多個執行緒操作同一個容器的場景
,則可以通過工具類Collections中的synchronizedList方法將其轉換成執行緒安全的容器後再使用
(這是對裝潢模式的應用,將已有物件傳入另一個類的構造器中建立新的物件來增強實現)。

79 Collection和Collections的區別?

Collection是一個介面,它是Set、List等容器的父介面;Collections是個一個工具類,
提供了一系列的靜態方法來輔助容器操作,這些方法包括對容器的搜尋、排序、執行緒安全化等等。

80 List、Map、Set三個介面存取元素時,各有什麼特點?

List以特定索引來存取元素,可以有重複元素。Set不能存放重複元素(用物件的equals()
方法來區分元素是否重複)。Map儲存鍵值對(key-value pair)對映,對映關係可以是一
對一或多對一。Set和Map容器都有基於雜湊儲存和排序樹的兩種實現版本,基於雜湊儲存的
版本理論存取時間複雜度為O(1),而基於排序樹版本的實現在插入或刪除元素時會按照元素
或元素的鍵(key)構成排序樹從而達到排序和去重的效果。

81 TreeMap和TreeSet在排序時如何比較元素?Collections工具類中的sort()方法如何比較元素?

TreeSet要求存放的物件所屬的類必須實現Comparable介面,該介面提供了比較元素的compareTo()方
法,當插入元素時會回撥該方法比較元素的大小。TreeMap要求存放的鍵值對對映的鍵必須實現Comparable
介面從而根據鍵對元素進行排序。Collections工具類的sort方法有兩種過載的形式,第一種要求傳入的
待排序容器中存放的物件比較實現Comparable介面以實現元素的比較;第二種不強制性的要求容器中
的元素必須可比較,但是要求傳入第二個引數,引數是Comparator介面的子型別(需要重寫
compare方法實現元素的比較),相當於一個臨時定義的排序規則,其實就是通過介面注入
比較元素大小的演算法,也是對回撥模式的應用(Java中對函數語言程式設計的支援)。

82 Java集合框架是什麼?說出一些集合框架的長處?

  • 每種程式語言中都有集合。最初的Java版本號包括幾種集合類:Vector、
    Stack、HashTable和Array。
  • 隨著集合的廣泛使用。Java1.2提出了囊括全部集合介面、實現和演算法的集合框架。
  • 在保證執行緒安全的情況下使用泛型和併發集合類,Java已經經歷了非常久。
    它還包括在Java併發包中,堵塞介面以及它們的實現。
  • 集合框架的部分長處例如以下:
    • 使用核心集合類減少開發成本,而非實現我們自己的集合類。
    • 隨著使用經過嚴格測試的集合框架類。程式碼質量會得到提高。
    • 通過使用JDK附帶的集合類,能夠減少程式碼維護成本。
    • 複用性和可操作性。

83 集合框架中的泛型有什麼長處?

Java1.5引入了泛型。全部的集合介面和實現都大量地使用它。泛型同意我們為集合提供
一個能夠容納的物件型別,因此。假設你加入其他型別的不論什麼元素,它會在編譯時報錯
。這避免了在執行時出現ClassCastException。由於你將會在編譯時得到報錯資訊。
泛型也使得程式碼整潔,我們不須要使用顯式轉換和instanceOf操作符。
它也給執行時帶來長處。由於不會產生型別檢查的位元組碼指令。

84 Java集合框架的基礎介面有哪些?

Collection為集合層級的根介面。
一個集合代表一組物件。這些物件即為它的元素。
Java平臺不提供這個介面不論什麼直接的實現。
Set是一個不能包括反覆元素的集合。
這個介面對數學集合抽象進行建模。被用來代表集合,就如一副牌。
List是一個有序集合。能夠包括反覆元素。
你能夠通過它的索引來訪問不論什麼元素。List更像長度動態變換的陣列。
Map是一個將key對映到value的物件.一個Map不能包括反覆的key:每一個key最多僅
僅能對映一個value。

85 為何Collection不從Cloneable和Serializable介面繼承?

Collection介面指定一組物件,物件即為它的元素。怎樣維護這些元素由Collection
的詳細實現決定。
比如。一些如List的Collection實現同意反覆的元素。而其他的如Set就不同意。
非常多Collection實現有一個公有的clone方法。
然而。把它放到集合的全部實現中也是沒有意義的。這是由於Collection是一個
抽象表現。重要的是實現。
當與詳細實現打交道的時候,克隆或序列化的語義和含義才發揮作用。所以,詳
細實現應該決定怎樣對它進行克隆或序列化,或它能否夠被克隆或序列化。
在全部的實現中授權克隆和序列化,終於導致更少的靈活性和很多其他的限制。
特定的實現應該決定它能否夠被克隆和序列化。

86 為何Map介面不繼承Collection介面

雖然Map介面和它的實現也是集合框架的一部分。但Map不是集合。集合也不是Map。
因此,Map繼承Collection毫無意義,反之亦然。
假設Map繼承Collection介面,那麼元素去哪兒?Map包括key-value對,
它提供抽取key或value列表集合的方法,可是它不適合“一組物件”規範。

87 Iterator是什麼?

Iterator介面提供遍歷不論什麼Collection的介面。
我們能夠從一個Collection中使用迭代器方法來獲取迭代器例項。迭代器代
替了Java集合框架中的Enumeration。迭代器同意呼叫者在迭代過程中移除元素。

88 Enumeration和Iterator介面的差別?

Enumeration的速度是Iterator的兩倍,也使用更少的記憶體。
Enumeration是非常基礎的,也滿足了基礎的須要。可是,與Enumeration相比,
Iterator更加安全,由於當一個集合正在被遍歷的時候。它會阻止其他執行緒去改動集合。
迭代器代替了Java集合框架中的Enumeration。
迭代器同意呼叫者從集合中移除元素,而Enumeration不能做到。
為了使它的功能更加清晰,迭代器方法名已經經過改善。

89 為何沒有像Iterator.add()這種方法。向集合中加入元素?

語義不明。已知的是,Iterator的協議不能確保迭代的次序。然而要注意。
ListIterator沒有提供一個add操作,它要確保迭代的順序。

90 Iterater和ListIterator之間有什麼差別?

  • 我們能夠使用Iterator來遍歷Set和List集合,而ListIterator僅僅能遍歷List。
  • Iterator僅僅能夠向前遍歷。而LIstIterator能夠雙向遍歷。
  • ListIterator從Iterator介面繼承,然後加入了一些額外的功能,
    比方加入一個元素、替換一個元素、獲取前面或後面元素的索引位置。

91 通過迭代器fail-fast屬性,你明確了什麼?

每次我們嘗試獲取下一個元素的時候,Iterator fail-fast屬性檢查當
前集合結構裡的不論什麼改動。假設發現不論什麼改動。它丟擲ConcurrentModificationException。
Collection中全部Iterator的實現都是按fail-fast來設計的(ConcurrentHashMap
和CopyOnWriteArrayList這類併發集合類除外)。

92 UnsupportedOperationException是什麼?

UnsupportedOperationException是用於表明操作不支援的異常。
在JDK類中已被大量運用,在集合框架java.util.Collections.UnmodifiableCollection
將會在全部add和remove操作中丟擲這個異常。

93 在Java中,HashMap是怎樣工作的?

HashMap在Map.Entry靜態內部類實現中儲存key-value對。
HashMap使用雜湊演算法。在put和get方法中。它使用hashCode()和equals()方法。
當我們通過傳遞key-value對呼叫put方法的時候。HashMap使用Key hashCode()和
雜湊演算法來找出儲存key-value對的索引。
Entry儲存在LinkedList中,所以假設存在entry。它使用equals()方法來檢查傳
遞的key是否已經存在。假設存在,它會覆蓋value。假設不存在。它會建立一個
新的entry然後儲存。
當我們通過傳遞key呼叫get方法時,它再次使用hashCode()來找到陣列中的索引,
然後使用equals()方法找出正確的Entry,然後返回它的值。下面的圖片解釋了詳細內容。
其他關於HashMap比較重要的問題是容量、負荷係數和閥值調整。HashMap預設的
初始容量是32,負荷係數是0.75。
閥值是為負荷係數乘以容量,不管何時我們嘗試加入一個entry,假設map的大小
比閥值大的時候,HashMap會對map的內容進行又一次雜湊。且使用更大的容量。
容量總是2的冪。所以假設你知道你須要儲存大量的key-value對,比方快取從資料
庫裡面拉取的資料,使用正確的容量和負荷係數對HashMap進行初始化是個不錯的做法

94 hashCode()和equals()方法有何重要性?

HashMap使用Key物件的hashCode()和equals()方法去決定key-value對的索引。
當我們試著從HashMap中獲取值的時候,這些方法也會被用到。
假設這些方法沒有被正確地實現,在這種情況下,兩個不同Key或許會產生同樣的
hashCode()和equals()輸出,HashMap將會覺得它們是同樣的,然後覆蓋它們。
而非把它們儲存到不同的地方。

95 HashMap和HashTable有何不同?

  • HashMap同意key和value為null。而HashTable不同意。
  • HashTable是同步的,而HashMap不是。所以HashMap適合單執行緒環境,
    HashTable適合多執行緒環境。
  • 在Java1.4中引入了LinkedHashMap,HashMap的一個子類,假如你想要遍歷順序,
    你非常easy從HashMap轉向LinkedHashMap,可是HashTable不是這種。
    它的順序是不可預知的。
  • HashMap提供對key的Set進行遍歷。因此它是fail-fast的。但HashTable
    提供對key的Enumeration進行遍歷,它不支援fail-fast。
  • HashTable被覺得是個遺留的類。假設你尋求在迭代的時候改動Map,
    你應該使用CocurrentHashMap。

96 怎樣決定選用HashMap還是TreeMap?

對於在Map中插入、刪除和定位元素這類操作,HashMap是最好的選擇。
然而。假如你須要對一個有序的key集合進行遍歷,TreeMap是更好的選擇。
基於你的collection的大小,或許向HashMap中加入元素會更快。將map
換為TreeMap進行有序key的遍歷。

97 ArrayList和Vector有何異同點?

  • 兩者都是基於索引的,內部由一個陣列支援。
  • 兩者維護插入的順序,我們能夠依據插入順序來獲取元素。
  • ArrayList和Vector的迭代器實現都是fail-fast的。
  • ArrayList和Vector兩者同意null值。也能夠使用索引值對元素進行隨機訪問。
  • Vector是同步的,而ArrayList不是。然而。假設你尋求在迭代的時候對
    列表進行改變。你應該使用CopyOnWriteArrayList。
  • ArrayList比Vector快。它由於有同步。不會過載。
  • ArrayList更加通用,由於我們能夠使用Collections工具類輕易地獲取
    同步列表和僅僅讀列表。

98 Array和ArrayList有何差別?什麼時候更適合用Array?

Array能夠容納基本型別和物件,而ArrayList僅僅能容納物件。
Array是指定大小的,而ArrayList大小是固定的。
Array沒有提供ArrayList那麼多功能,比方addAll、removeAll和iterator等。
雖然ArrayList明顯是更好的選擇。但也有些時候Array比較好用。

99 ArrayList和LinkedList有何差別?

  • ArrayList是由Array所支援的基於一個索引的資料結構,所以它提供對元
    素的隨機訪問。複雜度為O(1),但LinkedList儲存一系列的節點資料。每一
    個節點都與前一個和下一個節點相連線。所以。雖然有使用索引獲取元素的方
    法,內部實現是從起始點開始遍歷,遍歷到索引的節點然後返回元素。時間復
    雜度為O(n)。比ArrayList要慢。
  • 與ArrayList相比,在LinkedList中插入、加入和刪除一個元素會更快。
    由於在一個元素被插入到中間的時候,不會涉及改變陣列的大小,或更新索引。
  • LinkedList比ArrayList消耗很多其他的記憶體,由於LinkedList中的每一
    個節點儲存了前後節點的引用。

100 哪些集合類提供對元素的隨機訪問?

ArrayList、HashMap、TreeMap和HashTable類提供對元素的隨機訪問。

101 哪些集合類是執行緒安全的?

Vector、HashTable、Properties和Stack是同步類,所以它們是執行緒安全
的,能夠在多執行緒環境下使用。
Java1.5併發API包括一些集合類。同意迭代時改動,由於它們都工作在集合
的克隆上。所以它們在多執行緒環境中是安全的。

102 併發集合類是什麼?

Java1.5併發包(java.util.concurrent)包括執行緒安全集合類,同意在
迭代時改動集合。
迭代器被設計為fail-fast的,會丟擲ConcurrentModificationException。
一部分類為:CopyOnWriteArrayList、 ConcurrentHashMap、
CopyOnWriteArraySet。

103 BlockingQueue是什麼?

Java.util.concurrent.BlockingQueue是一個佇列,在進行檢索或移除一個
元素的時候,它會等待佇列變為非空;當在加入一個元素時,它會等待佇列中的可用空間。
BlockingQueue介面是Java集合框架的一部分,主要用於實現生產者-消費者模式
。我們不須要操心等待生產者有可用的空間。或消費者有可用的物件。由於它都
在BlockingQueue的實現類中被處理了。
Java提供了集中BlockingQueue的實現,比方ArrayBlockingQueue、
LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。

104 佇列和棧是什麼,列出它們的差別?

棧和佇列兩者都被用來預儲存資料。java.util.Queue是一個介面,
它的實現類在Java併發包中。佇列同意先進先出(FIFO)檢索元素,
但並不是總是這樣。Deque介面同意從兩端檢索元素。
棧與佇列非常類似,但它同意對元素進行後進先出(LIFO)進行檢索。
Stack是一個擴充套件自Vector的類,而Queue是一個介面。

105 Collections類是什麼?

Java.util.Collections是一個工具類僅包括靜態方法。它們操作或返
回集合。它包括操作集合的多型演算法,返回一個由指定集合支援的新集合
和其他一些內容。這個類包括集合框架演算法的方法,比方折半搜尋、排序、
混編和逆序等。

106 Comparable和Comparator介面是什麼?

假設我們想使用Array或Collection的排序方法時。須要在自己定義類裡
實現Java提供Comparable介面。
Comparable介面有compareTo(T OBJ)方法,它被排序方法所使用。我們
應該重寫這種方法,假設“this”物件比傳遞的物件引數更小、相等或更大
時,它返回一個負整數、0或正整數
可是。在大多數實際情況下,我們想依據不同引數進行排序。
比方。作為一個CEO。我想對僱員基於薪資進行排序。一個HR想基於年齡對
他們進行排序。這就是我們須要使用Comparator介面的情景。由於
Comparable.compareTo(Object o)方法實現僅僅能基於一個欄位進行
排序,我們不能依據物件排序的須要選擇欄位。
Comparator介面的compare(Object o1, Object o2)方法的實現須要
傳遞兩個物件引數,若第一個引數比第二個小,返回負整數;若第一個
等於第二個。返回0;若第一個比第二個大。返回正整數。

107 HashMap和HashSet區別

a. HashMap實現了Map介面,HashSet實現了Set介面
b.HashMap儲存鍵值對,HashSet儲存物件
c.HashMap呼叫put()向map中新增元素,HashSet呼叫add()像set中新增元素
d.HashMap使用Key計算hasncode,HashMap使用成員計算Hashcode

108 fail-fast 與 fail-safe 之間的區別?

Fail fast快速地報告任何的failure。無論何時任何一個問題都會
引發 fail fast系統fails· 在Java Fail fast 迭代器中,迭代objects集
合有時會出現併發修改異常,出現這種情況有2個原因· 如果一個執行緒正在迭代
一個集合,而另一個執行緒同時試圖修改這個集合· 在呼叫remove()方法後,如
何我們還試圖去修改集合object

109 是否可以往 TreeSet 或者 HashSet 中新增 null 元素?

可以往 hashset 中新增一個 null· TreeSet 也允許一個 null值

110 ArrayList集合加入1萬條資料,應該怎麼提高效率

ArrayList的預設初始容量為10,要插入大量資料的時候需要不斷擴容,而擴
容是非常影響效能的。因此,現在明確了10萬條資料了,我們可以直接在初始
化的時候就設定ArrayList的容量!
這樣就可以提高效率了~

111 HashMap中的get操作是什麼原理?

先根據key的hashcode值找到對應的連結串列,再迴圈連結串列,根據key的hash是否
相同且key的==或者equals比較操作找到對應的值

112 Java中什麼是Exception?

異常是Java傳達給你的系統和程式錯誤的方
式。在java中,異常功能是通過實現比如Throwable,Exception,
RuntimeException之類的類,然後還有一
些處理異常時候的關鍵字,比如throw,throws,try,catch,finally之
類的。 所有的異常都是通過Throwable
衍生出來的。Throwable把錯誤進一步劃分為 java.lang.Exception
和 java.lang.Error.  java.lang.Error 用
來處理系統錯誤,例如java.lang.StackOverFlowError 或者
Java.lang.OutOfMemoryError 之類的。然後
 Exception用來處理程式錯誤,請求的資源不可用等等。

113 Java中的檢查型異常和非檢查型異常有什麼區別?

這又是一個非常流行的Java異常面試題,會出現在各種層次的Java面試中。
檢查型異常和非檢查型異常的主要區別在於其處理方式。檢查型異常需要使
用try, catch和finally關鍵字在編譯期進行處理,否則會出現編譯
器會報錯。對於非檢查型異常則不需要這樣做。Java中所有繼承自
java.lang.Exception類的異常都是檢查型異常,所有繼承自
RuntimeException的異常都被稱為非檢查型異常。

114 Java中的NullPointerException和ArrayIndexOutOfBoundException之間有什麼相同之處?

在Java異常面試中這並不是一個很流行的問題,但會出現在不同層次的初
學者面試中,用來測試應聘者對檢查型異常和非檢查型異常的概念是否熟悉。
順便說一下,該題的答案是,這兩個異常都是非檢查型異常,都繼承自
RuntimeException。該問題可能會引出另一個問題,即Java和C的陣列有
什麼不同之處,因為C裡面的陣列是沒有大小限制的,絕對不會丟擲ArrayIndexOutOfBoundException。

115 在Java異常處理的過程中,你遵循的那些最好的實踐是什麼?

這個問題在面試技術經理是非常常見的一個問題。因為異常處理在專案設
計中是非常關鍵的,所以精通異常處理是十分必要的。異常處理有很多最
佳實踐,下面列舉集中,它們提高你程式碼的健壯性和靈活性:

  1. 呼叫方法的時候返回布林值來代替返回null,這樣可以 NullPointerException。
    由於空指標是java異常裡最噁心的異常。
  2. catch塊裡別不寫程式碼。空catch塊是異常處理裡的錯誤事件,因為它只是捕獲了
    異常,卻沒有任何處理或者提示。通常你起碼要列印出異常資訊,當然你最好根據需求
    對異常資訊進行處理。
    3)能拋受控異常(checked Exception)就儘量不拋受非控異常(checked Exception)。
    通過去掉重複的異常處理程式碼,可以提高程式碼的可讀性。
  3. 絕對不要讓你的資料庫相關異常顯示到客戶端。由於絕大多數資料庫和SQLException異
    常都是受控異常,在Java中,你應該在DAO層把異常資訊處理,然後返回處理過的能讓使用者看懂
    並根據異常提示資訊改正操作的異常資訊。5) 在Java中,一定要在資料庫連線,資料庫查詢,
    流處理後,在finally塊中呼叫close()方法。

116 error和exception的區別?

Error類和Exception類的父類都是Throwable類
Error類一般是指與虛擬機器相關的問題,如系統奔潰,虛擬機器錯誤,記憶體空間不足,方法呼叫
棧溢位等。錯誤導致的應用程式中斷,僅靠程式本身無法恢復和預防,遇到這樣的錯誤,建議程式終止。
Exception類表示程式可以處理的異常,可以捕獲且有可能恢復。遇到這種類異常,應儘可能
處理異常,使程式恢復執行,而不是隨意終止異常。

117 Java異常處理機制

Java對異常類進行了分類,不同型別的異常分類用不用的Java類表示,所有異常類的根
類是java.lang.Throwable,Throwable下面有兩個派生的子類Error和Exception,Error
表示應用程式本身無法克服和恢復的一種嚴重問題。Exception表示程式還能恢復和克服的
問題,其中分為系統異常和普通異常,系統異常是軟體本身缺陷導致的問題,也就是開發人
員考慮不周到所導致的問題,軟體使用者無法克服和恢復,但是這種問題下還可以讓系統運
行或者讓軟體死掉,例如,陣列下標越界(ArrayIndexOfBoundsException),空指標異常
等;普通異常是執行環境的變化或異常導致的問題,是使用者能夠克服的問題,例如,網路斷
線,硬碟空間不夠,發生這樣的異常後,程式不應該死掉。
Java為系統異常和普通異t常提供了不同的解決方案,編譯器強制普通異常必須try…catch
處理或用throws宣告繼續上拋給呼叫方法處理,所以普通異常也稱為checked異常,而系
統異常可以處理也可以不處理,所以,編譯器不強制用try…catch處理或throws宣告,所以
系統異常處理也稱為uncheched異常。

118 寫出常見的5個RuntimeException

(1)java.lang.NullPointerException空指標異常,出現原因:呼叫了未經初始化的對
性愛那個或者不存在的物件。
(2)ClassNoFoundException 指定類找不到,出現原因:類的名稱和路徑載入錯誤,通
常是試圖通過字串來載入某個類時可能引發異常。
(3)NumberFormatException字串轉換為數字異常,出現原因:字串資料中包含非
數字型字元。
(4)IndexOutOfBoundsException陣列下標越界異常
(5)IllegalArgumentException 方法傳遞引數錯誤

119 throw和throws區別

throw:
    (1)throw語句用在方法體內,表示丟擲異常,由方法體內的語句處理
    (2)throw是具體向外丟擲異常的動作,所以它丟擲的是一個異常例項,執行throw
一定是丟擲了某種異常
throws:
    (1)throws語句是用在方法宣告後面,表示如果丟擲異常,由該方法的呼叫者來進
行異常處理。
    (2)throws主要是宣告這個方法會丟擲某種型別的異常,讓它的使用者要知道需要
捕獲的異常的型別。
    (3)throws表示出現異常的一種可能性,並不一定會發生這種異常。

120 什麼是“異常鏈”?

“異常鏈”是Java中非常流行的異常處理概念,是指在進行一個異常處理時丟擲了另外一個
異常,由此產生
了一個異常鏈條。該技術大多用於將“ 受檢查異常” ( checked exception)封裝成
為“非受檢查異常”
(unchecked exception)或者RuntimeException。順便說一下,如果因為因為異常你
決定丟擲一個新的異常,
你一定要包含原有的異常,這樣,處理程式才可以通過getCause()和initCause()方法
來訪問異常最終的根源。

121 你曾經自定義實現過異常嗎?怎麼寫的?

然,我們絕大多數都寫過自定義或者業務異常,像AccountNotFoundException。在面
試過程中詢問
這個Java異常問題的主要原因是去發現你如何使用這個特性的。這可以更準確和精緻的
去處理異常,當然這也跟
你選擇checked 還是unchecked exception息息相關。通過為每一個特定的情況建立一
個特定的異常,你就為
呼叫者更好的處理異常提供了更好的選擇。相比通用異常(general exception),我
更傾向更為精確的異常。大
量的建立自定義異常會增加專案class的個數,因此,在自定義異常和通用異常之間維
持一個平衡是成功的關鍵。

122 Java異常處理中有哪些關鍵字?

throw:有時我們需要顯式地建立並丟擲異常物件來終止程式的正常執行。throw關鍵字
用來丟擲並處理執行時異常。
throws:當我們丟擲任何“被檢查的異常(checked exception)”並不處理時,需要在
方法簽名中使用關鍵字throws來告知呼叫程式此方法可能會丟擲的異常。呼叫方法可
能會處理這些異常,或者同樣用throws來將異常傳給上一級呼叫方法。throws關鍵字
後可接多個潛在異常,甚至是在main()中也可以使用throws。
try-catch:我們在程式碼中用try-catch塊處理異常。當然,一個try塊之後可以有多個
catch子句,try-catch塊也能巢狀。每個catch塊必須接受一個(且僅有一個)代表
異常型別的引數。

123 描述一下異常的層級。

Java異常是層級的,並通過繼承來區分不同種類的異常。
Throwable是所有異常的父類,它有兩個直接子物件Error,Exception,其中Exception
又被繼續劃分為“被檢查的異常(checked exception)”和”執行時的異常
(runtime exception,即不受檢查的異常)”。 Error表示編譯時和系統錯誤,
通常不能預期和恢復,比如硬體故障、JVM崩潰、記憶體不足等。
被檢查的異常(Checked exception)在程式中能預期,並要嘗試修復,
如FileNotFoundException。我們必須捕獲此類異常,併為使用者提供有用信
息和合適日誌來進行除錯。Exception是所有被檢查的異常的父類。
執行時異常(Runtime Exception)又稱為不受檢查異常,源於糟糕的程式設計。
比如我們檢索陣列元素之前必須確認陣列的長度,否則就可能會丟擲
ArrayIndexOutOfBoundException執行時異常。RuntimeException是所有執行時異常的父類。
閉,因此,我們能使用finally進行關閉。不管異常有沒有出現,finally塊總會被執行。

124 Java異常類有哪些的重要方法?

String getMessage():方法返回Throwable的String型資訊,當異常通過構造器建立後可用。
String getLocalizedMessage():此方法通過被重寫來得到用本地語言
表示的異常資訊返回給呼叫程式。Throwable類通常只是用getMessage()方法來實現返回異常資訊。
synchronized Throwable getCause():此方法返回異常產生的原因,
如果不知道原因的話返回null。(原文有拼寫錯誤 應該是if 不是id)
String toString():方法返回String格式的Throwable資訊,此資訊
包括Throwable的名字和本地化資訊。
void printStackTrace():該方法列印棧軌跡資訊到標準錯誤流。
該方法能接受PrintStream 和PrintWriter作為引數實現過載,這樣就能實現列印棧軌跡到檔案或流中。

125 Error和Exception有什麼區別?

Error表示系統級的錯誤和程式不必處理的異常,是恢復不是不可能但很困難
的情況下的一種嚴重問題;比如記憶體溢位,不可能指望程式能處理這樣的情況;
Exception表示需要捕捉或者需要程式進行處理的異常,是一種設計或實現問題;
也就是說,它表示如果程式執行正常,從不會發生的情況。

126 try{}裡有一個return語句,那麼緊跟在這個try後的finally{}裡的程式碼會不會被執行,什麼時候被執行,在return前還是後?

會執行,在方法返回撥用者前執行。

127 Java語言如何進行異常處理,關鍵字:throws、throw、try、catch、finally分別如何使用?

Java通過物件導向的方法進行異常處理,把各種不同的異常進行分類,
並提供了良好的介面。在Java中,每個異常都是一個物件,它是Throwable
類或其子類的例項。當一個方法出現異常後便丟擲一個異常物件,該物件中
包含有異常資訊,呼叫這個物件的方法可以捕獲到這個異常並可以對其進行
處理。Java的異常處理是通過5個關鍵詞來實現的:try、catch、throw、
throws和finally。一般情況下是用try來執行一段程式,如果系統會丟擲
(throw)一個異常物件,可以通過它的型別來捕獲(catch)它,或通過總
是執行程式碼塊(finally)來處理;try用來指定一塊預防所有異常的程式;
catch子句緊跟在try塊後面,用來指定你想要捕獲的異常的型別;throw語
句用來明確地丟擲一個異常;throws用來宣告一個方法可能丟擲的各種異常
(當然宣告異常時允許無病呻吟);finally為確保一段程式碼不管發生什麼異
常狀況都要被執行;try語句可以巢狀,每當遇到一個try語句,異常的結構就
會被放入異常棧中,直到所有的try語句都完成。如果下一級的try語句沒有對某
種異常進行處理,異常棧就會執行出棧操作,直到遇到有處理這種異常的try語
句或者最終將異常拋給JVM。

128 闡述final、finally、finalize的區別。

final:修飾符(關鍵字)有三種用法:如果一個類被宣告為final,意味著它
不能再派生出新的子類,即不能被繼承,因此它和abstract是反義詞。將變數聲
明為final,可以保證它們在使用中不被改變,被宣告為final的變數必須在宣告
時給定初值,而在以後的引用中只能讀取不可修改。被宣告為final的方法也同
樣只能使用,不能在子類中被重寫。- finally:通常放在try…catch…的後面構
造總是執行程式碼塊,這就意味著程式無論正常執行還是發生異常,這裡的程式碼只要
JVM不關閉都能執行,可以將釋放外部資源的程式碼寫在finally塊中。- finalize:Object
類中定義的方法,Java中允許使用finalize()方法在垃圾收集器將物件從記憶體中清除出去之
前做必要的清理工作。這個方法是由垃圾收集器在銷燬物件時呼叫的,通過重寫finalize()
方法可以整理系統資源或者執行其他清理工作。

129 什麼是位元(Bit),什麼是位元組(Byte),什麼是字元(Char),它們長度是多少,各有什麼區別

Bit最小的二進位制單位 ,是計算機的操作部分 取值0或者1Byte是計算機運算元據
的最小單位由8位bit組成 取值(-128-127)Char是使用者的可讀寫的最小單位,在Java
裡面由16位bit組成 取值(0-65535)
Bit 是最小單位 計算機 只能認識 0或者1 
8個位元組 是給計算機看的字元 是看到的東西  一個字元=二個位元組

130 什麼是流,按照傳輸的單位,分成哪兩種流,並且他們的父類叫什麼流是指資料的傳輸

位元組流,字元流 位元組流:InputStream OutputStream字元流:Reader Writer

131 流按照傳輸的方向可以分為哪兩種,分別舉例說明

輸入輸出相對於程式輸入流InputStream,輸出流OutputStream

132 OutputStream裡面的write()是什麼意思,write(byte b[], int off, int len)這個方法裡面的三個引數分別是什麼意思

write將指定位元組傳入資料來源Byte b[ ]是byte陣列b[off]是傳入的第一個
字元b[off+len-1]是傳入的最後的一個字元 len是實際長度

133 流一般需要不需要關閉,如果關閉的話在用什麼方法,一般要在那個程式碼塊裡面關閉比較好,處理流是怎麼關閉的,如果有多個流互相呼叫傳入是怎麼關閉的?

流一旦開啟就必須關閉,使用close方法放入finally語句塊中(finally 
語句一定會執行)呼叫的處理流就關閉處理流多個流互相呼叫只關閉最外層的流

134 Java中的所有的流可以分為幾大類,它們的名字是什麼,各代表什麼

分為 位元組輸入流 InputStream 位元組輸出流 OutputStream字元輸入流 Reader字
符輸出流 Writer所有流都是這四個流的子類

135 io流怎樣讀取檔案的

使用File物件獲取檔案路徑,通過字元流Reader加入檔案,使用字元快取流BufferedReader處
理Reader,再定義一個字串,迴圈遍歷出檔案。程式碼如下:
File file = new File(“d:/spring.txt”);try {Reader reader = 
new FileReader(file);BufferedReader buffered = 
new BufferedReader(reader);String data = null;
while((data = buffered.readLine())!=null){System.out.println(data);}} 
catch (FileNotFoundException e) {e.printStackTrace();} catch 
(IOException e) {e.printStackTrace();}

136  PrintStream、BufferedWriter、PrintWriter的比較?

PrintStream類的輸出功能非常強大,通常如果需要輸出文字內容,都應該將輸
出流包裝成PrintStream後進行輸出。它還提供其他兩項功能。與其他輸出流不
同,PrintStream 永遠不會丟擲 IOException;而是,異常情況僅設定可通過
checkError 方法測試的內部標誌。另外,為了自動重新整理,可以建立一個
PrintStreamBufferedWriter:將文字寫入字元輸出流,緩衝各個字元從而提
供單個字元,陣列和字串的高效寫入。通過write()方法可以將獲取到的字元
輸出,然後通過newLine()進行換行操作。BufferedWriter中的字元流必須通過
呼叫flush方法才能將其刷出去。並且BufferedWriter只能對字元流進行操作。
如果要對位元組流操作,則使用BufferedInputStream。 PrintWriter的println
方法自動新增換行,不會拋異常,若關心異常,需要呼叫checkError方法看是否有
異常發生,PrintWriter構造方法可指定引數,實現自動重新整理快取(autoflush)

137 闡述JDBC運算元據庫的步驟。

138 Statement和PreparedStatement有什麼區別?哪個效能更好?

與Statement相比,①PreparedStatement介面代表預編譯的語句,它主要的優勢在
於可以減少SQL的編譯錯誤並增加SQL的安全性(減少SQL注射攻擊的可能性);
②PreparedStatement中的SQL語句是可以帶引數的,避免了用字串連線拼接
SQL語句的麻煩和不安全;③當批量處理SQL或頻繁執行相同的查詢時,
PreparedStatement有明顯的效能上的優勢,由於資料庫可以將編譯優
化後的SQL語句快取起來,下次執行相同結構的語句時就會很快(不用再次編譯和生成執行計劃)。

139 使用JDBC運算元據庫時,如何提升讀取資料的效能?如何提升更新資料的效能?

要提升讀取資料的效能,可以指定通過結果集(ResultSet)物件的setFetchSize()
方法指定每次抓取的記錄數(典型的空間換時間策略);要提升更新資料的效能可以
使用PreparedStatement語句構建批處理,將若干SQL語句置於一個批處理中執行。

140 在進行資料庫程式設計時,連線池有什麼作用?

由於建立連線和釋放連線都有很大的開銷(尤其是資料庫伺服器不在本地時,每
次建立連線都需要進行TCP的三次握手,釋放連線需要進行TCP四次握手,造成的
開銷是不可忽視的),為了提升系統訪問資料庫的效能,可以事先建立若干連線
置於連線池中,需要時直接從連線池獲取,使用結束時歸還連線池而不必關閉連線
,從而避免頻繁建立和釋放連線所造成的開銷,這是典型的用空間換取時間的策
略(浪費了空間儲存連線,但節省了建立和釋放連線的時間)。池化技術在Java
開發中是很常見的,在使用執行緒時建立執行緒池的道理與此相同。基於Java的開源
資料庫連線池主要有:C3P0、Proxool、DBCP、BoneCP、Druid等

141 什麼是DAO模式?

DAO(Data Access Object)顧名思義是一個為資料庫或其他持久化機制提供了
抽象介面的物件,在不暴露底層持久化方案實現細節的前提下提供了各種資料訪問
操作。在實際的開發中,應該將所有對資料來源的訪問操作進行抽象化後封裝在一個
公共API中。用程式設計語言來說,就是建立一個介面,介面中定義了此應用程式
中將會用到的所有事務方法。在這個應用程式中,當需要和資料來源進行互動的時候
則使用這個介面,並且編寫一個單獨的類來實現這個介面,在邏輯上該類對應一個
特定的資料儲存。DAO模式實際上包含了兩個模式,一是Data Accessor(資料訪
問器),二是Data Object(資料物件),前者要解決如何訪問資料的問題,而後
者要解決的是如何用物件封裝資料。

142 事務的ACID是指什麼

原子性(Atomic):事務中各項操作,要麼全做要麼全不做,任何一項操作的失
敗都會導致整個事務的失敗;- 一致性(Consistent):事務結束後系統狀態是
一致的;- 隔離性(Isolated):併發執行的事務彼此無法看到對方的中間
狀態;- 永續性(Durable):事務完成後所做的改動都會被持久化,即使發
生災難性的失敗。通過日誌和同步備份可以在故障發生後重建資料。

143 髒讀

A事務讀取B事務尚未提交的資料並在此基礎上操作,而B事務執行回滾,那
麼A讀取到的資料就是髒資料。

144 不可重複讀

事務A重新讀取前面讀取過的資料,發現該資料已經被另一個已提交的事務
B修改過了。

145 幻讀

事務A重新執行一個查詢,返回一系列符合查詢條件的行,發現其中插入了被
事務B提交的行。

146 第1類丟失更新

事務A撤銷時,把已經提交的事務B的更新資料覆蓋了

147 第2類丟失更新

事務A覆蓋事務B已經提交的資料,造成事務B所做的操作丟失

148 JDBC中如何進行事務處理?

Connection提供了事務處理的方法,通過呼叫setAutoCommit(false)可以
設定手動提交事務;當事務完成後用commit()顯式提交事務;如果在事務處理
過程中發生異常則通過rollback()進行事務回滾。除此之外,從JDBC 3.0中還引
入了Savepoint(儲存點)的概念,允許通過程式碼設定儲存點並讓事務回滾到指定的儲存點。

149 JDBC能否處理Blob和Clob?

Blob是指二進位制大物件(Binary Large Object),而Clob是指大字元對
象(Character Large Objec),因此其中Blob是為儲存大的二進位制資料
而設計的,而Clob是為儲存大的文字資料而設計的。JDBC的PreparedStatement
和ResultSet都提供了相應的方法來支援Blob和Clob操作。

150 Java 中,編寫多執行緒程式的時候你會遵循哪些最佳實踐?

a)給執行緒命名,這樣可以幫助除錯。b)最小化同步的範圍,而不是將整個方法
同步,只對關鍵部分做同步。c)如果可以,更偏向於使用 volatile 而不
是 synchronized。d)使用更高層次的併發工具,而不是使用 wait() 和 notify() 來
實現執行緒間通訊,如 BlockingQueue,CountDownLatch 及 Semeaphore。e)優先使用
併發集合,而不是對集合進行同步。併發集合提供更好的可擴充套件性。

151 說出幾點 Java 中使用 Collections 的最佳實踐

a)使用正確的集合類,例如,如果不需要同步列表,使用 ArrayList 而不是 Vector。b)優
先使用併發集合,而不是對集合進行同步。併發集合提供更好的可擴充套件性。c)使用介面代表和
訪問集合,如使用List儲存 ArrayList,使用 Map 儲存 HashMap 等等。d)使用迭代器來循
環集合。e)使用集合的時候使用泛型。

152 說出至少 5 點在 Java 中使用執行緒的最佳實踐。

a)對執行緒命名b)將執行緒和任務分離,使用執行緒池執行器來執行 Runnable 或 Callable。c)使用執行緒池

153 說出 5 條 IO 的最佳實踐

a)使用有緩衝區的 IO 類,而不要單獨讀取位元組或字元。b)使用 NIO 和 NIO2c)在 finally
塊中關閉流,或者使用 try-with-resource 語句。d)使用記憶體對映檔案獲取更快的 IO。

154 列出 5 個應該遵循的 JDBC 最佳實踐

a)使用批量的操作來插入和更新資料b)使用 PreparedStatement 來避免 SQL 異常,並
提高效能。c)使用資料庫連線池d)通過列名來獲取結果集,不要使用列的下標來獲取。

155 在多執行緒環境下,SimpleDateFormat 是執行緒安全的嗎?

不是,非常不幸,DateFormat 的所有實現,包括 SimpleDateFormat 都不是執行緒安全
的,因此你不應該在多執行緒序中使用,除非是在對外執行緒安全的環境中使用,如
將 SimpleDateFormat 限制在 ThreadLocal 中。如果你不這麼做,在解析或
者格式化日期的時候,可能會獲取到一個不正確的結果。因此,從日期、時間處理的
所有實踐來說,我強力推薦 joda-time 庫。

156 Java 中如何格式化一個日期?如格式化為 ddMMyyyy 的形式?

Java 中,可以使用 SimpleDateFormat 類或者 joda-time 庫來格式日期。DateFormat 類
允許你使用多種流行的格式來格式化日期。參見答案中的示例程式碼,程式碼中演示了將日期格式化
成不同的格式,如 dd-MM-yyyy 或 ddMMyyyy。

157 巢狀靜態類與頂級類有什麼區別?

一個公共的頂級類的原始檔名稱與類名相同,而巢狀靜態類沒有這個要求。一個巢狀類位於頂
級類內部,需要使用頂級類的名稱來引用巢狀靜態類,如 HashMap.Entry 是一個巢狀靜態
類,HashMap 是一個頂級類,Entry是一個巢狀靜態類。

158 Java 中,Serializable 與 Externalizable 的區別?

Serializable 介面是一個序列化 Java 類的介面,以便於它們可以在網路上傳輸或者可
以將它們的狀態儲存在磁碟上,是 JVM 內嵌的預設序列化方式,成本高、脆弱而且
不安全。Externalizable 允許你控制整個序列化過程,指定特定的二進位制格式,增加安全機制。

159 Java 中,DOM 和 SAX 解析器有什麼不同?

DOM 解析器將整個 XML 文件載入到記憶體來建立一棵 DOM 模型樹,這樣可以更快的查
找節點和修改 XML 結構,而 SAX 解析器是一個基於事件的解析器,不會將整個 XML 文
檔載入到記憶體。由於這個原因,DOM 比 SAX 更快,也要求更多的記憶體,不適合於解析大 XML 檔案。

160 說出 JDK 1.7 中的三個新特性?

雖然 JDK 1.7 不像 JDK 5 和 8 一樣的大版本,但是,還是有很多新的
特性,如 try-with-resource 語句,這樣你在使用流或者資源的時候,就不需
要手動關閉,Java 會自動關閉。Fork-Join 池某種程度上實現 Java 版的 Map-reduce。允
許 Switch 中有 String 變數和文字。菱形操作符(<>)用於型別推斷,不再需要在變數聲
明的右邊申明泛型,因此可以寫出可讀寫更強、更簡潔的程式碼。另一個值得一提的特性是
改善異常處理,如允許在同一個 catch 塊中捕獲多個異常。

161 說出 5 個 JDK 1.8 引入的新特性?

Java 8 在 Java 歷史上是一個開創新的版本,下面 JDK 8 中 5 個主要的特
性:Lambda 表示式,允許像物件一樣傳遞匿名函式Stream API,充分利用現代多
核 CPU,可以寫出很簡潔的程式碼Date 與 Time API,最終,有一個穩定、簡單
的日期和時間庫可供你使用擴充套件方法,現在,介面中可以有靜態、預設方法。重複
註解,現在你可以將相同的註解在同一型別上使用多次。

162 a==b”和”a.equals(b)”有什麼區別?

如果 a 和 b 都是物件,則 a==b 是比較兩個物件的引用,只有當 a 和 b 指向的
是堆中的同一個物件才會返回 true,而 a.equals(b) 是進行邏輯比較,所以通常需
要重寫該方法來提供邏輯一致性的比較。例如,String 類重寫 equals() 方法,所
以可以用於兩個不同物件,但是包含的字母相同的比較。

163 a.hashCode() 有什麼用?與 a.equals(b) 有什麼關係?

hashCode() 方法是相應物件整型的 hash 值。它常用於基於 hash 的集合類,
如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關係特別
緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的物件,必須具有相
同的 hash code。

164 JVM為什麼可以跨平臺

JVM能跨計算機體系結構(作業系統)來執行Java位元組碼(JVM位元組碼指令集),屏
蔽可與各個計算機平臺相關的軟體或者硬體之間的差異,使得與平臺相關的耦合統一
由JVM提供者來實現。
指令集:計算機所能識別的機器語言的命令集合。
每個執行中的Java程式都是一個JVM例項

165 描述JVM體系結構

(1)類載入器:JVM啟動時或者類執行時將需要的class載入到JVM中。每個被裝載的
類的型別對應一個Class例項,唯一表示該類,存於堆中。
(2)執行引擎:負責執行JVM的位元組碼指令(CPU)。執行引擎是JVM的核心部分,作
用是解析位元組碼指令,得到執行結果(實現方式:直接執行,JIT(just in time)
即時編譯轉成原生程式碼執行,暫存器晶片模式執行,基於棧執行)。本質上就是一個
個方法串起來的流程。每個Java執行緒就是一個執行引擎的例項,一個JVM例項中會有
多個執行引擎在工作,有的執行使用者程式,有的執行JVM內部程式(GC).
(3)記憶體區:模擬物理機的儲存、記錄和排程等功能模組,如暫存器或者PC指標記錄器
。儲存執行引擎執行時所需要儲存的資料。
(4)本地方法介面:呼叫作業系統本地方法返回結果。

166 描述JVM工作機制

機器如何執行程式碼:原始碼-前處理器-編譯器-彙編程式-目的碼-連結器-可執行程
序。
Java編譯器將高階語言編譯成虛擬機器目標語言。
JVM執行位元組碼指令是基於棧的架構,所有的運算元必須先入棧,然後根據操作碼選擇
從棧頂彈出若干元素進行計算後將結果壓入棧中。
通過Java編譯器將原始碼編譯成虛擬機器目標語言,然後通過JVM執行引擎執行。

167 為何JVM位元組碼指令選擇基於棧的結構

JVM要設計成平臺無關性,很難設計統一的基於暫存器的指令。
為了指令的緊湊性,讓編譯後的class檔案更加緊湊,提高位元組碼在網路上的傳輸效率

168 描述執行引擎的架構設計

建立新執行緒時,JVM會為這個執行緒建立一個棧,同時分配一個PC暫存器(指向第一行可
執行的程式碼)。呼叫新方法時會在這個棧上建立新的棧幀資料結構。執行完成後方法對
應的棧幀將消失,PC暫存器被銷燬,區域性變數區所有值被釋放,被JVM回收。

169 描述javac編譯器的基本結構

Javac編譯器的作用是將符合Java語言規範的的原始碼轉換成JVM規範的Java位元組碼。
(1)詞法分析器元件:找出規範化的Token流
(2)語法分析器元件:生成符合Java語言規範的抽象語法樹
(3)語義分析器元件:將複雜的語法轉化成最簡單的語法,註解語法樹
(4)程式碼生成器元件:將語法樹資料結構轉化成位元組碼資料結構

170 ClassLoader(類載入器)有哪些

1)Bootstrap ClassLoader(啟動類載入器):完全由JVM控制,載入JVM自身工作需要
的類(JAVA_HOME/lib)
(2)Extension ClassLoader(擴充套件類載入器):屬於JVM自身一部分,不是JVM自身實
現的(JAVA_HOME/lib/ext)
(3)Appclication ClassLoader(應用程式類載入器):父類是Extension ClassLoader,
載入Classpath(使用者類路徑)上的類庫

171 描述ClassLoader的作用(什麼是類載入器)和載入過程

將Class檔案載入到JVM中、審查每個類由誰載入(父優先的等級載入機制)、將Class字
節碼重新解析成JVM統一要求的物件(Class物件)格式。
.class->findclass->Liking:Class規範驗證、準備、解析->類屬性初始化賦值
(static塊的執行)->Class物件(這也就是為什麼靜態塊只執行一次)

172 描述JVM類載入機制

ClassLoader首先不會自己嘗試去載入類,而是把這個請求委託給父類載入器完成,
每一個層次都是。只有當父載入器反饋無法完成請求時(在搜尋範圍內沒有找到所需
的類),子載入器才會嘗試載入(等級載入機制、父優先、雙親委派)。
好處:類隨著它的載入器一起具有一種帶有優先順序的層次關係;保證同一個類只能
被一個載入器載入。

173 JVM載入class檔案到記憶體的兩種方式

(1)隱式載入:繼承或者引用的類不在記憶體中
(2)顯式載入:程式碼中通過呼叫ClassLoader載入

174 載入類錯誤分析及其解決

1)ClassNotFoundException:沒有找到對應的位元組碼(.class)檔案;檢查
classpath下有無對應檔案
(2)NoClassDefFoundError:隱式載入時沒有找到,ClassNotFoundException引
發NoClassDefFoundError;確保每個類引用的類都在classpath下
(3)UnsatisfiedLinkError:(未滿足連結錯誤)刪除了JVM的某個lib檔案或者解
析native標識的方法時找不到對應的本地庫檔案
(4)ClassCastException:強制型別轉換時出現這個錯誤;容器型別最好顯示指明其
所包含物件型別、先instanceof檢查是不是目標型別,再型別轉換
(5)ExceptionInitializerError:給類的靜態屬性賦值時

175 Java應不應該動態載入類(JVM能不能動態載入類)

JVM中物件只有一份,不能被替換,物件的引用關係只有物件的建立者持有和使用,
JVM不可干預物件的引用關係,因為JVM不知道物件是怎麼被使用的,JVM不知道物件
的執行時型別,只知道編譯時型別。
但是可以不儲存物件的狀態,物件建立和使用後就被釋放掉,下次修改後,物件就是
新的了(JSP)。

176 Java中哪些元件需要使用記憶體

(1)Java堆:儲存Java物件
(2)執行緒:Java執行程式的實體
(3)類和類載入器:儲存在堆中,這部分割槽域叫永久代(PermGen區)
(4)NIO:基於通道和緩衝區來執行I/O的新方式。
(5)JNI:原生程式碼可以呼叫Java方法,Java方法也可以呼叫原生程式碼

177 描述JVM記憶體結構及記憶體溢位

JVM是按照執行時資料的儲存結構來劃分記憶體結構的。
PC暫存器資料:嚴格來說是一個資料結構,儲存當前正在執行的程式的記憶體地址。
為了執行緒切換後能恢復到正確的執行位置,執行緒私有。不會記憶體溢位。
(1)Java棧:方法執行的記憶體模型,儲存執行緒執行所需要的資料。執行緒私有。
–OutOfMemoryError:JVM擴充套件棧時無法申請到足夠的空間。一個不斷呼叫自身而
不會終止的方法。
–StackOverflowError:請求的棧深度大於JVM所允許的棧深度。建立足夠多的執行緒。
(2)堆:儲存物件,每一個存在堆中Java物件都是這個物件的類的副本,複製包括
繼承自他父類的所有非靜態屬性。執行緒共享。
–OutOfMemoryError:物件數量到達堆容量限制。可通過不斷向ArrayList中新增
物件實現。

178 描述JVM記憶體結構及記憶體溢位

(3)方法區:儲存類結構資訊。包括常量池(編譯期生產的各種字面量和符號引用)
和執行時常量池。執行緒共享。
–OutOfMemoryError:同執行時常量池。
(4)本地方法棧:與Java棧類似,為JVM執行Native方法準備的空間。執行緒私有。
(C棧)OutOfMemoryError和StackOverflowError同JVM棧。
(5)執行時常量池:代表執行時每個class檔案中的常量表。執行期間產生的新的常
量放入執行時常量池。
–OutOfMemoryError:不斷向List中新增字串,然後String.inern(),
PermGen Space(執行時常量池屬於方法區)。
(6)本地直接記憶體:即NIO。
–OutOfMemoryError:通過直接向作業系統申請分配記憶體。

179 描述JVM記憶體分配策略

(1)物件優先分配在Eden
(2)大物件直接進入老年代
(3)長期存活的物件將進入老年代
(4)倖存區相同年齡物件的佔倖存區空間的多於其一半,將進入老年代
(5)空間擔保分配(老年代剩餘空間需多於倖存區的一半,否則要Full GC)

180 描述JVM如何檢測垃圾

通過可達性分析演算法,通過一些列稱為GC Roots的物件作為起始點,從這些起始
點向下搜尋,搜尋所走過的路徑稱為引用鏈,當一個物件到GC Roots沒有任何引
用鏈相連(GC Roots到這個物件不可達),則證明這個物件是不可用的。
使用可達性分析演算法而不是引用計數演算法。因為引用計數演算法很難解決物件之間相
互迴圈引用的問題。

181 哪些元素可作為GC Roots

(1)JVM棧(棧幀中的本地變數表)中的引用
(2)方法區中類靜態屬性引用
(3)方法區中常量引用
(4)本地方法棧中JNI(一般的Native方法)引用

182 描述分代垃圾收集演算法的思路

把物件按照壽命長短來分組,分為年輕代和老年代,新建立的在老年代,經歷幾次
回收後仍然存活的物件進入老年代,老年代的垃圾頻率不像年輕代那樣頻繁,減少
每次收集都去掃描所有物件的數量,提高垃圾回收效率。

183 描述基於分代的堆結構及其比例

(1)年輕代(Young區-1/4):Eden+Survior(1/8,這個比例保證只有10%的空間被
浪費,保證每次回收都只有不多於10%的物件存活)=From+To,存放新建立的物件.
(2)老年代(Old區 ):存放幾次垃圾收集後存活的物件
(3)永久區(Perm區):存放類的Class物件

184 描述垃圾收集演算法

1)標記-清除演算法:首先標記處所要回收的物件,標記完成後統一清除。缺點:標記
效率低,清除效率低,回收結束後會產生大量不連續的記憶體碎片(沒有足夠連續空間
分配記憶體,提前觸發另一次垃圾回收)。適用於物件存活率高的老年代。
(2)複製演算法(Survivor的from和to區,from和to會互換角色):
將記憶體容量劃分大小相等的兩塊,每次只使用其中一塊。一塊用完,就將存活的物件
複製到另一塊,然後把使用過的一塊一次清除。不用考慮記憶體碎片,每次只要移動頂
端指標,按順序分配記憶體即可,實現簡單執行高效。適用於新生代。
缺點:記憶體縮小為原來的一般,代價高。浪費50%的空間。
(3)標記-整理演算法:
標記完成後,將存活的物件移動到一端,然後清除邊界以外的記憶體。適用於物件存活
率高的老年代。

185 描述新生代和老年代的回收策略

Eden區滿後觸發minor GC,將所有存活物件複製到一個Survivor區,另一Survivor
區存活的物件也複製到這個Survivor區中,始終保證有一個Survivor是空的。
Toung區Survivor滿後觸發minor GC後仍然存活的物件存到Old區,如果Survivor
區放不下Eden區的物件或者Survivor區物件足夠老了,直接放入Old區,如果Old
區放不下則觸發Full GC。
Perm區滿將觸發Major GC。

186 描述CMS垃圾收集器

CMS 收集器:Concurrent Mark Sweep 併發標記-清除。重視響應速度,適用於互
聯網和B/S系統的服務端上。初始標記還是需要Stop the world 但是速度很快。缺
點:CPU資源敏感,無法浮動處理垃圾,會有大量空間碎片產生。

187 MySQL的複製原理以及流程

基本原理流程,3個執行緒以及之間的關聯;

  1. 主:binlog執行緒——記錄下所有改變了資料庫資料的語句,放進master上的binlog中;
  2. 從:io執行緒——在使用start slave 之後,負責從master上拉取 binlog 內
    容,放進 自己的relay log中;
  3. 從:sql執行執行緒——執行relay log中的語句;

188 MySQL中myisam與innodb的區別

1>.InnoDB支援事物,而MyISAM不支援事物
2>.InnoDB支援行級鎖,而MyISAM支援表級鎖
3>.InnoDB支援MVCC, 而MyISAM不支援
4>.InnoDB支援外來鍵,而MyISAM不支援
5>.InnoDB不支援全文索引,而MyISAM支援。

189 innodb引擎的4大特性

插入緩衝(insert buffer),二次寫(double write),自適應雜湊索引(ahi),預讀(read ahead)

190 MySQL中varchar與char的區別以及varchar(50)中的50代表的涵義

1)、varchar與char的區別char是一種固定長度的型別,varchar則是一種可變
長度的型別(2)、varchar(50)中50的涵義最多存放50個字元,varchar(50)和
(200)儲存hello所佔空間一樣,但後者在排序時會消耗更多記憶體,因為order by col採
用fixed_length計算col長度(memory引擎也一樣)(3)、int(20)中20的涵義是指顯
示字元的長度但要加引數的,最大為255,比如它是記錄行數的id,插入10筆資料,它
就顯示00000000001 ~~~00000000010,當字元的位數超過11,它也只顯示11位,如果
你沒有加那個讓它未滿11位就前面加0的引數,它不會在前面加020表示最大顯示寬度為
20,但仍佔4位元組儲存,儲存範圍不變;(4)、mysql為什麼這麼設計對大多數應用沒有
意義,只是規定一些工具用來顯示字元的個數;int(1)和int(20)儲存和計算均一樣

191 innodb有多少種日誌

錯誤日誌:記錄出錯資訊,也記錄一些警告資訊或者正確的資訊。查詢日誌:記錄所
有對資料庫請求的資訊,不論這些請求是否得到了正確的執行。慢查詢日誌:設定一個
閾值,將執行時間超過該值的所有SQL語句都記錄到慢查詢的日誌檔案中。二進位制日誌:記錄
對資料庫執行更改的所有操作。中繼日誌:事務日誌

192 事物的4種隔離級別

隔離級別讀未提交(RU)讀已提交(RC)可重複讀(RR)序列

193 如何設計一個高併發的系統

  • 資料庫的優化,包括合理的事務隔離級別、SQL語句優化、索引的優化
  • 使用快取,儘量減少資料庫 IO
  • 分散式資料庫、分散式快取
  • 伺服器的負載均衡

194 鎖的優化策略

  • 讀寫分離
  • 分段加鎖
  • 減少鎖持有的時間
  • 多個執行緒儘量以相同的順序去獲取資源

195 索引的底層實現原理和優化

B+樹,經過優化的B+樹
主要是在所有的葉子結點中增加了指向下一個葉子節點的指標,因此InnoDB建議為大部
分表使用預設自增的主鍵作為主索引。

196 什麼情況下設定了索引但無法使用

  • 以“%”開頭的LIKE語句,模糊匹配
  • OR語句前後沒有同時使用索引
  • 資料型別出現隱式轉化(如varchar不加單引號的話可能會自動轉換為int型)

197 實踐中如何優化MySQL

  • SQL語句及索引的優化
  • 資料庫表結構的優化
  • 系統配置的優化
  • 硬體的優化

198 簡單描述mysql中,索引,主鍵,唯一索引,聯合索引的區別,對資料庫的效能有什麼影響

索引是一種特殊的檔案(InnoDB資料表上的索引是表空間的一個組成部分),它們包含著
對資料表裡所有記錄的引用指標。普通索引(由關鍵字KEY或INDEX定義的索引)的唯一任
務是加快對資料的訪問速度。普通索引允許被索引的資料列包含重複的值。如果能確定
某個資料列將只包含彼此各不相同的值,在為這個資料列建立索引的時候就應該用關鍵字
UNIQUE把它定義為一個唯一索引。也就是說,唯一索引可以保證資料記錄的唯一性。主
鍵,是一種特殊的唯一索引,在一張表中只能定義一個主鍵索引,主鍵用於唯一標識一條
記錄,使用關鍵字PRIMARY KEY 來建立。索引可以覆蓋多個資料列,如像
INDEX(columnA, columnB)索引,這就是聯合索引。索引可以極大的提高資料的
查詢速度,但是會降低插入、刪除、更新表的速度,因為在執行這些寫操作時,還要操作
索引檔案

199 資料庫中的事務是什麼?

事務(transaction)是作為一個單元的一組有序的資料庫操作。如果組中的所有操作都
成功,則認為事務成功,即使只有一個操作失敗,事務也不成功。如果所有操作完成,事
務則提交,其修改將作用於所有其他資料庫程式。如果一個操作失敗,則事務將回滾,該
事務所有操作的影響都將取消。ACID 四大特性,原子性、隔離性、一致性、永續性

200 瞭解XSS攻擊嗎?如何防止?

XSS是跨站指令碼攻擊,首先是利用跨站指令碼漏洞以一個特權模式去執行攻擊者構造的腳
本,然後利用不安全的Activex控制元件執行惡意的行為。使用htmlspecialchars()函式
對提交的內容進行過濾,使字串裡面的特殊符號實體化

201 SQL隱碼攻擊漏洞產生的原因?如何防止

SQL隱碼攻擊產生的原因:程式開發過程中不注意規範書寫sql語句和對特殊字元進行過濾,
導致客戶端可以通過全域性變數POST和GET提交一些sql語句正常執行。
防止SQL隱碼攻擊的方式:
開啟配置檔案中的magic_quotes_gpc 和 magic_quotes_runtime設定
執行sql語句時使用addslashes進行sql語句轉換
Sql語句書寫儘量不要省略雙引號和單引號。
過濾掉sql語句中的一些關鍵詞:update、insert、delete、select、 * 。
提高資料庫表和欄位的命名技巧,對一些重要的欄位根據程式的特點命名,取不易被猜到的。
Php配置檔案中設定register_globals為off,關閉全域性變數註冊
控制錯誤資訊,不要在瀏覽器上輸出錯誤資訊,將錯誤資訊寫到日誌檔案中

202 解釋MySQL外連線、內連線與自連線的區別

先說什麼是交叉連線: 交叉連線又叫笛卡爾積,它是指不使用任何條件,直接將一個表的
所有記錄和另一個表中的所有記錄一一匹配。
內連線 則是隻有條件的交叉連線,根據某個條件篩選出符合條件的記錄,不符合條件的記
錄不會出現在結果集中,即內連線只連線匹配的行。外連線 其結果集中不僅包含符合連
接條件的行,而且還會包括左表、右表或兩個表中的所有資料行,這三種情況依次稱之為左
外連線,右外連線,和全外連線。
左外連線,也稱左連線,左表為主表,左表中的所有記錄都會出現在結果集中,對於那些
在右表中並沒有匹配的記錄,仍然要顯示,右邊對應的那些欄位值以NULL來填充。右外連
接,也稱右連線,右表為主表,右表中的所有記錄都會出現在結果集中。左連線和右連線可
以互換,MySQL目前還不支援全外連線

203 Myql中的事務回滾機制概述

事務是使用者定義的一個資料庫操作序列,這些操作要麼全做要麼全不做,是一個不可分割的工
作單位,事務回滾是指將該事務已經完成的對資料庫的更新操作撤銷。
要同時修改資料庫中兩個不同表時,如果它們不是一個事務的話,當第一個表修改完,可能
第二個表修改過程中出現了異常而沒能修改,此時就只有第二個表依舊是未修改之前的狀
態,而第一個表已經被修改完畢。而當你把它們設定為一個事務的時候,當第一個表修改
完,第二表修改出現異常而沒能修改,第一個表和第二個表都要回到未修改的狀態,這就
是所謂的事務回滾

204 什麼是儲存過程?用什麼來呼叫?

儲存過程是一個預編譯的SQL語句,優點是允許模組化的設計,就是說只需建立一次,以後
在該程式中就可以呼叫多次。如果某次操作需要執行多次SQL,使用儲存過程比單純SQL語
句執行要快。可以用一個命令物件來呼叫儲存過程

205 MySQL資料庫作釋出系統的儲存,一天五萬條以上的增量,預計運維三年,怎麼優化?

a. 設計良好的資料庫結構,允許部分資料冗餘,儘量避免join查詢,提高效率。
b. 選擇合適的表欄位資料型別和儲存引擎,適當的新增索引。
c. mysql庫主從讀寫分離。
d. 找規律分表,減少單表中的資料量提高查詢速度。
e。新增快取機制,比如memcached,apc等。
f. 不經常改動的頁面,生成靜態頁面。
g. 書寫高效率的SQL。比如 SELECT * FROM TABEL 改為 SELECT field_1,
field_2, field_3 FROM TABLE.

206  對於大流量的網站,您採用什麼樣的方法來解決各頁面訪問量統計問題

a. 確認伺服器是否能支撐當前訪問量。
b. 優化資料庫訪問。
c. 禁止外部訪問連結(盜鏈), 比如圖片盜鏈。
d. 控制檔案下載。
e. 使用不同主機分流。
f. 使用瀏覽統計軟體,瞭解訪問量,有針對性的進行優化。

207 儲存時期

Datatime:以 YYYY-MM-DD HH:MM:SS 格式儲存時期時間,精確到秒,佔用8個位元組
得儲存空間,datatime型別與時區無關
Timestamp:以時間戳格式儲存,佔用4個位元組,範圍小1970-1-1到2038-1-19,顯示
依賴於所指定得時區,預設在第一個列行的資料修改時可以自動得修改timestamp列得值
Date:(生日)佔用得位元組數比使用字串.datatime.int儲存要少,使用date只需
要3個位元組,儲存日期月份,還可以利用日期時間函式進行日期間得計算
Time:儲存時間部分得資料
注意:不要使用字串型別來儲存日期時間資料(通常比字串佔用得儲存空間小,
在進行查詢過濾可以利用日期得函式)
使用int儲存日期時間不如使用timestamp型別

208 Hibernate工作原理

1.讀取並解析配置檔案 2.讀取並解析對映資訊,建立SessionFactory 3.開啟
Sesssion 4.建立事務Transation 5.持久化操作 6.提交事務 7.關閉Session 
8.關閉SesstionFactory (finally進行執行)

209 Hibernate中get和load有什麼不同之處

把get和load放到一起進行對比是Hibernate面試時最常問到的問題,這是因為只有
正確理解get()和load()這二者後才有可能高效地使用Hibernate。get和load的最
大區別是,如果在快取中沒有找到相應的物件,get將會直接訪問資料庫並返回一個
完全初始化好的物件,而這個過程有可能會涉及到多個資料庫呼叫;而load方法在緩
存中沒有發現物件的情況下,只會返回一個代理物件,只有在物件getId()之外的其它
方法被呼叫時才會真正去訪問資料庫,這樣就能在某些情況下大幅度提高效能

210 Hibernate中save、persist和saveOrUpdate這三個方法的不同之處

除了get和load,這又是另外一個經常出現的Hibernate面試問題。 所有這三個方法,
也就是save()、saveOrUpdate()和persist()都是用於將物件儲存到資料庫中的方法,
但其中有些細微的差別。例如,save()只能INSERT記錄,但是saveOrUpdate()可以
進行 記錄的INSERT和UPDATE。還有,save()的返回值是一個Serializable物件,
而persist()方法返回值為void

211 Hibernate中的命名SQL查詢指的是什麼

Hibernate的這個面試問題同Hibernate提供的查詢功能相關。命名查詢指的是
用標籤在影射文件中定義的SQL查詢,可以通過使用Session.getNamedQuery()
方法對它進行呼叫。命名查詢使你可以使用你所指定的一個名字拿到某個特定的查詢。
Hibernate中的命名查詢可以使用註解來定義,也可以使用我前面提到的xml影射問句
來定義。在Hibernate中,@NameQuery用來定義單個的命名查詢,@NameQueries用來定義多個命名查詢。

212 Hibernate中的SessionFactory有什麼作用? SessionFactory是執行緒安全的嗎

這也是Hibernate框架的常見面試問題。顧名思義,SessionFactory就是一個用於
建立Hibernate的Session物件的工廠。SessionFactory通常是在應用啟動時建立
好的,應用程式中的程式碼用它來獲得Session物件。作為一個單個的資料儲存,它也
是 執行緒安全的,所以多個執行緒可同時使用同一個SessionFactory。Java JEE應用
一般只有一個SessionFactory,服務於客戶請求的各執行緒都通過這個工廠來獲得
Hibernate的Session例項,這也是為什麼SessionFactory介面的實現必須是線
程安全的原因。還有,SessionFactory的內部狀態包含著同物件關係影射有關的所
有後設資料,它是 不可變的,一旦建立好後就不能對其進行修改了。

213 Hibernate中的Session指的是什麼? 可否將單個的Session在多個執行緒間進行共享

前面的問題問完之後,通常就會接著再問這兩個問題。問完SessionFactory的問題
後就該輪到Session了。Session代表著Hibernate所做的一小部分工作,它負責維
護者同資料庫的連結而且 不是執行緒安全的,也就是說,Hibernage中的Session不能
在多個執行緒間進行共享。雖然Session會以主動滯後的方式獲得資料庫連線,但是
Session最好還是在用完之後立即將其關閉。

214 hibernate中sorted collection和ordered collection有什麼不同

Hibernate中,物件具有三種狀態:transient、persistent和detached。同
Hibernate的session有關聯的物件是persistent物件。對這種物件進行的所有
修改都會按照事先設定的重新整理策略,反映到資料庫之中,也即,可以在物件的任何
一個屬性發生改變時自動重新整理,也可以通過呼叫Session.flush()方法顯式地進行
重新整理。如果一個物件原來同Session有關聯關係,但當下卻沒有關聯關係了,這樣的
物件就是detached的物件。你可以通過呼叫任意一個session的update()或者
saveOrUpdate()方法,重新將該detached物件同相應的seesion建立關聯關係。
Transient物件指的是新建的持久化類的例項,它還從未同Hibernate的任何
Session有過關聯關係。同樣的,你可以呼叫persist()或者save()方法,將
transient物件變成persistent物件

215 Hibernate中Session的lock()方法有什麼作用

這是一個比較棘手的Hibernate面試問題,因為Session的lock()方法重建了關聯
關係卻並沒有同資料庫進行同步和更新。因此,你在使用lock()方法時一定要多加
小心。順便說一下,在進行關聯關係重建時,你可以隨時使用Session的update()
方法同資料庫進行同步。有時這個問題也可以這麼來問:Session的lock()方法和
update()方法之間有什麼區別?。這個小節中的關鍵點也可以拿來回答這個問題。

216 Hibernate中二級快取指的是什麼

這是同Hibernate的快取機制相關的第一個面試問題,不出意外後面還會有更多這方
面的問題。二級快取是在SessionFactory這個級別維護的快取,它能夠通過節省幾
番資料庫呼叫往返來提高效能。還有一點值得注意,二級快取是針對整個應用而不是
某個特定的session的。

217 Hibernate中的查詢快取指的是什麼

這個問題有時是作為上個Hibernate面試問題的後繼問題提出的。查詢快取實際上保
存的是sql查詢的結果,這樣再進行相同的sql查詢就可以之間從快取中拿到結果了。
為了改善效能,查詢快取可以同二級快取一起來使用。Hibernate支援用多種不同的
開源快取方案,比如EhCache,來實現查詢快取

218 為什麼在Hibernate的實體類中要提供一個無引數的構造器這一點非常重要

每個Hibernate實體類必須包含一個 無引數的構造器, 這是因為Hibernate框架要
使用Reflection API,通過呼叫Class.newInstance()來建立這些實體類的例項。
如果在實體類中找不到無引數的構造器,這個方法就會丟擲一個InstantiationException異常

219 可不可以將Hibernate的實體類定義為final類

是的,你可以將Hibernate的實體類定義為final類,但這種做法並不好。因為
Hibernate會使用代理模式在延遲關聯的情況下提高效能,如果你把實體類定義成
final類之後,因為 Java不允許對final類進行擴充套件,所以Hibernate就無法再使
用代理了,如此一來就限制了使用可以提升效能的手段。不過,如果你的持久化類實
現了一個介面而且在該介面中宣告瞭所有定義於實體類中的所有public的方法輪到
話,你就能夠避免出現前面所說的不利後果

220 hibernate的三種狀態之間如何轉換

當物件由瞬時狀態(Transient)一save()時,就變成了持久化狀態; 當我們在
Session裡儲存物件的時候,實際是在Session的Map裡存了一份, 也就是它的緩
存裡放了一份,然後,又到資料庫裡存了一份,在快取裡這一份叫持久物件
(Persistent)。 Session 一 Close()了,它的快取也都關閉了,整個Session也
就失效了,這個時候,這個物件變成了遊離狀態(Detached),但資料庫中還是存在
的。 當遊離狀態(Detached)update()時,又變為了持久狀態(Persistent)。
當持久狀態(Persistent)delete()時,又變為了瞬時狀態(Transient), 此時,
資料庫中沒有與之對應的記錄

221 Hibernate是如何延遲載入

當Hibernate在查詢資料的時候,資料並沒有存在與記憶體中,當程式真正對資料的
操作時,物件才存在與記憶體中,就實現了延遲載入,他節省了伺服器的記憶體開銷,
從而提高了伺服器的效能

222 解Hibernate中怎樣實現類之間的關係

類與類之間的關係主要體現在表與表之間的關係進行操作,它們都是對物件進行操
作,我們程式中把所有的表與類都對映在一起,它們通過配置檔案中的
many-to-one、one-to-many、many-to-many

223 如何優化Hibernate

1.使用雙向一對多關聯,不使用單向一對多 2.靈活使用單向一對多關聯 
3.不用一對一,用多對一取代 4.配置物件快取,不使用集合快取 5.一對多
集合使用Bag,多對多集合使用Set 6. 繼承類使用顯式多型 7. 表欄位要少,
表關聯不要怕多,有二級快取撐腰

224 Hibernate的五個核心介面

Configuration 介面:配置Hibernate,根據其啟動hibernate,建立
SessionFactory 物件; SessionFactory 介面:初始化Hibernate,充當
資料儲存源的代理,建立 session 物件,sessionFactory 是執行緒安全的,
意味著它的同一個例項可以被應 用的多個執行緒共享,是重量級、二級快取;
Session 介面:負責儲存、更新、刪除、載入和查詢物件,是執行緒不安全的,
避免多個執行緒共享同一個session,是輕量級、一級快取; Transaction 介面:
管理事務; Query 和Criteria 介面:執行資料庫的查詢

225 #{}和${}的區別是什麼

是 P r o p e r t i e s 文 件 中 的 變 量 佔 位 符 , 它 可 以 用 於 標 籤 屬 性 值 和 s q l 內 部 , 屬 於 靜 態 文 本 替 換 , 比 如 {}是Properties檔案中的變數佔位符,它可以用於標籤屬性值和sql內部, 屬於靜態文字替換,比如 Propertiessql{driver}會被靜態替換為com.mysql.jdbc.Driver。#{}是sql
的引數佔位符,Mybatis會將sql中的#{}替換為?號,在sql執行前會使用
PreparedStatement的引數設定方法,按序給sql的?號佔位符設定引數值,
比如ps.setInt(0, parameterValue),#{item.name}的取值方式為使用反
射從引數物件中獲取item物件的name屬性值,相當於param.getItem().getName()。

226 Xml對映檔案中,除了常見的select|insert|updae|delete標籤之外,還有哪些標籤

還有很多其他的標籤,、、、、
,加上動態sql的9個標籤,trim|where|set|foreach|if|choose|when|otherwise|bind等,
其中為sql片段標籤,通過標籤引入sql片段,為不支援自增的主鍵生成策略標籤

227 最佳實踐中,通常一個Xml對映檔案,都會寫一個Dao介面與之對應,請問,這個Dao介面的工作原理是什麼?Dao介面裡的方法,引數不同時,方法能過載嗎

Dao介面,就是人們常說的Mapper介面,介面的全限名,就是對映檔案中的namespace的
值,介面的方法名,就是對映檔案中MappedStatement的id值,介面方法內的引數,就
是傳遞給sql的引數。Mapper介面是沒有實現類的,當呼叫介面方法時,介面全限名+方
法名拼接字串作為key值,可唯一定位一個MappedStatement,舉例:
com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到
namespace為com.mybatis3.mappers.StudentDao下面id = findStudentById的
MappedStatement。在Mybatis中,每一個、、、
標籤,都會被解析為一個MappedStatement物件。
Dao介面裡的方法,是不能過載的,因為是全限名+方法名的儲存和尋找策略。
Dao介面的工作原理是JDK動態代理,Mybatis執行時會使用JDK動態代理為Dao介面生
成代理proxy物件,代理物件proxy會攔截介面方法,轉而執行MappedStatement所代
表的sql,然後將sql執行結果返回

228 Mybatis是如何進行分頁的?分頁外掛的原理是什麼

Mybatis使用RowBounds物件進行分頁,它是針對ResultSet結果集執行的記憶體分頁,
而非物理分頁,可以在sql內直接書寫帶有物理分頁的引數來完成物理分頁功能,也可以
使用分頁外掛來完成物理分頁。
分頁外掛的基本原理是使用Mybatis提供的外掛介面,實現自定義外掛,在外掛的攔截
方法內攔截待執行的sql,然後重寫sql,根據dialect方言,新增對應的物理分頁語句
和物理分頁引數。
舉例:select * from student,攔截sql後重寫為:select t.* from (select

  • from student)t limit 0,10

229 為什麼說Mybatis是半自動ORM對映工具?它與全自動的區別在哪裡?

Hibernate屬於全自動ORM對映工具,使用Hibernate查詢關聯物件或者關聯集合對
象時,可以根據物件關係模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯對
象或關聯集合物件時,需要手動編寫sql來完成,所以,稱之為半自動ORM對映工具

230 Mybatis比IBatis比較大的幾個改進是什麼

a.有介面繫結,包括註解繫結sql和xml繫結Sql ,
b.動態sql由原來的節點配置變成OGNL(物件圖導航語言)表示式,
c. 在一對一,一對多的時候引進了association,在一對多的時候引入了collection節
點,不過都是在resultMap裡面配置

231 介面繫結有幾種實現方式,分別是怎麼實現的

介面繫結有兩種實現方式,一種是通過註解繫結,就是在介面的方法上面加上
@Select@Update等註解裡面包含Sql語句來繫結,另外一種就是通過xml裡面寫SQL來繫結,
在這種情況下,要指定xml對映檔案裡面的namespace必須為介面的全路徑名.

232 MyBatis實現一對一有幾種方式?具體怎麼操作的

有聯合查詢和巢狀查詢,聯合查詢是幾個表聯合查詢,只查詢一次,
通過在resultMap裡面配置association節點配置一對一的類就可以完成;
巢狀查詢是先查一個表,根據這個表裡面的結果的外來鍵id,去再另外一個表裡面查
詢資料,也是通過association配置,但另外一個表的查詢通過select屬性配置

233 MyBatis的快取

MyBatis的快取分為一級快取和二級快取,
一級快取放在session裡面,預設就有,二級快取放在它的名稱空間裡,預設是開啟的
, 使用二級快取屬性類需要實現Serializable序列化介面(可用來儲存物件的狀態)
,可在它的對映檔案中配置<cache/

234 什麼是spring?

Spring 是個java企業級應用的開源開發框架。Spring主要用來開發Java應用,但
是有些擴充套件是針對構建J2EE平臺的web應用。Spring 框架目標是簡化Java企業級應
用開發,並通過POJO為基礎的程式設計模型促進良好的程式設計習慣。

235 使用Spring框架的好處是什麼

輕量:Spring 是輕量的,基本的版本大約2MB
控制反轉:Spring通過控制反轉實現了鬆散耦合,物件們給出它們的依賴,而不是
建立或查詢依賴的物件們
面向切面的程式設計(AOP):Spring支援面向切面的程式設計,並且把應用業務邏輯和系統
服務分開
容器:Spring 包含並管理應用中物件的生命週期和配置
MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品
事務管理:Spring 提供一個持續的事務管理介面,可以擴充套件到上至本地事務下至全
局事務(JTA)
異常處理:Spring 提供方便的API把具體技術相關的異常(比如由JDBC,Hibernate
or JDO丟擲的)轉化為一致的unchecked 異常

236 Spring由哪些模組組成

Core module
Bean module
Context module
Expression Language module
JDBC module
ORM module
OXM module
Java Messaging Service(JMS) module
Transaction module
Web module
Web-Servlet module
Web-Struts module
Web-Portlet module

237 核心容器(應用上下文) 模組

這是基本的Spring模組,提供spring 框架的基礎功能,BeanFactory 是 任何
以spring為基礎的應用的核心。Spring 框架建立在此模組之上,它使Spring成為一個容器

238 BeanFactory – BeanFactory 實現舉例

Bean 工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和
依賴從正真的應用程式碼中分離。
最常用的BeanFactory 實現是XmlBeanFactory 類

239 XMLBeanFactory

最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,
它根據XML檔案中的定義載入beans。該容器從XML 檔案讀取配置後設資料並用它去
建立一個完全配置的系統或應用

240 解釋AOP模組

AOP模組用於發給我們的Spring應用做面向切面的開發, 很多支援由AOP聯盟提供,
這樣就確保了Spring和其他AOP框架的共通性。這個模組將後設資料程式設計引入Spring

241 什麼是Spring IOC 容器

Spring IOC 負責建立物件,管理物件(通過依賴注入(DI),裝配物件,配置物件,
並且管理這些物件的整個生命週期

242 IOC的優點是什麼

IOC 或 依賴注入把應用的程式碼量降到最低。它使應用容易測試,單元測試不再需要單例
和JNDI查詢機制。最小的代價和最小的侵入性使鬆散耦合得以實現。IOC容器支援載入
服務時的餓漢式初始化和懶載入

243 ApplicationContext通常的實現是什麼

FileSystemXmlApplicationContext :此容器從一個XML檔案中載入beans的定義,
XML Bean 配置檔案的全路徑名必須提供給它的建構函式。
ClassPathXmlApplicationContext:此容器也從一個XML檔案中載入beans的定義,
這裡,你需要正確設定classpath因為這個容器將在classpath裡找bean配置。
WebXmlApplicationContext:此容器載入一個XML檔案,此檔案定義了一個WEB應用
的所有bean

244 Bean 工廠和 Application contexts  有什麼區別?

Application contexts提供一種方法處理文字訊息,一個通常的做法是載入檔案資源
(比如映象),它們可以向註冊為監聽器的bean釋出事件。另外,在容器或容器內的對
象上執行的那些不得不由bean工廠以程式化方式處理的操作,可以在Application
contexts中以宣告的方式處理。Application contexts實現了MessageSource介面,
該介面的實現以可插拔的方式提供獲取本地化訊息的方

245 什麼是Spring的依賴注入

依賴注入,是IOC的一個方面,是個通常的概念,它有多種解釋。這概念是說你不用建立
物件,而只需要描述它如何被建立。你不在程式碼裡直接組裝你的元件和服務,但是要在
配置檔案裡描述哪些元件需要哪些服務,之後一個容器(IOC容器)負責把他們組裝起來

246 有哪些不同型別的IOC(依賴注入)方式

構造器依賴注入:構造器依賴注入通過容器觸發一個類的構造器來實現的,該類有一系
列引數,每個引數代表一個對其他類的依賴。
Setter方法注入:Setter方法注入是容器通過呼叫無參構造器或無參static工廠 方法
例項化bean之後,呼叫該bean的setter方法,即實現了基於setter的依賴注入

247 Spring 的優點

(1)spring屬於低侵入式設計,程式碼的汙染極低;
(2)spring的DI機制降低了業務物件替換的複雜性;
(3)容器提供了AOP技術,利用它很容易實現如許可權攔截,執行期監控等功能;
(4)降低了元件之間的耦合性 ,實現了軟體各層之間的解耦; 
(5)容器提供單例模式支援;
(6)可以使用容器提供的眾多服務,如事務管理,訊息服務等;
(7)容器提供了眾多的輔助類,能加快應用的開發;
(8)spring對於主流的應用框架提供了整合支援,如hibernate,JPA,Struts等 
(9)獨立於各種應用伺服器 
(10)Spring的高度開放性,並不強制應用完全依賴於Spring,開發者可以自由選擇
spring的部分或全部。

248 Spring的AOP理解

AOP,一般稱為面向方面(切面)程式設計,作為物件導向的一種補充,用於解剖封裝好的
物件內部,找出其中對多個物件產生影響的公共行為,並將其封裝為一個可重用的模組,
這個模組被命名為“切面”(Aspect),切面將那些與業務無關,卻被業務模組共同呼叫
的邏輯提取並封裝起來,減少了系統中的重複程式碼,降低了模組間的耦合度,同時提高了
系統的可維護性。可用於許可權認證、日誌、事務處理。
AOP實現的關鍵在於AOP框架自動建立的AOP代理,AOP代理主要分為靜態代理和動態代
理。靜態代理的代表為AspectJ;動態代理則以Spring AOP為代表。
(1)AspectJ是靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP
代理類,因此也稱為編譯時增強,他會在編譯階段將AspectJ織入到Java位元組碼中,
執行的時候就是增強之後的AOP物件。
(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改位元組碼
,而是每次執行時在記憶體中臨時為方法生成一個AOP物件,這個AOP物件包含了目標對
象的全部方法,並且在特定的切點做了增強處理,並回撥原物件的方法。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理:
①JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個介面。
JDK動態代理的核心是InvocationHandler介面和Proxy類。生成的代理物件的方法
呼叫都會委託到InvocationHandler.invoke()方法,當我們呼叫代理類物件的方
法時,這個“呼叫”會轉送到invoke方法中,代理類物件作為proxy引數傳入,引數
method標識了我們具體呼叫的是代理類的哪個方法,args為這個方法的引數。
②如果目標類沒有實現介面,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。
CGLIB(Code Generation Library),是一個程式碼生成的類庫,可以在執行時動
態的生成指定類的一個子類物件,並覆蓋其中特定方法,覆蓋方法時可以新增增強代
碼,從而實現AOP。CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為
final,那麼它是無法使用CGLIB做動態代理的。
(3)靜態代理與動態代理區別在於生成AOP代理物件的時機不同,相對來說AspectJ的
靜態代理方式具有更好的效能,但是AspectJ需要特定的編譯器進行處理,而Spring
AOP則無需特定的編譯器處理

249 Spring的IoC理解

(1)IOC就是控制反轉。就是物件的建立權反轉交給Spring,由容器控制程式之間
的依賴關係,作用是實現了程式的解耦合,而非傳統實現中,由程式程式碼直接操控。
(依賴)控制權由應用程式碼本身轉到了外部容器,由容器根據配置檔案去建立例項並管
理各個例項之間的依賴關係,控制權的轉移,是所謂反轉,並且由容器動態的將某種
依賴關係注入到元件之中。BeanFactory 是Spring IoC容器的具體實現與核心介面,
提供了一個先進的配置機制,使得任何型別的物件的配置成為可能,用來包裝和管理
各種bean。
(2)最直觀的表達就是,IOC讓物件的建立不用去new了,可以由spring自動生產,
這裡用的就是java的反射機制,通過反射在執行時動態的去建立、呼叫物件。spring
就是根據配置檔案在執行時動態的去建立物件,並呼叫物件的方法的。
(3)Spring的IOC有三種注入方式 :第一是根據屬性注入,也叫set方法
注入;第二種是根據構造方法進行注入;第三種是根據註解進行注入。
詳細的說:
(4)IoC,控制反轉:將物件交給容器管理,你只需要在spring
配置檔案總配置相應的bean,以及設定相關的屬性,讓spring容器
生成類的例項物件以及管理物件。在spring容器啟動的時候,spring會
把你在配置檔案中配置的bean都初始化以及裝配好,然後在你需要呼叫的時候
,就把它已經初始化好的那些bean分配給你需要呼叫這些bean的類。就是將
物件的控制權反轉給spring容器管理。
(5)DI機制(Dependency Injection,依賴注入):可以說是IoC的其中一
個內容,在容器例項化物件的時候主動的將被呼叫者(或者說它的依賴物件)注
入給呼叫物件。比如物件A需要運算元據庫,以前我們總是要在A中自己編寫程式碼
來獲得一個Connection物件,有了 spring我們就只需要告訴spring,A中需要
一個Connection,至於這個Connection怎麼構造,何時構造,A不需要知道。在
系統執行時,spring會在適當的時候製造一個Connection,然後像打針一樣,注
射到A當中,這樣就完成了對各個物件之間關係的控制。
IoC讓相互協作的元件保持鬆散的耦合,而AOP程式設計允許你把遍佈於應用各層的功
能分離出來形成可重用的功能元件

250 BeanFactory和ApplicationContext有什麼區別

BeanFactory和ApplicationContext是Spring的兩大核心介面,而其中
ApplicationContext是BeanFactory的子介面。它們都可以當做Spring的
容器,生成Bean例項的,並管理容器中的Bean。
(1)BeanFactory:是Spring裡面最底層的介面,提供了最簡單的容器的功
能,負責讀取bean配置文件,管理bean的載入與例項化,維護bean之間的依
賴關係,負責bean的生命週期,但是無法支援spring的aop功能和web應用。
(2)ApplicationContext介面作為BeanFactory的派生,因而具有BeanFactory
所有的功能。而且ApplicationContext還在功能上做了擴充套件,以一種更面向框架的
方式工作以及對上下文進行分層和實現繼承,相較於BeanFactorty,
ApplicationContext還提供了以下的功能: ①預設初始化所有的Singleton,
也可以通過配置取消預初始化。
②繼承MessageSource,因此支援國際化。
③資源訪問,比如訪問URL和檔案。
④事件機制。
⑤同時載入多個配置檔案。
⑥以宣告式方式啟動並建立Spring容器。
⑦載入多個(有繼承關係)上下文 ,使得每一個上下文都專注於一個特定的層
次,比如應用的web層。
(3)①BeanFactroy採用的是延遲載入形式來注入Bean的,即只有在使用到
某個Bean時(呼叫getBean()),才對該Bean進行載入例項化,這樣,我們就
不能發現一些存在的Spring的配置問題。如果Bean的某一個屬性沒有注入,
BeanFacotry載入後,直至第一次使用呼叫getBean方法才會丟擲異常。
②而ApplicationContext則相反,它是在容器啟動時,一次性建立了所有
的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤,
這樣有利於檢查所依賴屬性是否注入。 ApplicationContext啟動後預載入
所有的單例項Bean,通過預載入單例項bean ,確保當你需要的時候,你就不用
等待,因為它們已經建立好了。
③相對於基本的BeanFactory,ApplicationContext 唯一的不足是佔用記憶體
空間。當應用程式配置Bean較多時,程式啟動較慢。
(4)BeanFactory通常以程式設計的方式被建立,ApplicationContext還能以聲
明的方式建立,如使用ContextLoader。
(5)BeanFactory和ApplicationContext都支援BeanPostProcessor、
BeanFactoryPostProcessor的使用,但兩者之間的區別是:BeanFactory
需要手動註冊,而ApplicationContext則是自動註冊

251 解釋Spring支援的幾種bean的作用域。

Spring容器中的bean可以分為5個範圍:
(1)singleton:這種bean範圍是預設的,這種範圍確保不管接受到多少個
請求,每個容器中只有一個bean的例項,單例的模式由bean factory自身來維護。
(2)prototype:原形範圍與單例範圍相反,為每一個bean請求提供一個例項。
(3)request:在請求bean範圍內會每一個來自客戶端的網路請求建立一個例項,
在請求完成以後,bean會失效並被垃圾回收器回收。
(4)Session:與請求範圍類似,確保每個session中有一個bean的例項,
在session過期後,bean會隨之失效。(5)global-session:global-session
和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。
如果你想要宣告讓所有的portlet共用全域性的儲存變數的話,那麼這全域性變數需要儲存
在global-session中。全域性作用域與Servlet中的session作用域效果相同

252 請解釋Spring Bean的生命週期

首先說一下Servlet的生命週期:例項化,初始init,接收請求service,銷燬destroy;
 Spring上下文中的Bean生命週期也類似,如下:
(1)例項化一個Bean--也就是我們常說的new;
(2)按照Spring上下文對例項化的Bean進行配置--也就是IOC注入;
(3)如果這個Bean已經實現了BeanNameAware介面,會呼叫它實現的
setBeanName(String)方法,此處傳遞的就是Spring配置檔案中Bean的id值;
(4)如果這個Bean已經實現了BeanFactoryAware介面,會呼叫它實現的
setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自
身(可以用這個方式來獲取其它Bean,只需在Spring配置檔案中配置一個普通的Bean就可以);
(5)如果這個Bean已經實現了ApplicationContextAware介面,會呼叫
setApplicationContext(ApplicationContext)方法,傳入Spring上下
文(同樣這個方式也可以實現步驟4的內容,但比4更好,因為ApplicationContext
是BeanFactory的子介面,有更多的實現方法);
(6)如果這個Bean關聯了BeanPostProcessor介面,將會呼叫
postProcessBeforeInitialization(Object obj, String s)方法,
BeanPostProcessor經常被用作是Bean內容的更改,並且由於這個是在Bean
初始化結束時呼叫那個的方法,也可以被應用於記憶體或快取技術;
(7)如果Bean在Spring配置檔案中配置了init-method屬性會自動呼叫其配
置的初始化方法。
(8)如果這個Bean關聯了BeanPostProcessor介面,將會呼叫
postProcessAfterInitialization(Object obj, String s)方法、;

253  Spring中bean的載入過程

(1)獲取配置檔案資源;
(2)對獲取的xml資源進行一定的處理檢驗;
(3)處理包裝資源;
(4)解析處理包裝過後的資源;
(5)載入提取bean並註冊(新增到beanDefinitionMap中)

254  Spring框架中的單例Beans是執行緒安全的麼

Spring框架並沒有對單例bean進行任何多執行緒的封裝處理。關於單例bean的執行緒安
全和併發問題需要開發者自行去搞定。但實際上,大部分的Spring bean並沒有可變
的狀態(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是執行緒安
全的。如果你的bean有多種狀態的話(比如 View Model 物件),就需要自行保證線
程安全。最淺顯的解決辦法就是將多型bean的作用域由“singleton”變更為“prototype”

255  Spring如何處理執行緒併發問題

Spring使用ThreadLocal解決執行緒安全問題。
我們知道在一般情況下,只有有狀態的Bean才可以在多執行緒環境下共享,在Spring中,絕
大部分Bean都可以宣告為singleton作用域。就是因為Spring對一些
Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)
中非執行緒安全狀態採用ThreadLocal進行處理,讓它們也成為執行緒安全的狀態,
因為有狀態的Bean就可以在多執行緒中共享了。
ThreadLocal和執行緒同步機制都是為了解決多執行緒中相同變數的訪問衝突問題。
(1)在同步機制中,通過物件的鎖機制保證同一時間只有一個執行緒訪問變數。
這時該變數是多個執行緒共享的,使用同步機制要求程式慎密地分析什麼時候對變
量進行讀寫,什麼時候需要鎖定某個物件,什麼時候釋放物件鎖等繁雜的問題,
程式設計和編寫難度相對較大。
(2)而ThreadLocal則從另一個角度來解決多執行緒的併發訪問。ThreadLocal會為
每一個執行緒提供一個獨立的變數副本,從而隔離了多個執行緒對資料的訪問衝突。因為
每一個執行緒都擁有自己的變數副本,從而也就沒有必要對該變數進行同步了。ThreadLocal
提供了執行緒安全的共享物件,在編寫多執行緒程式碼時,可以把不安全的變數封裝進ThreadLocal。
(3)概括起來說,對於多執行緒資源共享的問題,同步機制採用了“以時間換空間”的方式,
而ThreadLocal採用了“以空間換時間”的方式。前者僅提供一份變數,讓不同的執行緒排隊訪問,
而後者為每一個執行緒都提供了一份變數,因此可以同時訪問而互不影響

256 請解釋Spring自動裝配模式的區別

在Spring框架中共有5種自動裝配:
(1)no:這是Spring框架的預設設定,在該設定下自動裝配是關閉的,開發者需要自行
在bean定義中用標籤明確的設定依賴關係。
(2)byName:該選項可以根據bean名稱設定依賴關係。當向一個bean中自動裝配一個
屬性時,容器將根據bean的名稱自動在配置檔案中查詢一個匹配的bean。如果找到的話,
就裝配這個屬性,如果沒找到的話就報錯。
(3)byType:該選項可以根據bean型別設定依賴關係。當向一個bean中自動裝配一個屬性
時,容器將根據bean的型別自動在在配置檔案中查詢一個匹配的bean。如果找到的話,就裝
配這個屬性,如果沒找到的話就報錯。
(4)constructor:構造器的自動裝配和byType模式類似,但是僅僅適用於與有構造器相同
引數的bean,如果在容器中沒有找到與構造器引數型別一致的bean,那麼將會丟擲異常。
(5)autodetect:該模式自動探測使用構造器自動裝配或者byType自動裝配。首先,首先
會嘗試找合適的帶引數的構造器,如果找到的話就是用構造器自動裝配,如果在bean內部沒
有找到相應的構造器或者是無參構造器,容器就會自動選擇byTpe的自動裝配方式

257 Spring 控制器的載入過程

(1)Web容器建立;
(2)上下文建立,但未初始化;
(3)監聽器建立,並註冊到Context上;
(4)上下文初始化;
(5)通知到監聽者,Spring配置檔案/@Configuration載入;
(6)Load-on-startup>0的ServletConfig建立,springMVC的DispatcherServlet此時建立

258 Spring 框架中都用到了哪些設計模式

(1)代理模式—在AOP和remoting中被用的比較多。(2)單例模式—在spring配置檔案中
定義的bean預設為單例模式。(3)工廠模式—BeanFactory用來建立物件的例項。(4)模
板方法—用來解決程式碼重複的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。
(5)前端控制器—Spring提供了DispatcherServlet來對請求進行分發。(6)檢視幫
助(View Helper )—Spring提供了一系列的JSP標籤,高效巨集來輔助將分散的程式碼整合在
檢視裡。(7)依賴注入—貫穿於BeanFactory / ApplicationContext介面的核心理念

259 Spring事務的種類和各自的區別

spring支援程式設計式事務管理和宣告式事務管理兩種方式:
(1)程式設計式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。
對於程式設計式事務管理,spring推薦使用TransactionTemplate。
(2)宣告式事務管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目標方法開始之前建立
或者加入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。宣告式事務最大的優點
就是不需要通過程式設計的方式管理事務,這樣就不需要在業務邏輯程式碼中摻雜事務管理的程式碼,只需
在配置檔案中做相關的事務規則宣告(或通過基於@Transactional註解的方式),便可以將事務規
則應用到業務邏輯中。
(3)顯然宣告式事務管理要優於程式設計式事務管理,這正是spring倡導的非侵入式的開發方式。聲
明式事務管理使業務程式碼不受汙染,一個普通的POJO物件,只要加上註解就可以獲得完全的事
務支援。和程式設計式事務相比,宣告式事務唯一不足地方是,後者的最細粒度只能作用到方法級別
,無法做到像程式設計式事務那樣可以作用到程式碼塊級別

260 Spring事務的實現方式和實現原理

(1)劃分處理單元——IOC:
由於spring解決的問題是對單個資料庫進行區域性事務處理的,具體的實現首相用spring中的
IOC劃分了事務處理單元。並且將對事務的各種配置放到了ioc容器中(設定事務管理器,設
置事務的傳播特性及隔離機制)。
(2)AOP攔截需要進行事務處理的類:
Spring事務處理模組是通過AOP功能來實現宣告式事務處理的,具體操作(比如事務實行的
配置和讀取,事務物件的抽象),用TransactionProxyFactoryBean介面來使用AOP功能,
生成proxy代理物件,通過TransactionInterceptor完成對代理方法的攔截,將事務處理的
功能編織到攔截的方法中。 
讀取ioc容器事務配置屬性,轉化為spring事務處理需要的內部資料結構
(TransactionAttributeSourceAdvisor),轉化為TransactionAttribute表示的資料物件。 
(3)對事物處理實現(事務的生成、提交、回滾、掛起):
spring委託給具體的事務處理器實現。實現了一個抽象和適配。適配的具
體事務處理器:DataSource資料來源支援、hibernate資料來源事務處理支援、
JDO資料來源事務處理支援,JPA、JTA資料來源事務處理支援。這些支援都是通過設
計PlatformTransactionManager、AbstractPlatforTransaction一系列事
務處理的支援。為常用資料來源支援提供了一系列的TransactionManager。
(4)結合:
PlatformTransactionManager實現了TransactionInterception介面,讓
其與TransactionProxyFactoryBean結合起來,形成一個Spring宣告式事務
處理的設計體系

261 解釋一下Spring AOP裡面的幾個名詞

(1)切面(Aspect):一個關注點的模組化,這個關注點可能會橫切多個物件。事
務管理是J2EE應用中一個關於橫切關注點的很好的例子。 在Spring AOP中,切面可
以使用通用類(基於模式的風格) 或者在普通類中以 @Aspect 註解(@AspectJ風格)
來實現。
(2)連線點(Joinpoint):在程式執行過程中某個特定的點,比如某方法呼叫的
時候或者處理異常的時候。 在Spring AOP中,一個連線點 總是 代表一個方法的
執行。 通過宣告一個org.aspectj.lang.JoinPoint型別的引數可以使通知(Advice)
的主體部分獲得連線點資訊。
(3)通知(Advice):在切面的某個特定的連線點(Joinpoint)上執行的動作。通
知有各種型別,其中包括“around”、“before”和“after”等通知。 通知的型別將在後
面部分進行討論。許多AOP框架,包括Spring,都是以攔截器做通知模型, 並維護一個
以連線點為中心的攔截器鏈。
(4)切入點(Pointcut):匹配連線點(Joinpoint)的斷言。通知和一個切入點表達
式關聯,並在滿足這個切入點的連線點上執行(例如,當執行某個特定名稱的方法時)。 
切入點表示式如何和連線點匹配是AOP的核心:Spring預設使用AspectJ切入點語法。
(5)引入(Introduction):(也被稱為內部型別宣告(inter-type declaration))。
宣告額外的方法或者某個型別的欄位。 Spring允許引入新的介面(以及一個對應的實現)
到任何被代理的物件。例如,你可以使用一個引入來使bean實現 IsModified 介面,以便
簡化快取機制。
(6)目標物件(Target Object): 被一個或者多個切面(aspect)所通知(advise)
的物件。也有人把它叫做 被通知(advised) 物件。 既然Spring AOP是通過執行時代理
實現的,這個物件永遠是一個 被代理(proxied) 物件
(7)織入(Weaving):把切面(aspect)連線到其它的應用程式型別或者物件上,並創
建一個被通知(advised)的物件。 這些可以在編譯時(例如使用AspectJ編譯器),類加
載時和執行時完成。 Spring和其他純Java AOP框架一樣,在執行時完成織入。
切入點(pointcut)和連線點(join point)匹配的概念是AOP的關鍵,這使得AOP不同於
其它僅僅提供攔截功能的舊技術。 切入點使得定位通知(advice)可獨立於OO層次。 
例如,一個提供宣告式事務管理的around通知可以被應用到一組橫跨多個物件中的方法上

相關文章