針對《面試心得與總結—BAT、網易、蘑菇街》一文中出現的技術問題的收集與整理

最近,我在ImportNew網站上,看到了這篇文章,以爲總結的很是好,就默默的收藏起來了,以爲往後必定要好好整理學習一下,昨天忽然發如今脈脈的行業頭條中,竟然也推送了這篇文章,更加堅決了我整理的信心。
文中答案和詳解部分過於詳細的我會附上,本人認爲寫的 比較好的連接,供你們參考,若是有什麼不正確的地方,還但願各位大神,在評論中給予指導,謝謝!
J2SE基礎html

1. 九種基本數據類型的大小,以及他們的封裝類?
Java提供了一組基本數據類型,包括 boolean, byte, char, short, int, long, float, double, void.
同時,java也提供了這些類型的封裝類,分別爲 Boolean, Byte, Character, Short, Integer, Long, Float, Double, Void
爲何Java會這麼作?在java中使用基本類型來存儲語言支持的基本數據類型,這裏沒有采用對象,而是使用了傳統的面向過程語言所採用的基本類在型,
主要是從性能方面來考慮的:由於即便最簡單的數學計算,使用對象來處理也會引發一些開銷,而這些開銷對於數學計算原本是毫無必要的。
可是在java中,泛型類包括預約義的集合,使用的參數都是對象類型,沒法直接使用這些基本數據類型,因此java又提供了這些基本類型的包裝器。
區別:一、基本數據類型只能按值傳遞,而封裝類按引用傳遞,
二、基本類型在堆棧中建立;而對於對象類型,對象在堆中建立,對象的引用在堆棧中建立。基本類型因爲在堆棧中,效率會比較高,可是可能會存在內存泄漏的問題。java

 

2.Switch可否用string作參數?android

 

在 Java 7以前,switch 只能支持 byte、short、char、int或者其對應的封裝類以及 Enum 類型。在 Java 7中,String支持被加上了。程序員

 

3.equals與==的區別?算法

 

「==」比較的是值【變量(棧)內存中存放的對象的(堆)內存地址】數據庫

 

equal用於比較兩個對象的值是否相同【不是比地址】編程

 

【特別注意】Object類中的equals方法和「==」是同樣的,沒有區別,而String類,Integer類等等一些類,是重寫了equals方法,才使得equals和「==不一樣」,
因此,當本身建立類時,自動繼承了Object的equals方法,要想實現不一樣的等於比較,必須重寫equals方法。"=="比"equal"運行速度快,由於"=="只是比較引用.設計模式

 

參考連接:.equals與==數組

 

4. Object有哪些公用方法?緩存

 

直接上代碼:

 

Object o = new Object();

/**
* 比較當前對象和是否等於另外一個對象,指向的對象是否相同
*/
System.out.println(o.equals(new Object()));

/**
* 返回hashCode
*/
System.out.println(o.hashCode());

/**
* 返回包名+類名+Integer.toHexString(hashCode())
*/
System.out.println(o.toString());

/**
* 返回class對象
*/
System.out.println(o.getClass());

 

try {
/**
* 線程等待,Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
*/
o.wait();
o.wait(1000);
o.wait(1000,1000);
} catch (InterruptedException e) {
e.printStackTrace();
}


/**
* notify()和notifyAll()都是Object對象用於通知處在等待該對象的線程的方法。二者的最大區別在於:
* notifyAll使全部原來在該對象上等待被notify的線程通通退出wait的狀態,變成等待該對象上的鎖,一旦該對象被解鎖,他們就會去競爭。
* notify則文明得多他只是選擇一個wait狀態線程進行通知,並使它得到該對象上的鎖,但不驚動其餘一樣在等待被該對象notify的線程們,當第一個線程運行完畢之後釋放對象上的鎖此時若是該對象沒有再次使用notify語句,則即使該對象已經空閒,其餘wait狀態等待的線程因爲沒有獲得該對象的通知,繼續處在wait狀態,直到這個對象發出一個notify或notifyAll,它們等待的是被notify或notifyAll,而不是鎖。
*/
o.notify();
o.notifyAll();
5. Java的四種引用,強弱軟虛,用到的場景。

強引用
最廣泛的一種引用方式,如String s = "abc",變量s就是字符串「abc」的強引用,只要強引用存在,則垃圾回收器就不會回收這個對象。

 

軟引用(SoftReference)
用於描述還有用但非必須的對象,若是內存足夠,不回收,若是內存不足,則回收。通常用於實現內存敏感的高速緩存,
軟引用能夠和引用隊列ReferenceQueue聯合使用,若是軟引用的對象被垃圾回收,JVM就會把這個軟引用加入到與之關聯的引用隊列中。

 

弱引用(WeakReference)
弱引用和軟引用大體相同,弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。
在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。

 

虛引用(PhantomReference)
就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,
在任什麼時候候均可能被垃圾回收器回收。 虛引用主要用來跟蹤對象被垃圾回收器回收的活動。
虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,
若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中

 

參考連接:http://droidyue.com/blog/2014/10/12/understanding-weakreference-in-java/

 


6. Hashcode的做用
hashCode方法的主要做用是爲了配合基於散列的集合一塊兒正常運行,這樣的散列集合包括HashSet、HashMap以及HashTable

 

參考連接:淺談Java中的hashcode方法

7.ArrayList、LinkedList、Vector的區別
這三者都是實現了List接口,都擁有List接口裏面定義的方法,而且同時擁有Collection接口的方法;

 

ArrayList:採用的是數組的方式進行存儲數據的,查詢和修改速度快,可是增長和刪除速度慢;線程是不一樣步的

 

LinkedList:採用的是鏈表的方式進行存儲數據的,查詢和修改速度慢,可是增長和刪除速度快;線程是不一樣步的

 

Vector:也採用的是數組的方式進行存儲的,Vector在java1.0之前用,可是ArrayList是在java1.2版本後使用的,線程是同步的,效率相比ArrayList來講慢一點;同時Vector查詢數據有迭代器,有枚舉,有get(int index),有indexOf(int index)四種方式,而ArrayList卻沒有枚舉

 

8. String、StringBuffer與StringBuilder的區別
一、可變與不可變

 

String類中使用字符數組保存字符串,以下就是,由於有「final」修飾符,因此能夠知道string對象是不可變的。

 

private final char value[];

 

StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,以下就是,可知這兩種對象都是可變的。

 

char[] value;

 

二、是否多線程安全

 

String中的對象是不可變的,也就能夠理解爲常量,顯然線程安全。  

 

AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操做,如expandCapacity、append、insert、indexOf等公共方法

 

StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,因此是線程安全的

 

StringBuilder並無對方法進行加同步鎖,因此是非線程安全的

 

9. Map、Set、List、Queue、Stack的特色與用法

 

Map

 

Map是鍵值對,鍵Key是惟一不能重複的,一個鍵對應一個值,值能夠重複。
TreeMap能夠保證順序,HashMap不保證順序,即爲無序的。
Map中能夠將Key和Value單獨抽取出來,其中KeySet()方法能夠將全部的keys抽取正一個Set。而Values()方法能夠將map中全部的values抽取成一個集合。

 

Set

 

不包含重複元素的集合,set中最多包含一個null元素
只能用Lterator實現單項遍歷,Set中沒有同步方法

 

List

 

有序的可重複集合。
能夠在任意位置增長刪除元素。
用Iterator實現單向遍歷,也可用ListIterator實現雙向遍歷

 

Queue

 

Queue聽從先進先出原則。
使用時儘可能避免add()和remove()方法,而是使用offer()來添加元素,使用poll()來移除元素,它的優勢是能夠經過返回值來判斷是否成功。
LinkedList實現了Queue接口。
Queue一般不容許插入null元素

 

Stack

 

Stack聽從後進先出原則。
Stack繼承自Vector。
它經過五個操做對類Vector進行擴展,容許將向量視爲堆棧,它提供了一般的push和pop操做,以及取堆棧頂點的peek()方法、測試堆棧是否爲空的empty方法等

 

若是涉及堆棧,隊列等操做,建議使用List
對於快速插入和刪除元素的,建議使用LinkedList
若是須要快速隨機訪問元素的,建議使用ArrayList

 


HashMap和Hashtable都實現了Map接口,但決定用哪個以前先要弄清楚它們之間的分別。主要的區別有:線程安全性,同步(synchronization),以及速度。

 

10. HashMap和HashTable的區別。
HashMap幾乎能夠等價於Hashtable,除了HashMap是非synchronized的,並能夠接受null(HashMap能夠接受爲null的鍵值(key)和值(value),而Hashtable則不行)。
HashMap是非synchronized,而Hashtable是synchronized,這意味着Hashtable是線程安全的,多個線程能夠共享一個Hashtable;而若是沒有正確的同步的話,多個線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。
另外一個區別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。因此當有其它線程改變了HashMap的結構(增長或者移除元素),將會拋出ConcurrentModificationException,但迭代器自己的remove()方法移除元素則不會拋出ConcurrentModificationException異常。但這並非一個必定發生的行爲,要看JVM。這條一樣也是Enumeration和Iterator的區別。
因爲Hashtable是線程安全的也是synchronized,因此在單線程環境下它比HashMap要慢。若是你不須要同步,只須要單一線程,那麼使用HashMap性能要好過Hashtable。
HashMap不能保證隨着時間的推移Map中的元素次序是不變的
參考文章:HashMap和HashTable的區別
十一、HashMap和ConcurrentHashMap的區別,HashMap的底層源碼。

 

Hashmap本質是數組加鏈表。根據key取得hash值,而後計算出數組下標,若是多個key對應到同一個下標,就用鏈表串起來,新插入的在前面。

 

ConcurrentHashMap:在hashMap的基礎上,ConcurrentHashMap將數據分爲多個segment(相似hashtable),默認16個(concurrency level),而後在每個分段上都用鎖進行保護,從而讓鎖的粒度更精細一些,併發性能更好

 


參考文章:HashMap VS ConcurrentHashMap

 

HashMap的源碼:【Java集合源碼剖析】HashMap源碼剖析

 

十二、TreeMap、HashMap、LindedHashMap的區別

 


1.HashMap裏面存入的鍵值對在取出的時候是隨機的,也是咱們最經常使用的一個Map.它根據鍵的HashCode值存儲數據,根據鍵能夠直接獲取它的值,具備很快的訪問速度。在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。
2.TreeMap取出來的是排序後的鍵值對。但若是您要按天然順序或自定義順序遍歷鍵,那麼TreeMap會更好。
3. LinkedHashMap 是HashMap的一個子類,若是須要輸出的順序和輸入的相同,那麼用LinkedHashMap能夠實現. (應用場景:購物車等須要順序的)
13. Collection包結構,與Collections的區別。

 

Collection是集合類的上級接口,子接口主要有Set 和List、Map。

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

給你們補充一個連接:collections在java中的常見用法

 

參考連接:http://blog.sina.com.cn/s/blog_105817120102vzh6.html

 

1四、try catch finally,try裏有return,finally還執行麼?

 

一、無論有木有出現異常,finally塊中代碼都會執行;
二、當try和catch中有return時,finally仍然會執行;
三、finally是在return後面的表達式運算後執行的(此時並無返回運算後的值,而是先把要返回的值保存起來,管finally中的代碼怎麼樣,返回的值都不會改變,任然是以前保存的值),因此函數返回值是在finally執行前肯定的;
四、finally中最好不要包含return,不然程序會提早退出,返回值不是try或catch中保存的返回值。

 

狀況1:try{} catch(){}finally{} return;
顯然程序按順序執行。
狀況2:try{ return; }catch(){} finally{} return;
程序執行try塊中return以前(包括return語句中的表達式運算)代碼;
再執行finally塊,最後執行try中return;
finally塊以後的語句return,由於程序在try中已經return因此再也不執行。
狀況3:try{ } catch(){return;} finally{} return;
程序先執行try,若是遇到異常執行catch塊,
有異常:則執行catch中return以前(包括return語句中的表達式運算)代碼,再執行finally語句中所有代碼,
最後執行catch塊中return. finally以後也就是4處的代碼再也不執行。
無異常:執行完try再finally再return.
狀況4:try{ return; }catch(){} finally{return;}
程序執行try塊中return以前(包括return語句中的表達式運算)代碼;
再執行finally塊,由於finally塊中有return因此提早退出。
狀況5:try{} catch(){return;}finally{return;}
程序執行catch塊中return以前(包括return語句中的表達式運算)代碼;
再執行finally塊,由於finally塊中有return因此提早退出。
狀況6:try{ return;}catch(){return;} finally{return;}
程序執行try塊中return以前(包括return語句中的表達式運算)代碼;
有異常:執行catch塊中return以前(包括return語句中的表達式運算)代碼;
則再執行finally塊,由於finally塊中有return因此提早退出。
無異常:則再執行finally塊,由於finally塊中有return因此提早退出。

 

最終結論:任何執行try 或者catch中的return語句以前,都會先執行finally語句,若是finally存在的話。
若是finally中有return語句,那麼程序就return了,因此finally中的return是必定會被return的,
編譯器把finally中的return實現爲一個warning。

 

15. Excption與Error包結構。OOM你遇到過哪些狀況,SOF你遇到過哪些狀況

這裏寫圖片描述

 

(一)Throwable

 

  Throwable 類是 Java 語言中全部錯誤或異常的超類。只有當對象是此類或其子類之一的實例時,才能經過 Java 虛擬機或者 Java throw 語句拋出,才能夠是 catch 子句中的參數類型。
  Throwable 類及其子類有兩個構造方法,一個不帶參數,另外一個帶有 String 參數,此參數可用於生成詳細消息。
  Throwable 包含了其線程建立時線程執行堆棧的快照。它還包含了給出有關錯誤更多信息的消息字符串。
  
Java將可拋出(Throwable)的結構分爲三種類型:
  錯誤(Error)
  運行時異常(RuntimeException)
  被檢查的異常(Checked Exception)

 

 1.Error
  Error 是 Throwable 的子類,用於指示合理的應用程序不該該試圖捕獲的嚴重問題。大多數這樣的錯誤都是異常條件。
  和RuntimeException同樣, 編譯器也不會檢查Error。
  當資源不足、約束失敗、或是其它程序沒法繼續運行的條件發生時,就產生錯誤,程序自己沒法修復這些錯誤的。
  
 2.Exception
  Exception 類及其子類是 Throwable 的一種形式,它指出了合理的應用程序想要捕獲的條件。
   對於能夠恢復的條件使用被檢查異常(Exception的子類中除了RuntimeException以外的其它子類),對於程序錯誤使用運行時異常。 
  

 

① ClassNotFoundException
  
當應用程序試圖使用如下方法經過字符串名加載類時:
Class 類中的 forName 方法。
ClassLoader 類中的 findSystemClass 方法。
ClassLoader 類中的 loadClass 方法。
可是沒有找到具備指定名稱的類的定義,拋出該異常。

 

CloneNotSupportedException

 

當調用
Object 類中的 clone 方法複製對象,但該對象的類沒法實現 Cloneable 接口時,拋出該異常。重寫 clone 方法的應用程序也可能拋出此異常,指示不能或不該複製一個對象。

 

③ IOException
當發生某種 I/O 異常時,拋出此異常。此類是失敗或中斷的 I/O 操做生成的異常的通用類。

 

-EOFException
  當輸入過程當中意外到達文件或流的末尾時,拋出此異常。
此異常主要被數據輸入流用來代表到達流的末尾。
注意:其餘許多輸入操做返回一個特殊值表示到達流的末尾,而不是拋出異常。
    
-FileNotFoundException
  當試圖打開指定路徑名錶示的文件失敗時,拋出此異常。
在不存在具備指定路徑名的文件時,此異常將由 FileInputStream、FileOutputStream 和 RandomAccessFile 構造方法拋出。若是該文件存在,可是因爲某些緣由不可訪問,好比試圖打開一個只讀文件進行寫入,則此時這些構造方法仍然會拋出該異常。

 

-MalformedURLException
  拋出這一異常指示出現了錯誤的 URL。或者在規範字符串中找不到任何合法協議,或者沒法解析字符串。 
 
-UnknownHostException
  指示主機 IP 地址沒法肯定而拋出的異常。

 

④ RuntimeException
   是那些可能在 Java 虛擬機正常運行期間拋出的異常的超類。可能在執行方法期間拋出但未被捕獲的 RuntimeException 的任何子類都無需在 throws 子句中進行聲明。
   Java編譯器不會檢查它。當程序中可能出現這類異常時,仍是會編譯經過。
   雖然Java編譯器不會檢查運行時異常,可是咱們也能夠經過throws進行聲明拋出,也能夠經過try-catch對它進行捕獲處理。

 

-ArithmeticException
當出現異常的運算條件時,拋出此異常。例如,一個整數「除以零」時,拋出此類的一個實例。

 

-ClassCastException
  當試圖將對象強制轉換爲不是實例的子類時,拋出該異常。
例如:Object x = new Integer(0);

 

-LllegalArgumentException
  拋出的異常代表向方法傳遞了一個不合法或不正確的參數。

 

-IllegalStateException
  在非法或不適當的時間調用方法時產生的信號。換句話說,即 Java 環境或 Java 應用程序沒有處於請求操做所要求的適當狀態下。

 

-IndexOutOfBoundsException 
  指示某排序索引(例如對數組、字符串或向量的排序)超出範圍時拋出。
應用程序能夠爲這個類建立子類,以指示相似的異常。

 

-NoSuchElementException
  由 Enumeration 的 nextElement 方法拋出,代表枚舉中沒有更多的元素。

 

-NullPointerException
  當應用程序試圖在須要對象的地方使用 null 時,拋出該異常。這種狀況包括:
調用 null 對象的實例方法。
訪問或修改 null 對象的字段。
將 null 做爲一個數組,得到其長度。
將 null 做爲一個數組,訪問或修改其時間片。
將 null 做爲 Throwable 值拋出。
應用程序應該拋出該類的實例,指示其餘對 null 對象的非法使用。

 

(二) SOF (堆棧溢出 StackOverflow)

 

StackOverflowError 的定義:
當應用程序遞歸太深而發生堆棧溢出時,拋出該錯誤。

 

由於棧通常默認爲1-2m,一旦出現死循環或者是大量的遞歸調用,在不斷的壓棧過程當中,形成棧容量超過1m而致使溢出。

 

棧溢出的緣由:

 

遞歸調用
大量循環或死循環
全局變量是否過多
數組、List、map數據過大

 

16. Java面向對象的三個特徵與含義

 

1 . 封裝性
將對象的狀態信息儘量的隱藏在對象內部,只保留有限的接口和方法與外界進行交互,從而避免了外界對對象內部屬性的破壞。
Java中使用訪問控制符來保護對類、變量、方法和構造方法的訪問

 

2. 繼承
java經過繼承建立分等級層次的類,能夠理解爲一個對象從另外一個對象獲取屬性的過程。

 

3.多態
多態是同一個行爲具備多個不一樣表現形式或形態的能力。 多態性是對象多種表現形式的體現
參考連接:https://yq.aliyun.com/articles/52843

 


17. Override和Overload的含義和區別

 

方法的重寫(Overriding)和重載(Overloading)是Java多態性的不一樣表現。
重寫(Overriding)是父類與子類之間多態性的一種表現,而重載(Overloading)是一個類中多態性的一種表現。若是在子類中定義某方法與其父類有相同的名稱和參數,咱們說該方法被重寫 (Overriding) 。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被"屏蔽"了。若是在一個類中定義了多個同名的方法,它們或有不一樣的參數個數或有不一樣的參數類型或有不一樣的參數次序,則稱爲方法的重載(Overloading)。不能經過訪問權限、返回類型、拋出的異常進行重載。

 

1. Override 特色
一、覆蓋的方法的標誌必需要和被覆蓋的方法的標誌徹底匹配,才能達到覆蓋的效果;
二、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
三、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;
四、方法被定義爲final不能被重寫。
五、對於繼承來講,若是某一方法在父類中是訪問權限是private,那麼就不能在子類對其進行重寫覆蓋,若是定義的話,也只是定義了一個新方法,而不會達到重寫覆蓋的效果。(一般存在於父類和子類之間。)

 

2.Overload 特色
一、在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序(固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int, float), 可是不能爲fun(int, int));
二、不能經過訪問權限、返回類型、拋出的異常進行重載;
三、方法的異常類型和數目不會對重載形成影響;
四、重載事件一般發生在同一個類中,不一樣方法之間的現象。
五、存在於同一類中,可是隻有虛方法和抽象方法才能被覆寫。

 

其具體實現機制:

 

overload是重載,重載是一種參數多態機制,即代碼經過參數的類型或個數不一樣而實現的多態機制。 是一種靜態的綁定機制(在編譯時已經知道具體執行的是哪一個代碼段)。

override是覆蓋。覆蓋是一種動態綁定的多態機制。即在父類和子類中同名元素(如成員函數)有不一樣 的實現代碼。執行的是哪一個代碼是根據運行時實際狀況而定的。

 

18. Interface與abstract類的區別

 

抽象類和接口都不可以實例化,但能夠定義抽象類和接口類型的引用。
一個類若是繼承了某個抽象類或者實現了某個接口都須要對其中的抽象方法所有進行實現,不然該類仍然須要被聲明爲抽象類。
接口比抽象類更加抽象,由於抽象類中能夠定義構造器,能夠有抽象方法和具體方法,而接口中不能定義構造器並且其中的方法所有都是抽象方法。
抽象類中的成員能夠是private、默認、protected、public的,而接口中的成員全都是public的。
抽象類中能夠定義成員變量,而接口中定義的成員變量實際上都是常量。
有抽象方法的類必須被聲明爲抽象類,而抽象類未必要有抽象方法。

 

19. Static class 與non static class的區別

 

內部靜態類不須要有指向外部類的引用。但非靜態內部類須要持有對外部類的引用。
非靜態內部類可以訪問外部類的靜態和非靜態成員。靜態類不能訪問外部類的非靜態成員。他只能訪問外部類的靜態成員。
一個非靜態內部類不能脫離外部類實體被建立,一個非靜態內部類能夠訪問外部類的數據和方法,由於他就在外部類裏面。

 

1.首先是類中的數據,static的
class A {
static int a;
}
class B {
int b;
}
不管新建幾個A對象,這幾個對象公用一個int a,一個對象的a改變,另外一個也會改變。
而B對象,不一樣對象之間的int b獨立存在,互不影響,能夠有多個值。

 

2.類中的方法
靜態的方法,不須要創建對象就能夠訪問
如Math.abs()這個方法,咱們沒有創建Math的對象,就能夠經過類名直接使用abs這個方法。
而非靜態的方法,必須先創建對象,而後經過對象名,調用這個方法。
如JButton jb = new JButton();
jb.addActionListener(l);

 

ps:在靜態方法的定義中,不能直接引用本類的其餘非靜態方法。例如。咱們不能在main中直接引用,本類的其餘方法。因此咱們常常能夠看見,在main方法中,先創建本類的一個對象,而後才經過對象調用本類的其餘方法。

 

3.在初始化過程當中,靜態的老是先初始化

 

20. java多態的實現原理。

 

參考連接:http://www.cnblogs.com/startRuning/p/5673485.html

 


21. 實現多線程的兩種方法:Thread與Runable

 

Thread 和 Runnable 的相同點:都是「多線程的實現方式」。
Thread 和 Runnable 的不一樣點:
Thread 是類,而Runnable是接口;Thread自己是實現了Runnable接口的類。咱們知道「一個類只能有一個父類,可是卻能實現多個接口」,所以Runnable具備更好的擴展性。
此外,Runnable還能夠用於「資源的共享」。即,多個線程都是基於某一個Runnable對象創建的,它們會共享Runnable對象上的資源。
一般,建議經過「Runnable」實現多線程

 

參考連接:http://hjsj186.blog.163.com/blog/static/2465820332015218115231968/

 

22. 線程同步的方法:sychronized、lock、reentrantLock等

 

一.什麼是sychronized

 

sychronized是Java中最基本同步互斥的手段,能夠修飾代碼塊,方法,類.

 

在修飾代碼塊的時候須要一個reference對象做爲鎖的對象.

 

在修飾方法的時候默認是當前對象做爲鎖的對象.

 

在修飾類時候默認是當前類的Class對象做爲鎖的對象.

 

synchronized會在進入同步塊的先後分別造成monitorenter和monitorexit字節碼指令.在執行monitorenter指令時會嘗試獲取對象的鎖,若是此沒對象沒有被鎖,或者此對象已經被當前線程鎖住,那麼鎖的計數器加一,每當monitorexit被鎖的對象的計數器減一.直到爲0就釋放該對象的鎖.由此synchronized是可重入的,不會出現本身把本身鎖死.

 


二.什麼ReentrantLock

 

以對象的方式來操做對象鎖.相對於sychronized須要在finally中去釋放鎖

 

三.synchronized和ReentrantLock的區別

 

除了synchronized的功能,多了三個高級功能.

 

等待可中斷,公平鎖,綁定多個Condition.

 

1.等待可中斷

 

在持有鎖的線程長時間不釋放鎖的時候,等待的線程能夠選擇放棄等待. tryLock(long timeout, TimeUnit unit)

 

2.公平鎖

 

按照申請鎖的順序來一次得到鎖稱爲公平鎖.synchronized的是非公平鎖,ReentrantLock能夠經過構造函數實現公平鎖. new RenentrantLock(boolean fair)

 

3.綁定多個Condition

 

經過屢次newCondition能夠得到多個Condition對象,能夠簡單的實現比較複雜的線程同步的功能.經過await(),signal();

 


分析理解:
在併發量比較小的狀況下,使用synchronized是個不錯的選擇,可是在併發量比較高的狀況下,其性能降低很嚴重,此時ReentrantLock是個不錯的方案。

一、ReentrantLock 擁有Synchronized相同的併發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候

 

線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定,

 

若是使用 synchronized ,若是A不釋放,B將一直等下去,不能被中斷

 

若是 使用ReentrantLock,若是A不釋放,能夠使B在等待了足夠長的時間之後,中斷等待,而幹別的事情

 

 

 

ReentrantLock獲取鎖定與三種方式:
a) lock(), 若是獲取了鎖當即返回,若是別的線程持有鎖,當前線程則一直處於休眠狀態,直到獲取鎖

 

b) tryLock(), 若是獲取了鎖當即返回true,若是別的線程正持有鎖,當即返回false;

 

c)tryLock(long timeout,TimeUnit unit), 若是獲取了鎖定當即返回true,若是別的線程正持有鎖,會等待參數給定的時間,在等待的過程當中,若是獲取了鎖定,就返回true,若是等待超時,返回false;

 

d) lockInterruptibly:若是獲取了鎖定當即返回,若是沒有獲取鎖定,當前線程處於休眠狀態,直到或者鎖定,或者當前線程被別的線程中斷

 

 

 

二、synchronized是在JVM層面上實現的,不但能夠經過一些監控工具監控synchronized的鎖定,並且在代碼執行時出現異常,JVM會自動釋放鎖定,可是使用Lock則不行,lock是經過代碼實現的,要保證鎖定必定會被釋放,就必須將unLock()放到finally{}中

 

 

 

三、在資源競爭不是很激烈的狀況下,Synchronized的性能要優於ReetrantLock,可是在資源競爭很激烈的狀況下,Synchronized的性能會降低幾十倍,可是ReetrantLock的性能能維持常態;

 

JDK5.0的多線程任務包對於同步的性能方面有了很大的改進,在原有synchronized關鍵字的基礎上,又增長了ReentrantLock,以及各類Atomic類。瞭解其性能的優劣程度,有助與咱們在特定的情形下作出正確的選擇。

 

整體的結論先擺出來:

 

synchronized:
在資源競爭不是很激烈的狀況下,偶爾會有同步的情形下,synchronized是很合適的。緣由在於,編譯程序一般會盡量的進行優化synchronize,另外可讀性很是好,無論用沒用過5.0多線程包的程序員都能理解。

 

ReentrantLock:
ReentrantLock提供了多樣化的同步,好比有時間限制的同步,能夠被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,性能稍微比synchronized差點點。可是當同步很是激烈的時候,synchronized的性能一會兒能降低好幾十倍。而ReentrantLock確還能維持常態。

 

Atomic:
和上面的相似,不激烈狀況下,性能比synchronized略遜,而激烈的時候,也能維持常態。激烈的時候,Atomic的性能會優於ReentrantLock一倍左右。可是其有一個缺點,就是隻能同步一個值,一段代碼中只能出現一個Atomic的變量,多於一個同步無效。由於他不能在多個Atomic之間同步。

 


因此,咱們寫同步的時候,優先考慮synchronized,若是有特殊須要,再進一步優化。ReentrantLock和Atomic若是用的很差,不只不能提升性能,還可能帶來災難。

 

23. 鎖的等級:方法鎖、對象鎖、類鎖

 

方法鎖(synchronized修飾方法時)
經過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。

 

synchronized 方法控制對類成員變量的訪問:
每一個類實例對應一把鎖,每一個 synchronized 方法都必須得到調用該方法的類實例的鎖方能執行,不然所屬線程阻塞,方法一旦執行,就獨佔該鎖,直到從該方法返回時纔將鎖釋放,此後被阻塞的線程方能得到該鎖,從新進入可執行狀態。這種機制確保了同一時刻對於每個類實例,其全部聲明爲 synchronized 的成員函數中至多隻有一個處於可執行狀態,從而有效避免了類成員變量的訪問衝突。

 

對象鎖(synchronized修飾方法或代碼塊)

 

  當一個對象中有synchronized method或synchronized block的時候調用此對象的同步方法或進入其同步區域時,就必須先得到對象鎖。若是此對象的對象鎖已被其餘調用者佔用,則須要等待此鎖被釋放。(方法鎖也是對象鎖)       

 

java的全部對象都含有1個互斥鎖,這個鎖由JVM自動獲取和釋放。線程進入synchronized方法的時候獲取該對象的鎖,固然若是已經有線程獲取了這個對象的鎖,那麼當前線程會等待;synchronized方法正常返回或者拋異常而終止,JVM會自動釋放對象鎖。這裏也體現了用synchronized來加鎖的1個好處,方法拋異常的時候,鎖仍然能夠由JVM來自動釋放。
類鎖(synchronized 修飾靜態的方法或代碼塊)

 

  因爲一個class不論被實例化多少次,其中的靜態方法和靜態變量在內存中都只有一份。因此,一旦一個靜態的方法被申明爲synchronized。此類全部的實例化對象在調用此方法,共用同一把鎖,咱們稱之爲類鎖。  

 

對象鎖是用來控制實例方法之間的同步,類鎖是用來控制靜態方法(或靜態變量互斥體)之間的同步。 

 

類鎖只是一個概念上的東西,並非真實存在的,它只是用來幫助咱們理解鎖定實例方法和靜態方法的區別的。
24. 寫出生產者消費者模式。

 

生產者-消費者(producer-consumer)問題,也稱做有界緩衝區(bounded-buffer)問題,兩個進程共享一個公共的固定大小的緩衝區。其中一個是生產者,用於將消息放入緩衝區;另一個是消費者,用於從緩衝區中取出消息。問題出如今當緩衝區已經滿了,而此時生產者還想向其中放入一個新的數據項的情形,其解決方法是讓生產者此時進行休眠,等待消費者從緩衝區中取走了一個或者多個數據後再去喚醒它。一樣地,當緩衝區已經空了,而消費者還想去取消息,此時也可讓消費者進行休眠,等待生產者放入一個或者多個數據時再喚醒它。

 

一,首先定義公共資源類,其中的變量number是保存的公共數據。而且定義兩個方法,增長number的值和減小number的值。因爲多線程的緣由,必須加上synchronized關鍵字,注意while判斷的條件。
/**
* 公共資源類
*/
public class PublicResource {
private int number = 0;

/**
* 增長公共資源
*/
public synchronized void increace() {
while (number != 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;
System.out.println(number);
notify();
}

/**
* 減小公共資源
*/
public synchronized void decreace() {
while (number == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number--;
System.out.println(number);
notify();
}
} </span>

 

二,分別定義生產者線程和消費者線程,並模擬屢次生產和消費,即增長和減小公共資源的number值
[java] view plain copy
<span style="font-size:18px;"> /**
* 生產者線程,負責生產公共資源
*/
public class ProducerThread implements Runnable {
private PublicResource resource;

public ProducerThread(PublicResource resource) {
this.resource = resource;
}

@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.increace();
}
}
}
/**
* 消費者線程,負責消費公共資源
*/
public class ConsumerThread implements Runnable {
private PublicResource resource;

public ConsumerThread(PublicResource resource) {
this.resource = resource;
}

@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.decreace();
}
}
} </span>

 

三,模擬多個生產者和消費者操做公共資源的情形,結果須保證是在容許的範圍內。
public class ProducerConsumerTest {
public static void main(String[] args) {
PublicResource resource = new PublicResource();
new Thread(new ProducerThread(resource)).start();
new Thread(new ConsumerThread(resource)).start();
new Thread(new ProducerThread(resource)).start();
new Thread(new ConsumerThread(resource)).start();
new Thread(new ProducerThread(resource)).start();
new Thread(new ConsumerThread(resource)).start();
}
}
參考連接:http://blog.csdn.net/u010339647/article/details/52013123

 

25. ThreadLocal的設計理念與做用
ThreadLocal類的大體結構和進行ThreadLocalMap的操做.咱們能夠從中得出如下的結論:
1. ThreadLocalMap變量屬於線程(Thread)的內部屬性,不一樣的線程(Thread)擁有徹底不一樣的ThreadLocalMap變量.
2. 線程(Thread)中的ThreadLocalMap變量的值是在ThreadLocal對象進行set或者get操做時建立的.
3. 在建立ThreadLocalMap以前,會首先檢查當前線程(Thread)中的ThreadLocalMap變量是否已經存在,若是不存在則建立一個;
若是已經存在,則使用當前線程(Thread)已建立的ThreadLocalMap.
4. 使用當前線程(Thread)的ThreadLocalMap的關鍵在於使用當前的ThreadLocal的實例做爲key進行存儲ThreadLocal模式
,至少從兩個方面完成了數據訪問隔離,有了橫向和縱向的兩種不一樣的隔離方式,ThreadLocal模式就能真正地作到線程安全:
縱向隔離 —— 線程(Thread)與線程(Thread)之間的數據訪問隔離.這一點由線程(Thread)的數據結構保證.由於每一個線程(Thread)在進行對象訪問時,
訪問的都是各自線程本身的ThreadLocalMap.橫向隔離 —— 同一個線程中,不一樣的ThreadLocal實例操做的對象之間的相互隔離.
這一點由ThreadLocalMap在存儲時,採用當前ThreadLocal的實例做爲key來保證.

 

話很少說,給你們推薦一篇原創博文,我就是在這篇博客http://blog.csdn.net/hua286306956/article/details/8660268裏 學習的

 

26. ThreadPool用法與優點。

 

先定義一個線程池ThreadPoolExecutor,使用的時候用executor來調用runnable

 

優點:合理利用線程池可以帶來三個好處。
第一:下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。
第二:提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行。
第三:提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。

 


推薦連接:http://blog.csdn.net/scboyhj__/article/details/48805881
27. Concurrent包裏的其餘東西:ArrayBlockingQueue、CountDownLatch等等。

 

ArrayBlockingQueue

 

一個創建在數組之上被BlockingQueue綁定的阻塞隊列。這個隊列元素順序是先進先出。隊列的頭部是在隊列中待的時間最長的元素。隊列的尾部是再隊列中待的時間最短的元素。新的元素會被插入到隊列尾部,而且隊列從隊列頭部獲取元素。
這是一個典型的綁定緩衝,在這個緩衝區中,有一個固定大小的數組持有生產者插入的數據,而且消費者會提取這些數據。一旦這個類被建立,那麼這個數組的容量將不能再被改變。嘗試使用put操做給一個滿隊列插入元素將致使這個操做被阻塞;嘗試從空隊列中取元素也會被阻塞。
這個類推薦了一個可選的公平策略來排序等待的生產者和消費者線程。默認的,這個順序是不肯定的。可是隊列會使用公平的設置true來使線程按照先進先出順序訪問。一般公平性會減小吞吐量可是卻減小了可變性以及避免了線程飢餓。
參考博文:http://blog.csdn.net/startupmount/article/details/37413275?utm_source=tuicool&utm_medium=referral

 

concurrent包是jdk1.5引入的重要的包,主要代碼由大牛Doug Lea完成,實際上是在jdk1.4時代,因爲java語言內置對多線程編程的支持比較基礎和有限,因此他寫了這個,由於實在太過於優秀,因此被加入到jdk之中;

 

一般所說的concurrent包基本有3個package組成
java.util.concurrent:提供大部分關於併發的接口和類,如BlockingQueue,Callable,ConcurrentHashMap,ExecutorService, Semaphore等
java.util.concurrent.atomic:提供全部原子操做的類, 如AtomicInteger, AtomicLong等;
java.util.concurrent.locks:提供鎖相關的類, 如Lock, ReentrantLock, ReadWriteLock, Condition等;

 


ountDownLatch, 能夠用來在一個線程中等待多個線程完成任務的類;
一般的使用場景是,某個主線程接到一個任務,起了n個子線程去完成,可是主線程須要等待這n個子線程都完成任務了之後纔開始執行某個操做;

 

掩飾代碼:
@Test
public void demoCountDown()
{
int count = 10;

final CountDownLatch l = new CountDownLatch(count);
for(int i = 0; i < count; ++i)
{
final int index = i;
new Thread(new Runnable() {

@Override
public void run() {

try {
Thread.currentThread().sleep(20 * 1000);
} catch (InterruptedException e) {

e.printStackTrace();
}

System.out.println("thread " + index + " has finished...");

l.countDown();

}
}).start();
}

try {
l.await();
} catch (InterruptedException e) {

e.printStackTrace();
}

System.out.println("now all threads have finished");

}

 

28. wait()和sleep()的區別
① 這兩個方法來自不一樣的類分別是,sleep來自Thread類,和wait來自Object類。
sleep是Thread的靜態類方法,誰調用的誰去睡覺,即便在a線程裏調用b的sleep方法,實際上仍是a去睡覺,要讓b線程睡覺要在b的代碼中調用sleep。
② 鎖: 最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其餘線程能夠使用同步控制塊或者方法。

 

sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其餘線程能夠佔用CPU。通常wait不會加時間限制,由於若是wait線程的運行資源不夠,再出來也沒用,要等待其餘線程調用notify/notifyAll喚醒等待池中的全部線程,纔會進入就緒隊列等待OS分配系統資源。sleep(milliseconds)能夠用時間指定使它自動喚醒過來,若是時間不到只能調用interrupt()強行打斷。

 

Thread.sleep(0)的做用是「觸發操做系統馬上從新進行一次CPU競爭」。

 

③ 使用範圍:wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在任何地方使用。

 

synchronized(x){
x.notify()
//或者wait()
}
29. foreach與正常for循環效率對比

 

不是絕對的,在選擇for, foreach的時候,應該考慮如下幾點:

 

1. 若是隻是讀數據,優先選擇foreach,由於效率高,並且代碼簡單,方便;

 

2. 若是要寫數據,就只能選擇for了

 

30. Java IO與NIO

 

區別對比

 

IO NIO
面向流 面向緩衝
阻塞IO 非阻塞IO
無 選擇器</span>
一、面向流與面向緩衝
Java NIO和IO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。 java IO面向流意味着每次從流中讀一個或多個字節,直至讀取全部字節,它們沒有被緩存在任何地方。此外,它不能先後移動流中的數據。若是須要先後移動從流中讀取的數據,須要先將它緩存到一個緩衝區。 Java NIO的緩衝導向方法略有不一樣。數據讀取到一個它稍後處理的緩衝區,須要時可在緩衝區中先後移動。這就增長了處理過程當中的靈活性。可是,還須要檢查是否該緩衝區中包含全部您須要處理的數據。並且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裏還沒有處理的數據。

 

二、阻塞與非阻塞IO

 

Java IO的各類流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據徹底寫入。該線程在此期間不能再幹任何事情了。 Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,可是它僅能獲得目前可用的數據,若是目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,因此直至數據變的能夠讀取以前,該線程能夠繼續作其餘的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不須要等待它徹底寫入,這個線程同時能夠去作別的事情。 線程一般將非阻塞IO的空閒時間用於在其它通道上執行IO操做,因此一個單獨的線程如今能夠管理多個輸入和輸出通道(channel)。

 

三、選擇器(Selector)

 

ava NIO的選擇器容許一個單獨的線程來監視多個輸入通道,你能夠註冊多個通道使用一個選擇器,而後使用一個單獨的線程來「選擇」通道:這些通道里已經有能夠處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。

 

31. 反射的做用與原理。

 

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

 

推薦連接:Class對象和java反射機制

 

java反射

 

32. 泛型經常使用特色,List<String>可否轉爲List<Object>。

 

一、類型安全。類型錯誤如今在編譯期間就被捕獲到了,而不是在運行時看成java.lang.ClassCastException展現出來,將類型檢查從運行時挪到編譯時有助於開發者更容易找到錯誤,並提升程序的可靠性

 

二、消除了代碼中許多的強制類型轉換,加強了代碼的可讀性

 

三、爲較大的優化帶來了可能

 

List<String>向上轉換至List<Object>會丟失String類的身份(String類型的特有接口),這種轉換是不完美的。
當須要由List向下轉型時,你的程序必須明確的知道將對象轉換成何種具體類型,否則這將是不不‘安全的操做!

 

33. 解析XML的幾種方式的原理與特色:DOM、SAX、PULL
SAX是基於事件流的解析
當解析器發現元素開始、元素結束、文本、文檔的開始或結束等時,發送事件,程序員編寫響應這些事件的代碼,保存數據
DOM是基於XML文檔樹結構的解析
解析器讀入整個文檔,而後構建一個駐留內存的樹結構,而後代碼就能夠使用 DOM 接口來操做這個樹結構
Sax定義

 

SAX是一個解析速度快而且佔用內存少的xml解析器,很是適合用於Android等移動設備

 

SAX全稱是Simple API for Xml,既是指一種接口,也是一個軟件包

 

做爲接口,sax是事件驅動型xml解析的一個標準接口

 

Sax工做原理

 

Sax的工做原理簡單的說,就是對文檔進行順序掃描,掃描到文檔(document)開始與結束,掃描到元素(element)開始、結束等地方時調用事件處理

 

處理函數作相應動做,而後繼續掃描,直到文檔結束。

 

Sax特色

 

1. 解析效率高,佔用內存少

 

2.能夠隨時中止解析

 

3.不能載入整個文檔到內存

 

4.不能寫入xml

 

5.SAX解析xml文件採用的是事件驅動

 

---sax並不須要解析完 整個文檔,在按內容順序解析文檔的過程當中,sax會判斷當前讀到的字符是否合法xml語法中的某部分,若是符合就會觸發事件

 

DOM工做原理
dom全稱Document Object Model ,爲xml文檔的已解析版本定義了一組接口。解析器讀入整個文檔,而後構建一個主流內存的樹結構,

 

而後代碼就能夠使用dom接口來操做這個樹結構

 

DOM的特色
>優勢

 

1.整個文檔樹在內存中,便於操做;支持刪除、修改、從新排列等多種功能

 

2.經過樹形結構存取xml文檔

 

3.能夠在樹的某個節點上向前或向後移動

 

>缺點

 

1.將整個文檔調入內存(包括無用的節點),浪費時間和空間

 

>適用場合

 

一旦解析了文檔還需屢次訪問這些數據;硬件資源充足(內存,cpu)

 

pull解析器簡介
1.pull解析器是android內置的解析器,解析原理與sax相似

 

2.pull它提供了相似的事件。

 

如:開始元素和結束元素事件,使用parse.next()能夠進入下一個元素並觸發相應的事件,事件將做爲數值代碼被髮送

 

所以能夠使用一個switch對感興趣的事件進行處理。當元素開始解析時,調用parser.nextText()方法獲取下一個Text類型節點的值

 

pull與sax的不一樣之處
1.pull讀取xml文件後觸發相應的事件調用方法返回的是數字。

 

2.pull能夠在程序中控制,想解析到哪裏就能夠中止到哪裏

 

3.Android中更推薦使用pull解析

 

參考連接:http://blog.csdn.net/kukulongzai_123/article/details/7058008

 

34. Java與C++對比
Java沒有顯式指針,而在C++中卻能夠用。
Java是主動多態的,不用關心具備繼承關係的多個類之間的同名成員函數會調用哪一個,Java會主動地從祖父類、祖祖父類……,追溯至最高一級父類,而後從上至下開始尋找並調用;C++卻不會主動使用多態,要使用多態,就要用虛函數。
Java是隱式繼承的;C++是被動多態的,C++把話說明白了,你繼承誰就繼承誰,繼承多個均可以,你什麼都不說那麼就不繼承。
Java有接口,C++中卻沒有。C++中是定義了一個抽象類,把成員函數設爲常量,並改爲純虛函數,在C++中這樣的抽象類就是接口。
Java是單根繼承的,可是容許一個類實現多個接口;C++雖然支持多繼承,儘管不多有人去用它。
Java中全部的函數都與類相關,沒有全局變量和非成員函數,而C++卻支持這些。
C++中使用的動態內存怎麼用就怎麼還,Java中因爲包含一個垃圾收集系統。
Java有很緊湊的異常處理機制,而C++稍微顯得草率了一些。可是,這不表明C++異常處理機制不強大,由於Java只能拋出Throwable之類的異常,而C++卻什麼均可以。
Java標準庫是Java龐大的體現,涵蓋了國際化、網絡化、數學、聲音、Web應用和服務以及數據庫等。
35. Java1.7與1.8新特性。

JDK 1.7 新特性
1,switch中能夠使用字串了

 

2,"<>"這個玩意兒的運用List<String> tempList = new ArrayList<>(); 即泛型實例化類型自動推斷

 

3. 自定義自動關閉類

 

4. 新增一些取環境信息的工具方法

 

5. Boolean類型反轉,空指針安全,參與位運算

 

6. 兩個char間的equals

 

7,安全的加減乘除

 

八、對Java集合(Collections)的加強支持

 

九、數值可加下劃線

 

十、支持二進制文字

 

十一、簡化了可變參數方法的調用

 

十二、在try catch異常撲捉中,一個catch能夠寫多個異常類型,用"|"隔開,

 

1三、jdk7以前,你必須用try{}finally{}在try內使用資源,在finally中關閉資源,無論try中的代碼是否正常退出或者異常退出。jdk7以後,你能夠沒必要要寫finally語句來關閉資源,只要你在try()的括號內部定義要使用的資源

 

JDK 1.8 新特性
1、接口的默認方法
2、Lambda 表達式

 

3、函數式接口

 

4、方法與構造函數引用

 

5、Lambda 做用域

 

6、訪問局部變量

 

8、訪問接口的默認方法

 

9、Date API

 

10、Annotation 註解

 

強烈推薦參考連接:JDK各個版本的新特性jdk1.5-jdk8

 

36. 設計模式:單例、工廠、適配器、責任鏈、觀察者等等。

 

Java開發中的23種設計模式詳解(轉)

 

37. JNI的使用
JNI是Java Native Interface的縮寫,它提供了若干的API實現了Java和其餘語言的通訊(主要是C&C++)。
從Java1.1開始,JNI標準成爲java平臺的一部分,它容許Java代碼和其餘語言寫的代碼進行交互。
JNI一開始是爲了本地已編譯語言,尤爲是C和C++而設計的,可是它並不妨礙你使用其餘編程語言,只要調用約定受支持就能夠了。
使用java與本地已編譯的代碼交互,一般會喪失平臺可移植性。可是,有些狀況下這樣作是能夠接受的,甚至是必須的。
例如,使用一些舊的庫,與硬件、操做系統進行交互,或者爲了提升程序的性能。JNI標準至少要保證本地代碼能工做在任何Java 虛擬機環境。

 

推薦連接:JNI的簡單使用

 

j2se的部分 可算整理完了,但願各位讀者可以喜歡,不足的地方但願各位大神多多批評指正,過幾天給你們整理JVM 的部分

JVM
1. 內存模型以及分區,須要詳細到每一個區放什麼

JVM內存區域模型

 

 

 

JVM內存模型
1.方法區
也稱」永久代」 、「非堆」, 它用於存儲虛擬機加載的類信息、常量、靜態變量、是各個線程共享的內存區域。默認最小值爲16MB,最大值爲64MB,能夠經過-XX:PermSize 和 -XX:MaxPermSize 參數限制方法區的大小。
運行時常量池:是方法區的一部分,Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯器生成的各類符號引用,這部份內容將在類加載後放到方法區的運行時常量池中。

2.虛擬機棧
描述的是Java 方法執行的內存模型:每一個方法被執行的時候 都會建立一個「棧幀」用於存儲局部變量表(包括參數)、操做棧、方法出口等信息。每一個方法被調用到執行完的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。聲明週期與線程相同,是線程私有的。
局部變量表存放了編譯器可知的各類基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(引用指針,並不是對象自己),其中64位長度的long和double類型的數據會佔用2個局部變量的空間,其他數據類型只佔1個。局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法須要在棧幀中分配多大的局部變量是徹底肯定的,在運行期間棧幀不會改變局部變量表的大小空間。

3.本地方法棧
與虛擬機棧基本相似,區別在於虛擬機棧爲虛擬機執行的java方法服務,而本地方法棧則是爲Native方法服務。

4.堆
也叫作java 堆、GC堆是java虛擬機所管理的內存中最大的一塊內存區域,也是被各個線程共享的內存區域,在JVM啓動時建立。該內存區域存放了對象實例及數組(全部new的對象)。其大小經過-Xms(最小值)和-Xmx(最大值)參數設置,-Xms爲JVM啓動時申請的最小內存,默認爲操做系統物理內存的1/64但小於1G,-Xmx爲JVM可申請的最大內存,默認爲物理內存的1/4但小於1G,默認當空餘堆內存小於40%時,JVM會增大Heap到-Xmx指定的大小,可經過-XX:MinHeapFreeRation=來指定這個比列;當空餘堆內存大於70%時,JVM會減少heap的大小到-Xms指定的大小,可經過XX:MaxHeapFreeRation=來指定這個比列,對於運行系統,爲避免在運行時頻繁調整Heap的大小,一般-Xms與-Xmx的值設成同樣。
因爲如今收集器都是採用分代收集算法,堆被劃分爲新生代和老年代。新生代主要存儲新建立的對象和還沒有進入老年代的對象。老年代存儲通過屢次新生代GC(Minor GC)任然存活的對象。

新生代:
程序新建立的對象都是重新生代分配內存,新生代由Eden Space和兩塊相同大小的Survivor Space(一般又稱S0和S1或From和To)構成,可經過-Xmn參數來指定新生代的大小,也能夠經過-XX:SurvivorRation來調整Eden Space及Survivor Space的大小。

老年代:
用於存放通過屢次新生代GC任然存活的對象,例如緩存對象,新建的對象也有可能直接進入老年代,主要有兩種狀況:①.大對象,可經過啓動參數設置-XX:PretenureSizeThreshold=1024(單位爲字節,默認爲0)來表明超過多大時就不在新生代分配,而是直接在老年代分配。②.大的數組對象,切數組中無引用外部對象。
老年代所佔的內存大小爲-Xmx對應的值減去-Xmn對應的值。

5.程序計數器
是最小的一塊內存區域,它的做用是當前線程所執行的字節碼的行號指示器,在虛擬機的模型裏,字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、異常處理、線程恢復等基礎功能都須要依賴計數器完成。

2. 堆裏面的分區:Eden,survival from to,老年代,各自的特色。
HotSpot虛擬機的分代收集,分爲一個Eden區、兩個Survivor去以及Old Generation/Tenured區,其中Eden以及Survivor共同組成New Generatiton/Young space。
一般將對New Generation進行的回收稱爲Minor GC;對Old Generation進行的回收稱爲Major GC,但因爲Major GC除併發GC外均需對整個堆以及Permanent Generation進行掃描和回收,所以又稱爲Full GC。

Eden區是分配對象的區域。
Survivor是minor/younger gc後存儲存活對象的區域。
Tenured區域存儲長時間存活的對象
1.Eden區
Eden區位於Java堆的年輕代,是新對象分配內存的地方,因爲堆是全部線程共享的,所以在堆上分配內存須要加鎖。而Sun JDK爲提高效率,會爲每一個新建的線程在Eden上分配一塊獨立的空間由該線程獨享,這塊空間稱爲TLAB(Thread Local Allocation Buffer)。在TLAB上分配內存不須要加鎖,所以JVM在給線程中的對象分配內存時會盡可能在TLAB上分配。若是對象過大或TLAB用完,則仍然在堆上進行分配。若是Eden區內存也用完了,則會進行一次Minor GC(young GC)。

2.Survival from to
Survival區與Eden區相同都在Java堆的年輕代。Survival區有兩塊,一塊稱爲from區,另外一塊爲to區,這兩個區是相對的,在發生一次Minor GC後,from區就會和to區互換。在發生Minor GC時,Eden區和Survival from區會把一些仍然存活的對象複製進Survival to區,並清除內存。Survival to區會把一些存活得足夠舊的對象移至年老代。

3.年老代
年老代裏存放的都是存活時間較久的,大小較大的對象,所以年老代使用標記整理算法。當年老代容量滿的時候,會觸發一次Major GC(full GC),回收年老代和年輕代中再也不被使用的對象資源。

3. 對象建立方法,對象的內存分配,對象的訪問定位。

Java對象的建立大體上有如下幾個步驟:
類加載檢查:檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,而且檢查這個符號引用表明的類是否已被加載、解析和初始化過。若是沒有,那必須先執行相應的類的加載過程
爲對象分配內存:對象所需內存的大小在類加載完成後便徹底肯定,爲對象分配空間的任務等同於把一塊肯定大小的內存從Java堆中劃分出來。因爲堆被線程共享,所以此過程須要進行同步處理(分配在TLAB上不須要同步)
內存空間初始化:虛擬機將分配到的內存空間都初始化爲零值(不包括對象頭),內存空間初始化保證了對象的實例字段在Java代碼中能夠不賦初始值就直接使用,程序能訪問到這些字段的數據類型所對應的零值。
對象設置:JVM對對象頭進行必要的設置,保存一些對象的信息(指明是哪一個類的實例,哈希碼,GC年齡等)
init:執行完上面的4個步驟後,對JVM來講對象已經建立完畢了,但對於Java程序來講,咱們還須要對對象進行一些必要的初始化。
對象的內存分配
Java對象的內存分配有兩種狀況,由Java堆是否規整來決定(Java堆是否規整由所採用的垃圾收集器是否帶有壓縮整理功能決定):
指針碰撞(Bump the pointer):若是Java堆中的內存是規整的,全部用過的內存都放在一邊,空閒的內存放在另外一邊,中間放着一個指針做爲分界點的指示器,分配內存也就是把指針向空閒空間那邊移動一段與內存大小相等的距離
空閒列表(Free List):若是Java堆中的內存不是規整的,已使用的內存和空閒的內存相互交錯,就沒有辦法簡單的進行指針碰撞了。虛擬機必須維護一張列表,記錄哪些內存塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給對象實例,並更新列表上的記錄
對象的訪問定位
對象的訪問形式取決於虛擬機的實現,目前主流的訪問方式有使用句柄和直接指針兩種:
使用句柄:
若是使用句柄訪問,Java堆中將會劃分出一塊內存來做爲句柄池,引用中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息:
對象訪問句柄
優點:引用中存儲的是穩定的句柄地址,在對象被移動(垃圾收集時移動對象是很是廣泛的行爲)時只會改變句柄中的實例數據指針,而引用自己不須要修改。
直接指針:
若是使用直接指針訪問對象,那麼對象的實例數據中就包含一個指向對象類型數據的指針,引用中存的直接就是對象的地址:
對象訪問直接指針
優點:速度更快,節省了一次指針定位的時間開銷,聚沙成塔的效應很是可觀。

4. GC的兩種斷定方法:引用計數與引用鏈。
基於引用計數與基於引用鏈這兩大類別的自動內存管理方式最大的不一樣之處在於:前者只須要局部信息,然後者須要全局信息

引用計數
引用計數顧名思義,就是記錄下一個對象被引用指向的次數。引用計數方式最基本的形態就是讓每一個被管理的對象與一個引用計數器關聯在一塊兒,該計數器記錄着該對象當前被引用的次數,每當建立一個新的引用指向該對象時其計數器就加1,每當指向該對象的引用失效時計數器就減1。當該計數器的值降到0就認爲對象死亡。每一個計數器只記錄了其對應對象的局部信息——被引用的次數,而沒有(也不須要)一份全局的對象圖的生死信息。因爲只維護局部信息,因此不須要掃描全局對象圖就能夠識別並釋放死對象;但也由於缺少全局對象圖信息,因此沒法處理循環引用的情況。

引用鏈
引用鏈須要內存的全局信息,當使用引用鏈進行GC時,從對象圖的「根」(GC Root,必然是活的引用,包括棧中的引用,類靜態屬性的引用,常量的引用,JNI的引用等)出發掃描出去,基於引用的可到達性算法來判斷對象的生死。這使得對象的生死狀態能批量的被識別出來,而後批量釋放死對象。引用鏈不須要顯式維護對象的引用計數,只在GC使用可達性算法遍歷全局信息的時候判斷對象是否被引用,是否存活。

5. GC的三種收集方法:標記清除、標記整理、複製算法的原理與特色,分別用在什麼地方,若是讓你優化收集方法,有什麼思路?
標記清除
標記清除算法分兩步執行:
暫停用戶線程,經過GC Root使用可達性算法標記存活對象
清除未被標記的垃圾對象
標記清除算法缺點以下:
效率較低,須要暫停用戶線程
清除垃圾對象後內存空間不連續,存在較多內存碎片
標記算法現在使用的較少了

複製算法
複製算法也分兩步執行,在複製算法中通常會有至少兩片的內存空間(一片是活動空間,裏面含有各類對象,另外一片是空閒空間,裏面是空的):
暫停用戶線程,標記活動空間的存活對象
把活動空間的存活對象複製到空閒空間去,清除活動空間
複製算法相比標記清除算法,優點在於其垃圾回收後的內存是連續的。
可是複製算法的缺點也很明顯:
須要浪費必定的內存做爲空閒空間
若是對象的存活率很高,則須要複製大量存活對象,致使效率低下
複製算法通常用於年輕代的Minor GC,主要是由於年輕代的大部分對象存活率都較低

標記整理
標記整理算法是標記清除算法的改進,分爲標記、整理兩步:
暫停用戶線程,標記全部存活對象
移動全部存活對象,按內存地址次序一次排列,回收末端對象之後的內存空間
標記整理算法與標記清除算法相比,整理出的內存是連續的;而與複製算法相比,不須要多片內存空間。
然而標記整理算法的第二步整理過程較爲麻煩,須要整理存活對象的引用地址,理論上來講效率要低於複製算法。
所以標記整理算法通常引用於老年代的Major GC
參考博文:Java虛擬機學習(2):垃圾收集算法

6. GC收集器有哪些?CMS收集器與G1收集器的特色?

常見的GC收集器以下圖所示,連線表明可搭配使用:
GC收集器
1.Serial收集器(串行收集器)
用於新生代的單線程收集器,收集時須要暫停全部工做線程(Stop the world)。優勢在於:簡單高效,單個CPU時沒有線程交互的開銷,堆較小時停頓時間不長。常與Serial Old 收集器一塊兒使用,示意圖以下所示:
串行收集器

2.ParNew收集器(parallel new 收集器,新生代並行收集器)
Serial收集器多線程版本,除了使用多線程外和Serial收集器如出一轍。常與Serial Old 收集器一塊兒使用,示意圖以下:
ParNew收集器

3.Parallel Scavenge收集器
與ParNew收集器同樣是一款多線程收集器,其特色在於關注點與別的GC收集器不一樣:通常的GC收集器關注於縮短工做線程暫停的時間,而該收集器關注於吞吐量,所以也被稱爲吞吐量優先收集器。(吞吐量 = 用戶運行代碼時間 / (用戶運行代碼時間 + 垃圾回收時間))高吞吐量與停頓時間短相比主要強調任務快完成,所以常和Parallel Old 收集器一塊兒使用(沒有Parallel Old以前與Serial Old一塊兒使用),示意圖以下:
Parallel Old 收集器

4.Serial Old收集器
Serial收集器的年老代版本,不在贅述。

5.Parallel Old收集器
年老代的並行收集器,在JDK1.6開始使用。

6.CMS收集器(Concurrent Mark Sweep,併發標記清除收集器)
CMS收集器是一個年老代的收集器,是以最短回收停頓時間爲目標的收集器,其示意圖以下所示:
CMS收集器
CMS收集器基於標記清除算法實現,主要分爲4個步驟:
初始標記,須要stop the world,標記GC Root能關聯到的對象,速度快
併發標記,對GC Root執行可達性算法
從新標記,須要stop the world,修復併發標記時因用戶線程運行而產生的標記變化,所需時間比初始標記長,但遠比並發標記短
併發清理
CMS收集器的缺點在於:
其對於CPU資源很敏感。在併發階段,雖然CMS收集器不會暫停用戶線程,可是會由於佔用了一部分CPU資源而致使應用程序變慢,總吞吐量下降。其默認啓動的回收線程數是(cpu數量+3)/4,當cpu數較少的時候,會分掉大部分的cpu去執行收集器線程
沒法處理浮動垃圾,浮動垃圾即在併發清除階段由於是併發執行,還會產生垃圾,這一部分垃圾即爲浮動垃圾,要等下次收集
CMS收集器使用的是標記清除算法,GC後會產生碎片
7.G1收集器(Garbage First收集器)
相比CMS收集器,G1收集器主要有兩處改進:
使用標記整理算法,確保GC後不會產生內存碎片
能夠精確控制停頓,容許指定消耗在垃圾回收上的時間
G1收集器能夠實如今基本不犧牲吞吐量的前提下完成低停頓的內存回收,這是因爲它可以極力地避免全區域的垃圾收集,以前的收集器進行收集的範圍都是整個新生代或老年代,而G1將整個Java堆(包括新生代、老年代)劃分爲多個大小固定的獨立區域(Region),而且跟蹤這些區域裏面的垃圾堆積程度,在後臺維護一個優先列表,每次根據容許的收集時間,優先回收垃圾最多的區域(這就是Garbage First名稱的來由)。區域劃分及有優先級的區域回收,保證了G1收集器在有限的時間內能夠得到最高的收集效率。

7. Minor GC與Full GC分別在何時發生?

Minor GC也叫Young GC,當年輕代內存滿的時候會觸發,會對年輕代進行GC
Full GC也叫Major GC,當年老代滿的時候會觸發,當咱們調用System.gc時也可能會觸發,會對年輕代和年老代進行GC

9. 類加載的五個過程:加載、驗證、準備、解析、初始化。
JVM把class文件加載的內存,並對數據進行校驗、轉換解析和初始化,最終造成JVM能夠直接使用的Java類型的過程就是加載機制。
類從被加載到虛擬機內存中開始,到卸載出內存爲止,它的生命週期包括了:加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸載(Unloading)七個階段,其中驗證、準備、解析三個部分統稱連接。
1.加載
在加載階段,虛擬機須要完成如下事情:
經過一個類的權限定名來獲取定義此類的二進制字節流
將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構
在java堆中生成一個表明這個類的java.lang.Class對象,做爲方法去這些數據的訪問入口
2.驗證
在驗證階段,虛擬機主要完成:
文件格式驗證:驗證class文件格式規範
元數據驗證:這個階段是對字節碼描述的信息進行語義分析,以保證起描述的信息符合java語言規範要求
字節碼驗證:進行數據流和控制流分析,這個階段對類的方法體進行校驗分析,這個階段的任務是保證被校驗類的方法在運行時不會作出危害虛擬機安全的行爲
符號引用驗證:符號引用中經過字符串描述的全限定名是否能找到對應的類、符號引用類中的類,字段和方法的訪問性(private、protected、public、default)是否可被當前類訪問
3.準備
準備階段是正式爲類變量(被static修飾的變量)分配內存並設置變量初始值(0值)的階段,這些內存都將在方法區中進行分配

4.解析
解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程
常見的解析有四種:
類或接口的解析
字段解析
類方法解析
接口方法解析

5.初始化
初始化階段才真正開始執行類中定義的java程序代碼,初始化階段是執行類構造器<clinit>()方法的過程

參考博文:Java虛擬機學習(3): 類加載機制

10. 雙親委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader


上圖中所展現的類加載器之間的這種層次關係,就稱爲類加載器的雙親委託模型。雙親委託模型要求除了頂層的啓動類加載器外,其他的類加載器都應當有本身的父類加載器。這裏類加載器之間的父子關係通常不會以繼承的關係來實現,而是使用組合關係來複用父加載器的代碼。

public abstract class ClassLoader {

privatestatic nativevoid registerNatives();
static{
registerNatives();
}

// The parent class loader for delegation
privateClassLoader parent;

// Hashtable that maps packages to certs
privateHashtable package2certs = newHashtable(11);


雙親委託的工做過程:若是一個類加載器收到了一個類加載請求,它首先不會本身去加載這個類,而是把這個請求委託給父類加載器去完成,每個層次的類加載器都是如此,所以全部的加載請求最終都應該傳送到頂層的啓動類加載器中,只有當父類加載器反饋本身沒法完成加載請求(它管理的範圍之中沒有這個類)時,子加載器纔會嘗試着本身去加載。

使用雙親委託模型來組織類加載器之間的關係,有一個顯而易見的好處就是Java類隨着它的類加載器一塊兒具有了一種帶有優先級的層次關係,例如java.lang.Object存放在rt.jar之中,不管那個類加載器要加載這個類,最終都是委託給啓動類加載器進行加載,所以Object類在程序的各類類加載器環境中都是同一個類,相反,若是沒有雙親委託模型,由各個類加載器去完成的話,若是用戶本身寫一個名爲java.lang.Object的類,並放在classpath中,應用程序中可能會出現多個不一樣的Object類,java類型體系中最基本安全行爲也就沒法保證。

分派:靜態分派與動態分派

靜態分派
全部依賴靜態類型來定位方法執行版本的分派動做稱爲靜態分派,其典型應用是方法重載(重載是經過參數的靜態類型而不是實際類型來選擇重載的版本的)
[java] view plain copy
class Car {}
class Bus extends Car {}
class Jeep extends Car {}
public class Main {
public static void main(String[] args) throws Exception {
// Car 爲靜態類型,Car 爲實際類型
Car car1 = new Car();
// Car 爲靜態類型,Bus 爲實際類型
Car car2 = new Bus();
// Car 爲靜態類型,Jeep 爲實際類型
Car car3 = new Jeep();

showCar(car1);
showCar(car2);
showCar(car3);
}
private static void showCar(Car car) {
System.out.println("I have a Car !");
}
private static void showCar(Bus bus) {
System.out.println("I have a Bus !");
}
private static void showCar(Jeep jeep) {
System.out.println("I have a Jeep !");
}
}
結果
靜態分派重載
動態分派
與靜態分派相似,動態分派指在在運行期根據實際類型肯定方法執行版本,其典型應用是方法重寫(即多態)。
舉例Java代碼以下:
[java] view plain copy
class Car {
public void showCar() {
System.out.println("I have a Car !");
}
}
class Bus extends Car {
public void showCar() {
System.out.println("I have a Bus !");
}
}
class Jeep extends Car {
public void showCar() {
System.out.println("I have a Jeep !");
}
}
public class Main {
public static void main(String[] args) throws Exception {
// Car 爲靜態類型,Car 爲實際類型
Car car1 = new Car();
// Car 爲靜態類型,Bus 爲實際類型
Car car2 = new Bus();
// Car 爲靜態類型,Jeep 爲實際類型
Car car3 = new Jeep();

car1.showCar();
car2.showCar();
car3.showCar();
}
}
動態分派重寫
能夠看出來重寫是一個根據實際類型決定方法版本的動態分派過程。
參考連接:http://www.importnew.com/20438.html

相關文章
相關標籤/搜索