1. 程式人生 > >java技術面試之面試題大全

java技術面試之面試題大全

本篇文章會對面試中常遇到的Java技術點進行全面深入的總結,幫助我們在面試中更加得心應手,不參加面試的同學也能夠藉此機會梳理一下自己的知識體系,進行查漏補缺(閱讀本文需要有一定的Java基礎)。本文的問題列表來自於www.nowcoder.com/discuss/304…在此感謝原作者的無私分享:)

1. Java中的原始資料型別都有哪些,它們的大小及對應的封裝類是什麼?

  • boolean
    boolean資料型別非true即false。這個資料型別表示1 bit,但是它的大小並沒有精確定義。
    《Java虛擬機器規範》中如是說:“雖然定義了boolean這種資料型別,但是隻對它提供了非常有限的支援。在Java虛擬機器中沒有任何供boolean值專用的位元組碼指令,Java語言表示式所操作的boolean值,在編譯之後都使用Java虛擬機器中的int資料型別來代替,而boolean陣列將會被編碼成Java虛擬機器的byte陣列,每個元素boolean元素佔8位”。這樣我們可以得出boolean型別單獨使用是4個位元組,在陣列中又是1個位元組。
    那虛擬機器為什麼要用int來代替boolean呢?為什麼不用byte或short,這樣不是更節省記憶體空間嗎?實際上,使用int的原因是,對於當下32位的CPU來說,一次進行32位的資料交換更加高效。
    綜上,我們可以知道:官方文件對boolean型別沒有給出精確的定義,《Java虛擬機器規範》給出了“單獨時使用4個位元組,boolean陣列時1個位元組”的定義,具體還要看虛擬機器實現是否按照規範來,所以1個位元組、4個位元組都是有可能的。這其實是一種時空權衡。
    boolean型別的封裝類是Boolean。
  • byte——1 byte——Byte
  • short——2 bytes——Short
  • int——4 bytes——Integer
  • long——8 bytes——Long
  • float——4 bytes——Float
  • double——8 bytes——Double
  • char——2 bytes——Character

2. 談一談”==“與”equals()"的區別。
《Think in Java》中說:“關係操作符生成的是一個boolean結果,它們計算的是運算元的值之間的關係”。
"=="判斷的是兩個物件的記憶體地址是否一樣,適用於原始資料型別和列舉型別(它們的變數儲存的是值本身,而引用型別變數儲存的是引用);equals是Object類的方法,Object對它的實現是比較記憶體地址,我們可以重寫這個方法來自定義“相等”這個概念。比如類庫中的String、Date等類就對這個方法進行了重寫。
綜上,對於列舉型別和原始資料型別的相等性比較,應該使用"==";對於引用型別的相等性比較,應該使用equals方法。

3. Java中的四種引用及其應用場景是什麼?

  • 強引用: 通常我們使用new操作符建立一個物件時所返回的引用即為強引用

  • 軟引用: 若一個物件只能通過軟引用到達,那麼這個物件在記憶體不足時會被回收,可用於圖片快取中,記憶體不足時系統會自動回收不再使用的Bitmap

  • 弱引用: 若一個物件只能通過弱引用到達,那麼它就會被回收(即使記憶體充足),同樣可用於圖片快取中,這時候只要Bitmap不再使用就會被回收

  • 虛引用: 虛引用是Java中最“弱”的引用,通過它甚至無法獲取被引用的物件,它存在的唯一作用就是當它指向的物件回收時,它本身會被加入到引用佇列中,這樣我們可以知道它指向的物件何時被銷燬。

4. object中定義了哪些方法?
clone(), equals(), hashCode(), toString(), notify(), notifyAll(), wait(), finalize(), getClass()

5. hashCode的作用是什麼?
請參見散列表的基本原理與實現

6. ArrayList, LinkedList, Vector的區別是什麼?

  • ArrayList: 內部採用陣列儲存元素,支援高效隨機訪問,支援動態調整大小

  • LinkedList: 內部採用連結串列來儲存元素,支援快速插入/刪除元素,但不支援高效地隨機訪問

  • Vector: 可以看作執行緒安全版的ArrayList

7. String, StringBuilder, StringBuffer的區別是什麼?

  • String: 不可變的字元序列,若要向其中新增新字元需要建立一個新的String物件

  • StringBuilder: 可變字元序列,支援向其中新增新字元(無需建立新物件)

  • StringBuffer: 可以看作執行緒安全版的StringBuilder

8. Map, Set, List, Queue、Stack的特點及用法。

  • Map: Java中儲存鍵值對的資料型別都實現了這個介面,表示“對映表”。支援的兩個核心操作是get(Object key)以及put(K key, V value),分別用來獲取鍵對應的值以及向對映表中插入鍵值對。

  • Set: 實現了這個介面的集合型別中不允許存在重複的元素,代表數學意義上的“集合”。它所支援的核心操作有add(E e), remove(Object o)contains(Object o),分別用於新增元素,刪除元素以及判斷給定元素是否存在於集中。

  • List: Java中集合框架中的列表型別都實現了這個介面,表示一種有序序列。支援get(int index)add(E e)等操作。

  • Queue: Java集合框架中的佇列介面,代表了“先進先出”佇列。支援add(E element),remove()等操作。

  • Stack: Java集合框架中表示堆疊的資料型別,堆疊是一種“後進先出”的資料結構。支援push(E item)pop()等操作。

更詳細的說明請參考官方文件,對相關資料結構不太熟悉的同學可以參考《演算法導論》或其他相關書籍。

9. HashMap和HashTable的區別

  • HashTable是執行緒安全的,而HashMap不是

  • HashMap中允許存在null鍵和null值,而HashTable中不允許

10. HashMap的實現原理
簡單的說,HashMap的底層實現是“基於拉鍊法的散列表”。詳細分析請參考深入解析HashMap、HashTable

11. ConcurrentHashMap的實現原理
ConcurrentHashMap是支援併發讀寫的HashMap,它的特點是讀取資料時無需加鎖,寫資料時可以保證加鎖粒度儘可能的小。由於其內部採用“分段儲存”,只需對要進行寫操作的資料所在的“段”進行加鎖。關於ConcurrentHashMap底層實現的詳細分析請參考Java併發程式設計:併發容器之ConcurrentHashMap

12. TreeMap, LinkedHashMap, HashMap的區別是什麼?

  • HashMap的底層實現是散列表,因此它內部儲存的元素是無序的;

  • TreeMap的底層實現是紅黑樹,所以它內部的元素的有序的。排序的依據是自然序或者是建立TreeMap時所提供的比較器(Comparator)物件。

  • LinkedHashMap可以看作能夠記住插入元素的順序的HashMap。

13. Collection與Collections的區別是什麼?

  • Collection是Java集合框架中的基本介面;
  • Collections是Java集合框架提供的一個工具類,其中包含了大量用於操作或返回集合的靜態方法。

14. 對於“try-catch-finally”,若try語句塊中包含“return”語句,finally語句塊會執行嗎?
會執行。只有兩種情況finally塊中的語句不會被執行:**

  • 呼叫了System.exit()方法;

  • JVM“崩潰”了。

15. Java中的異常層次結構
Java中的異常層次結構如下圖所示:

我們可以看到Throwable類是異常層級中的基類。Error類表示內部錯誤,這類錯誤使我們無法控制的;Exception表示異常,RuntimeException及其子類屬於未檢查異常,這類異常包括ArrayIndexOutOfBoundsException、NullPointerException等,我們應該通過條件判斷等方式語句避免未檢查異常的發生。IOException及其子類屬於已檢查異常,編譯器會檢查我們是否為所有可能丟擲的已檢查異常提供了異常處理器,若沒有則會報錯。對於未檢查異常,我們無需捕獲(當然Java也允許我們捕獲,但我們應該做的事避免未檢查異常的發生)。

16. Java面向物件的三個特徵與含義
三大特徵:封裝、繼承、多型。詳細介紹請戳Java面向物件三大特性

17. Override, Overload的含義與區別

  • Override表示“重寫”,是子類對父類中同一方法的重新定義

  • Overload表示“過載”,也就是定義一個與已定義方法名稱相同但簽名不同的新方法**

18. 介面與抽象類的區別

  • 介面是一種約定,實現介面的類要遵循這個約定;
  • 抽象類本質上是一個類,使用抽象類的代價要比介面大。

  • 介面與抽象類的對比如下:

    • 抽象類中可以包含屬性,方法(包含抽象方法與有著具體實現的方法),常量;介面只能包含常量和方法宣告。

    • 抽象類中的方法和成員變數可以定義可見性(比如public、private等);而介面中的方法只能為public(預設為public)。

    • 一個子類只能有一個父類(具體類或抽象類);而一個介面可以繼承一個多個介面,一個類也可以實現多個介面。

    • 子類中實現父類中的抽象方法時,可見性可以大於等於父類中的;而介面實現類中的介面 方法的可見性只能與介面中相同(public)。

19. 靜態內部類與非靜態內部類的區別
靜態內部類不會持有外圍類的引用,而非靜態內部類會隱式持有外圍類的一個引用。

20. Java中多型的實現原理
所謂多型,指的就是父類引用指向子類物件,呼叫方法時會呼叫子類的實現而不是父類的實現。多型的實現的關鍵在於“動態繫結”。詳細介紹請戳Java動態繫結的內部實現機制

21. 簡述Java中建立新執行緒的兩種方法

  • 繼承Thread類(假設子類為MyThread),並重寫run()方法,然後new一個MyThread物件並對其呼叫start()即可啟動新執行緒。

  • 實現Runnable介面(假設實現類為MyRunnable),而後將MyRunnable物件作為引數傳入Thread構造器,在得到的Thread物件上呼叫start()方法即可。

22. 簡述Java中進行執行緒同步的方法

  • volatile: Java Memory Model保證了對同一個volatile變數的寫happens before對它的讀;

  • synchronized: 可以來對一個程式碼塊或是對一個方法上鎖,被“鎖住”的地方稱為臨界區,進入臨界區的執行緒會獲取物件的monitor,這樣其他嘗試進入臨界區的執行緒會因無法獲取monitor而被阻塞。由於等待另一個執行緒釋放monitor而被阻塞的執行緒無法被中斷。

  • ReentrantLock: 嘗試獲取鎖的執行緒可以被中斷並可以設定超時引數。

23. 簡述Java中具有哪幾種粒度的鎖
Java中可以對類、物件、方法或是程式碼塊上鎖。

24. 給出“生產者-消費者”問題的一種解決方案
使用阻塞佇列:

public class BlockingQueueTest {
  private int size = 20;
  private ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(size);
  public static void main(String[] args) {
    BlockingQueueTest test = new BlockingQueueTest(); 
    Producer producer = test.new Producer(); 
    Consumer consumer = test.new Consumer(); 
    producer.start(); consumer.start(); 
  } 

  class Consumer extends Thread{ 
    @Override 
    public void run() { 
      while(true){ 
        try { 
          //從阻塞佇列中取出一個元素 
          queue.take(); 
          System.out.println("佇列剩餘" + queue.size() + "個元素"); 
        } catch (InterruptedException e) { 
        } 
      } 
    } 
  } 

  class Producer extends Thread{ 
    @Override 
    public void run() { 
      while (true) { 
        try { 
          //向阻塞佇列中插入一個元素 
          queue.put(1); 
          System.out.println("佇列剩餘空間:" + (size - queue.size())); 
        } catch (InterruptedException e) { 
        } 
      } 
    } 
  }
}

25. ThreadLocal的設計理念與作用
ThreadLocal的作用是提供執行緒內的區域性變數,在多執行緒環境下訪問時能保證各個執行緒內的ThreadLocal變數各自獨立。也就是說,每個執行緒的ThreadLocal變數是自己專用的,其他執行緒是訪問不到的。ThreadLocal最常用於以下這個場景:多執行緒環境下存在對非執行緒安全物件的併發訪問,而且該物件不需要線上程間共享,但是我們不想加鎖,這時候可以使用ThreadLocal來使得每個執行緒都持有一個該物件的副本。

26. concurrent包的整體架構


27. ArrayBlockingQueue, CountDownLatch類的作用

  • CountDownLatch: 允許執行緒集等待直到計數器為0。適用場景: 當一個或多個執行緒需要等待指定數目的事件發生後再繼續執行。

  • ArrayBlockingQueue: 一個基於陣列實現的阻塞佇列,它在構造時需要指定容量。當試圖向滿佇列中新增元素或者從空佇列中移除元素時,當前執行緒會被阻塞。通過阻塞佇列,我們可以按以下模式來工作:工作者執行緒可以週期性的將中間結果放入阻塞佇列中,其它執行緒可以取出中間結果並進行進一步操作。若工作者執行緒的執行比較慢(還沒來得及向佇列中插入元素),其他從佇列中取元素的執行緒會等待它(試圖從空佇列中取元素從而阻塞);若工作者執行緒執行較快(試圖向滿佇列中插入元素),則它會等待其它執行緒取出元素再繼續執行。

28. wait(),sleep() 的區別

  • wait(): Object類中定義的例項方法。在指定物件上呼叫wait方法會讓當前執行緒進入等待狀態(前提是當前執行緒持有該物件的monitor),此時當前執行緒會釋放相應物件的monitor,這樣一來其它執行緒便有機會獲取這個物件的monitor了。當其它執行緒獲取了這個物件的monitor並進行了所需操作時,便可以呼叫notify方法喚醒之前進入等待狀態的執行緒。

  • sleep(): Thread類中的靜態方法,作用是讓當前執行緒進入休眠狀態,以便讓其他執行緒有機會執行。進入休眠狀態的執行緒不會釋放它所持有的鎖。

29. 執行緒池的用法與優勢

  • 優勢: 實現對執行緒的複用,避免了反覆建立及銷燬執行緒的開銷;使用執行緒池統一管理執行緒可以減少併發執行緒的數目,而執行緒數過多往往會線上程上下文切換上以及執行緒同步上浪費過多時間。

  • 用法: 我們可以呼叫ThreadPoolExecutor的某個構造方法來自己建立一個執行緒池。但通常情況下我們可以使用Executors類提供給我們的靜態工廠方法來更方便的建立一個執行緒池物件。建立了執行緒池物件後,我們就可以呼叫submit方法提交任務到執行緒池中去執行了;執行緒池使用完畢後我們要記得呼叫shutdown方法來關閉它。

30. for-each與常規for迴圈的效率對比
關於這個問題我們直接看《Effective Java》給我們做的解答:

for-each能夠讓程式碼更加清晰,並且減少了出錯的機會。
下面的慣用程式碼適用於集合與陣列型別:

for (Element e : elements) {
    doSomething(e);
}

使用for-each迴圈與常規的for迴圈相比,並不存在效能損失,即使對陣列進行迭代也是如此。實際上,在有些場合下它還能帶來微小的效能提升,因為它只計算一次陣列索引的上限。

31. 簡述Java IO與NIO的區別

  • Java IO是面向流的,這意味著我們需要每次從流中讀取一個或多個位元組,直到讀取完所有位元組;NIO是面向緩衝的,也就是說會把資料讀取到一個緩衝區中,然後對緩衝區中的資料進行相應處理。

  • Java IO是阻塞IO,而NIO是非阻塞IO。

  • Java NIO中存在一個稱為選擇器(selector)的東西,它允許你把多個通道(channel)註冊到一個選擇器上,然後使用一個執行緒來監視這些通道:若這些通道里有某個準備好可以開始進行讀或寫操作了,則開始對相應的通道進行讀寫。而在等待某通道變為可讀/寫期間,請求對通道進行讀寫操作的執行緒可以去幹別的事情。

32. 反射的作用與原理
反射的作用概括地說是執行時獲取類的各種定義資訊,比如定義了哪些屬性與方法。原理是通過類的class物件來獲取它的各種資訊。

33. Java中的泛型機制
關於泛型機制的詳細介紹請直接戳Java核心技術點之泛型

34. Java 7與Java 8的新特性
這裡有兩篇總結的非常好的:
Java 7的新特性
Java 8的新特性

35. 常見設計模式
所謂“設計模式”,不過是面向物件程式設計中一些常用的軟體設計手法,並且經過實踐的檢驗,這些設計手法在各自的場景下能解決一些需求,因此它們就成為了如今廣為流傳的”設計模式“。也就是說,正式因為在某些場景下產生了一些棘手的問題,才催生了相應的設計模式。明確了這一點,我們在學習某種設計模式時要充分理解它產生的背景以及它所解決的主要矛盾是什麼。

常用的設計模式可以分為以下三大類:

  • 建立型模式: 包括工廠模式(又可進一步分為簡單工廠模式、工廠方法模式、抽象工廠模式)、建造者模式、單例模式。

  • 結構型模式: 包括介面卡模式、橋接模式、裝飾模式、外觀模式、享元模式、代理模式。

  • 行為型模式: 包括命令模式、中介者模式、觀察者模式、狀態模式、策略模式。

    關於每個模式具體的介紹請參考圖說設計模式

36. JNI的基本用法
關於JNI,這裡有篇好文:Android中的JNI

37. 動態代理的定義、應用場景及原理
請參見十分鐘理解Java之動態代理

38. 註解的基本概念與使用
註解可以看作是“增強版的註釋”,它可以向編譯器、虛擬機器說明一些事情。
註解是描述Java程式碼的程式碼,它能夠被編譯器解析,註解處理工具在執行時也能夠解析註解。註解本身是“被動”的資訊,只有主動解析它才有意義。
除了向編譯器/虛擬機器傳遞資訊,我們也可以使用註解來生成一些“模板化”的程式碼。

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.抽象類和介面的區別

語法層次
抽象類和介面分別給出了不同的語法定義。
設計層次
抽象層次不同,抽象類是對類抽象,而介面是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是介面卻是對類區域性(行為)進行抽象。抽象類是自底向上抽象而來的,介面是自頂向下設計出來的。
跨域不同
抽象類所體現的是一種繼承關係,要想使得繼承關係合理,父類和派生類之間必須存在"is-a"
關係,即父類和派生類在概念本質上應該是相同的。對於介面則不然,並不要求介面的實現者和介面定義在概念本質上是一致的,僅僅是實現了介面定義的契約而已,"like-a"的關係。

10.自動裝箱與拆箱

裝箱:將基本型別用它們對應的引用型別包裝起來;
拆箱:將包裝型別轉換為基本資料型別;
Java使用自動裝箱和拆箱機制,節省了常用數值的記憶體開銷和建立物件的開銷,提高了效率,由編譯器來完成,編譯器會在編譯期根據語法決定是否進行裝箱和拆箱動作。

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

泛型,即“引數化型別”。
建立集合時就指定集合元素的型別,該集合只能儲存其指定型別的元素,避免使用強制型別轉換。
Java編譯器生成的位元組碼是不包涵泛型資訊的,泛型型別資訊將在編譯處理是被擦除,這個過程即型別擦除。泛型擦除可以簡單的理解為將泛型java程式碼轉換為普通java程式碼,只不過編譯器更直接點,將泛型java程式碼直接轉換成普通java位元組碼。
型別擦除的主要過程如下:
1).將所有的泛型引數用其最左邊界(最頂級的父型別)型別替換。
2).移除所有的型別引數。

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實現原理

14.HashTable實現原理

15.HashMap和HashTable區別

1).HashTable的方法前面都有synchronized來同步,是執行緒安全的;HashMap未經同步,是非執行緒安全的。
2).HashTable不允許null值(key和value都不可以) ;HashMap允許null值(key和value都可以)。
3).HashTable有一個contains(Object
value)功能和containsValue(Object
value)功能一樣。
4).HashTable使用Enumeration進行遍歷;HashMap使用Iterator進行遍歷。
5).HashTable中hash陣列預設大小是11,增加的方式是old*2+1;HashMap中hash陣列的預設大小是16,而且一定是2的指數。
6).雜湊值的使用不同,HashTable直接使用物件的hashCode; HashMap重新計算hash值,而且用與代替求模。

16.ArrayList和vector區別

ArrayList和Vector都實現了List介面,都是通過陣列實現的。
Vector是執行緒安全的,而ArrayList是非執行緒安全的。
List第一次建立的時候,會有一個初始大小,隨著不斷向List中增加元素,當List 認為容量不夠的時候就會進行擴容。Vector預設情況下自動增長原來一倍的陣列長度,ArrayList增長原來的50%。

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

區別
ArrayList底層是用陣列實現的,可以認為ArrayList是一個可改變大小的陣列。隨著越來越多的元素被新增到ArrayList中,其規模是動態增加的。
LinkedList底層是通過雙向連結串列實現的, LinkedList和ArrayList相比,增刪的速度較快。但是查詢和修改值的速度較慢。同時,LinkedList還實現了Queue介面,所以他還提供了offer(),
peek(), poll()等方法。
使用場景
LinkedList更適合從中間插入或者刪除(連結串列的特性)。
ArrayList更適合檢索和在末尾插入或刪除(陣列的特性)。

18.Collection和Collections的區別

java.util.Collection 是一個集合介面。它提供了對集合物件進行基本操作的通用介面方法。Collection介面在Java 類庫中有很多具體的實現。Collection介面的意義是為各種具體的集合提供了最大化的統一操作方式。
java.util.Collections 是一個包裝類。它包含有各種有關集合操作的靜態多型方法。此類不能例項化,就像一個工具類,服務於Java的Collection框架。

19.Concurrenthashmap實現原理

20.Error、Exception區別

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

21.Unchecked

Exception和Checked Exception,各列舉幾個#
Unchecked Exception:
a. 指的是程式的瑕疵或邏輯錯誤,並且在執行時無法恢復。
b. 包括Error與RuntimeException及其子類,如:OutOfMemoryError,
UndeclaredThrowableException, IllegalArgumentException,
IllegalMonitorStateException, NullPointerException, IllegalStateException,
IndexOutOfBoundsException等。
c. 語法上不需要宣告丟擲異常。

Checked Exception:
a. 代表程式不能直接控制的無效外界情況(如使用者輸入,資料庫問題,網路異常,檔案丟失等)
b. 除了Error和RuntimeException及其子類之外,如:ClassNotFoundException,
NamingException, ServletException, SQLException, IOException等。
c. 需要try catch處理或throws宣告丟擲異常。

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

JDK動態代理:代理類和目標類實現了共同的介面,用到InvocationHandler介面。
CGLIB動態代理:代理類是目標類的子類,用到MethodInterceptor介面。

23.多執行緒的實現方式

繼承Thread類、實現Runnable介面、使用ExecutorService、Callable、Future實現有返回結果的多執行緒。

24.執行緒的狀態轉換


20140828202610671.jpg

25.如何停止一個執行緒

26.什麼是執行緒安全

執行緒安全就是多執行緒訪問同一程式碼,不會產生不確定的結果。

27.如何保證執行緒安全

對非安全的程式碼進行加鎖控制;
使用執行緒安全的類;
多執行緒併發情況下,執行緒共享的變數改為方法級的區域性變數。

28.synchronized如何使用

synchronized是Java中的關鍵字,是一種同步鎖。它修飾的物件有以下幾種:
1). 修飾一個程式碼塊,被修飾的程式碼塊稱為同步語句塊,其作用的範圍是大括號{}括起來的程式碼,作用的物件是呼叫這個程式碼塊的物件;
2). 修飾一個方法,被修飾的方法稱為同步方法,其作用的範圍是整個方法,作用的物件是呼叫這個方法的物件;
3). 修改一個靜態的方法,其作用的範圍是整個靜態方法,作用的物件是這個類的所有物件;
4). 修改一個類,其作用的範圍是synchronized後面括號括起來的部分,作用主的物件是這個類的所有物件。

29.synchronized和Lock的區別

主要相同點:Lock能完成synchronized所實現的所有功能
主要不同點: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為使用者模式。

36.Java執行緒池技術及原理

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

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開始支援。
AIO:非同步非阻塞,伺服器實現模式為一個有效請求一個執行緒,客戶端的I/O請求都是由OS先完成了再通知伺服器應用去啟動執行緒進行處理.AIO方式使用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫OS參與併發操作,程式設計比較複雜,JDK7開