非常榮幸作為曉峰哥的同事,之前就看過這篇文章,重寫讀一遍,再學習學習。同時也推薦給大家
一、開篇詞
初級、中級:java和計算機科學基礎、開源框架的使用;高級、專家:java io/nio、並發、虛擬機、底層源碼、分布式、安全、性能
java基礎、java進階、java應用開發擴展、java安全基礎、java性能基礎
第1講:java平台的理解
java編譯器和運行時;
javac的編譯:編譯將java源碼生成.class文件,實際是字節碼,而不是可以直接執行的機器碼。
運行時:JVM通過類加載器(Class-Loader)加載字節碼,解釋或者編譯執行;解釋器、編譯器(JIT);
解釋器:逐條讀入,逐條解釋運行的。
java虛擬機,指定不同的參數對運行模式可以進行選擇。-Xint,告訴jvm只進行解釋執行,不對代碼進行編譯,拋棄JIT可能帶來的性能優勢。-Xcomp,jvm關閉解釋器,導致jvm啟動變慢很多。
第2講:Exception和Error的區別
NoClassDefFoundError是一個錯誤(Error),而ClassNOtFoundException是一個異常,在Java中對於錯誤和異常的處理是不同的,我們可以從異常中恢復程序但卻不應該嘗試從錯誤中恢復程序。
(1)Error:系統錯誤,虛擬機出錯,我們處理不了,也不需要我們來處理。
(2)Exception,可以捕獲的異常,且作出處理。也就是要么捕獲異常並作出處理,要么繼續拋出異常。
第3講:談談final、finally、finalize
final 可以用來修飾類、方法、變量,分別有不同的意義,final 修飾的 class 代表不可以繼承擴展,final 的變量是不可以修改的,而 final 的方法也是不可以重寫的(override)。
try-catch-finally
第4講:引用
(1)強引用
特點:我們平常典型編碼Object obj = new Object()中的obj就是強引用。通過關鍵字new創建的對象所關聯的引用就是強引用。 當JVM內存空間不足,JVM寧願拋出OutOfMemoryError運行時錯誤(OOM),使程序異常終止,也不會靠隨意回收具有強引用的“存活”對象來解決內存不足的問題。對於一個普通的對象,如果沒有其他的引用關系,只要超過了引用的作用域或者顯式地將相應(強)引用賦值為 null,就是可以被垃圾收集的了,具體回收時機還是要看垃圾收集策略。
(2)軟引用
特點:軟引用通過SoftReference類實現。 軟引用的生命周期比強引用短一些。只有當 JVM 認為內存不足時,才會去試圖回收軟引用指向的對象:即JVM 會確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對象。軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。后續,我們可以調用ReferenceQueue的poll()方法來檢查是否有它所關心的對象被回收。如果隊列為空,將返回一個null,否則該方法返回隊列中前面的一個Reference對象。
應用場景:軟引用通常用來實現內存敏感的緩存。如果還有空閑內存,就可以暫時保留緩存,當內存不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡內存。
(3)弱引用
弱引用通過WeakReference類實現。 弱引用的生命周期比軟引用短。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。由於垃圾回收器是一個優先級很低的線程,因此不一定會很快回收弱引用的對象。弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
應用場景:弱應用同樣可用於內存敏感的緩存。
(4)虛引用
特點:虛引用也叫幻象引用,通過PhantomReference類來實現。無法通過虛引用訪問對象的任何屬性或函數。幻象引用僅僅是提供了一種確保對象被 finalize 以后,做某些事情的機制。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那么就可以在所引用的對象的內存被回收之前采取一些程序行動。
應用場景:可用來跟蹤對象被垃圾回收器回收的活動,當一個虛引用關聯的對象被垃圾收集器回收之前會收到一條系統通知。
第5講:String、StringBuffer、StringBuilder區別
String:final class,所有屬性也都是final。
StringBuffer:append 線程安全
StringBuilder:非線程安全
intern方法
https://www.cnblogs.com/Qian123/p/5702574.html
應用場景
[A]在字符串內容不經常發生變化的業務場景優先使用String類。例如:常量聲明、少量的字符串拼接操作等。如果有大量的字符串內容拼接,避免使用String與String之間的“+”操作,因為這樣會產生大量無用的中間對象,耗費空間且執行效率低下(新建對象、回收對象花費大量時間)。
[B]在頻繁進行字符串的運算(如拼接、替換、刪除等),並且運行在多線程環境下,建議使用StringBuffer,例如XML解析、HTTP參數解析與封裝。
[C]在頻繁進行字符串的運算(如拼接、替換、刪除等),並且運行在單線程環境下,建議使用StringBuilder,例如SQL語句拼裝、JSON封裝等。
第6講:動態代理
(1)反射機制
反射最大的作用之一就在於我們可以不在編譯時知道某個對象的類型,而在運行時通過提供完整的”包名+類名.class”得到。注意:不是在編譯時,而是在運行時。
利用Java反射機制我們可以加載一個運行時才得知名稱的class,獲悉其構造方法,並生成其對象實體,能對其fields設值並喚起其methods:運行時動態加載需要加載的對象
(2) 動態代理
public class MyDynamicProxy { public static void main (String[] args) { HelloImpl hello = new HelloImpl(); MyInvocationHandler handler = new MyInvocationHandler(hello); // 構造代碼實例 Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler); // 調用代理方法 proxyHello.sayHello(); } } interface Hello { void sayHello(); } class HelloImpl implements Hello { @Override public void sayHello() { System.out.println("Hello World"); } } class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Invoking sayHello"); Object result = method.invoke(target, args); return result; } }
https://blog.51cto.com/13586365/2065317
(3)cglib
第7講 int和Interger 區別
8個原始數據類型:boolean、int、byte、short、char、int、float、double、long
包裝類
原始類型線程安全:AtomicInteger、AtomicLong
原始數據類型和 Java 泛型並不能配合使用 Object
第8講 Vector、ArrayList、LinkedList 區別
Vector:https://www.jianshu.com/p/f50307de72b1
ArrayList :http://www.importnew.com/19867.html
LinkedList :https://www.jianshu.com/p/d5ec2ff72b33
Vector、ArrayList、LinkedList均為線型的數據結構,但是從實現方式與應用場景中又存在差別。
1 底層實現方式
ArrayList內部用數組來實現;LinkedList內部采用雙向鏈表實現;Vector內部用數組實現。
2 讀寫機制
ArrayList在執行插入元素是超過當前數組預定義的最大值時,數組需要擴容,擴容過程需要調用底層System.arraycopy()方法進行大量的數組復制操作;在刪除元素時並不會減少數組的容量(如果需要縮小數組容量,可以調用trimToSize()方法);在查找元素時要遍歷數組,對於非null的元素采取equals的方式尋找。
LinkedList在插入元素時,須創建一個新的Entry對象,並更新相應元素的前后元素的引用;在查找元素時,需遍歷鏈表;在刪除元素時,要遍歷鏈表,找到要刪除的元素,然后從鏈表上將此元素刪除即可。
Vector與ArrayList僅在插入元素時容量擴充機制不一致。對於Vector,默認創建一個大小為10的Object數組,並將capacityIncrement設置為0;當插入元素數組大小不夠時,如果capacityIncrement大於0,則將Object數組的大小擴大為現有size+capacityIncrement;如果capacityIncrement<=0,則將Object數組的大小擴大為現有大小的2倍。
3 讀寫效率
ArrayList對元素的增加和刪除都會引起數組的內存分配空間動態發生變化。因此,對其進行插入和刪除速度較慢,但檢索速度很快。
LinkedList由於基於鏈表方式存放數據,增加和刪除元素的速度較快,但是檢索速度較慢。
4 線程安全性
ArrayList、LinkedList為非線程安全;Vector是基於synchronized實現的線程安全的ArrayList。
需要注意的是:單線程應盡量使用ArrayList,Vector因為同步會有性能損耗;即使在多線程環境下,我們可以利用Collections這個類中為我們提供的synchronizedList(List list)方法返回一個線程安全的同步列表對象。
問題回答
利用PriorityBlockingQueue或Disruptor可實現基於任務優先級為調度策略的執行調度系統。
第9講 hashtable、HashMap、TreeMap 區別
Hashtable: https://www.jianshu.com/p/526970086e4e
HashMap: http://yikun.github.io/2015/04/01/Java-HashMap%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%8F%8A%E5%AE%9E%E7%8E%B0/
TreeMap: https://www.jianshu.com/p/94acb78a8a4f
Hashtable、HashMap、TreeMap心得
三者均實現了Map接口,存儲的內容是基於key-value的鍵值對映射,一個映射不能有重復的鍵,一個鍵最多只能映射一個值。
(1)元素特性
HashTable中的key、value都不能為null;HashMap中的key、value可以為null,很顯然只能有一個key為null的鍵值對,但是允許有多個值為null的鍵值對;TreeMap中當未實現 Comparator 接口時,key 不可以為null;當實現 Comparator 接口時,若未對null情況進行判斷,則key不可以為null,反之亦然。
(2)順序特性
HashTable、HashMap具有無序特性。TreeMap是利用紅黑樹來實現的(樹中的每個節點的值,都會大於或等於它的左子樹種的所有節點的值,並且小於或等於它的右子樹中的所有節點的值),實現了SortMap接口,能夠對保存的記錄根據鍵進行排序。所以一般需要排序的情況下是選擇TreeMap來進行,默認為升序排序方式(深度優先搜索),可自定義實現Comparator接口實現排序方式。
(3)初始化與增長方式
初始化時:HashTable在不指定容量的情況下的默認容量為11,且不要求底層數組的容量一定要為2的整數次冪;HashMap默認容量為16,且要求容量一定為2的整數次冪。
擴容時:Hashtable將容量變為原來的2倍加1;HashMap擴容將容量變為原來的2倍。
(4)線程安全性
HashTable其方法函數都是同步的(采用synchronized修飾),不會出現兩個線程同時對數據進行操作的情況,因此保證了線程安全性。也正因為如此,在多線程運行環境下效率表現非常低下。因為當一個線程訪問HashTable的同步方法時,其他線程也訪問同步方法就會進入阻塞狀態。比如當一個線程在添加數據時候,另外一個線程即使執行獲取其他數據的操作也必須被阻塞,大大降低了程序的運行效率,在新版本中已被廢棄,不推薦使用。
HashMap不支持線程的同步,即任一時刻可以有多個線程同時寫HashMap;可能會導致數據的不一致。如果需要同步(1)可以用 Collections的synchronizedMap方法;(2)使用ConcurrentHashMap類,相較於HashTable鎖住的是對象整體, ConcurrentHashMap基於lock實現鎖分段技術。首先將Map存放的數據分成一段一段的存儲方式,然后給每一段數據分配一把鎖,當一個線程占用鎖訪問其中一個段的數據時,其他段的數據也能被其他線程訪問。ConcurrentHashMap不僅保證了多線程運行環境下的數據訪問安全性,而且性能上有長足的提升。
(5)一段話HashMap
HashMap基於哈希思想,實現對數據的讀寫。當我們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,讓后找到bucket位置來儲存值對象。當獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然后返回值對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會儲存在鏈表的下一個節點中。 HashMap在每個鏈表節點中儲存鍵值對對象。當兩個不同的鍵對象的hashcode相同時,它們會儲存在同一個bucket位置的鏈表中,可通過鍵對象的equals()方法用來找到鍵值對。如果鏈表大小超過閾值(TREEIFY_THRESHOLD, 8),鏈表就會被改造為樹形結構。
第10講 集合的線程安全,ConcurrentHashMap
java.util.concurrent
https://www.cnblogs.com/chengxiao/p/6842045.html
第11講 java IO、NIO
同步與異步:同步操作,后續任務需要等待當前調用放回才能進行下一步;異步不需要
阻塞與非阻塞: