① 深入淺出的分析 Set集合
Set集合的特點主要有:元素不重復、存儲無序的特點。
打開 Set 集合,主要實現類有 HashSet、LinkedHashSet 、TreeSet 、EnumSet( RegularEnumSet、JumboEnumSet )等等,總結 Set 介面實現類,圖如下:
由圖中的繼承關系,可以知道,Set 介面主要實現類有 AbstractSet、HashSet、LinkedHashSet 、TreeSet 、EnumSet( RegularEnumSet、JumboEnumSet ),其中 AbstractSet、EnumSet 屬於抽象類,EnumSet 是在 jdk1.5 中新增的,不同的是 EnumSet 集合元素必須是枚舉類型。
HashSet 是一個輸入輸出無序的集合,集合中的元素基於 HashMap 的 key 實現,元素不可重復;
LinkedHashSet 是一個輸入輸出有序的集合,集合中的元素基於 LinkedHashMap 的 key 實現,元素也不可重復;
TreeSet 是一個排序的集合,集合中的元素基於 TreeMap 的 key 實現,同樣元素不可重復;
EnumSet 是一個與枚舉類型一起使用的專用 Set 集合,其中 RegularEnumSet 和 JumboEnumSet 不能單獨實例化,只能由 EnumSet 來生成,同樣元素不可重復;
下面咱們來對各個主要實現類進行一一分析!
HashSet 是一個輸入輸出無序的集合,底層基於 HashMap 來實現,HashSet 利用 HashMap 中的key元素來存放元素,這一點我們可以從源碼上看出來,閱讀源碼如下:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable{
}
打開HashSet的add()方法,源碼如下:
public boolean add(E e) {
//向 HashMap 中添加元素
return map.put(e, PRESENT)==null;
}
其中變數PRESENT,是一個非空對象,源碼部分如下:
private static final Object PRESENT = new Object();
可以分析出,當進行add()的時候,等價於
HashMap map = new HashMap<>();
map.put(e, new Object());//e 表示要添加的元素
在之前的集合文章中,咱們了解到 HashMap 在添加元素的時候 ,通過equals()和hashCode()方法來判斷傳入的key是否相同,如果相同,那麼 HashMap 認為添加的是同一個元素,反之,則不是。
從源碼分析上可以看出,HashSet 正是使用了 HashMap 的這一特性,實現存儲元素下標無序、元素不會重復的特點。
HashSet 的刪除方法,同樣如此,也是基於 HashMap 的底層實現,源碼如下:
public boolean remove(Object o) {
//調用HashMap 的remove方法,移除元素
return map.remove(o)==PRESENT;
}
HashSet 沒有像 List、Map 那樣提供 get 方法,而是使用迭代器或者 for 循環來遍歷元素,方法如下:
public static void main(String[] args) {
Set<String> hashSet = new HashSet<String>();
System.out.println("HashSet初始容量大小:"+hashSet.size());
hashSet.add("1");
hashSet.add("2");
hashSet.add("3");
hashSet.add("3");
hashSet.add("2");
hashSet.add(null);
}
輸出結果:
HashSet初始容量大小:0
HashSet容量大小:4
null,1,2,3,
===========
null,1,2,3,
需要注意的是,HashSet 允許添加為null的元素。
LinkedHashSet 是一個輸入輸出有序的集合,繼承自 HashSet,但是底層基於 LinkedHashMap 來實現。
如果你之前了解過 LinkedHashMap,那麼你一定知道,它也繼承自 HashMap,唯一有區別的是,LinkedHashMap 底層數據結構基於循環鏈表實現,並且數組指定了頭部和尾部,雖然數組的下標存儲無序,但是卻可以通過數組的頭部和尾部,加上循環鏈表,依次可以查詢到元素存儲的過程,從而做到輸入輸出有序的特點。
如果還不了解 LinkedHashMap 的實現過程,可以參閱集合系列中關於 LinkedHashMap 的實現過程文章。
閱讀 LinkedHashSet 的源碼,類定義如下:
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
}
查詢源碼,super調用的方法,源碼如下:
HashSet(int initialCapacity, float loadFactor, boolean mmy) {
//初始化一個 LinkedHashMap
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
LinkedHshSet沒有重寫add方法,而是直接調用HashSet的add()方法,因為map的實現類是LinkedHashMap,所以此處是向LinkedHashMap中添加元素,當進行add()的時候,等價於
HashMap map = new LinkedHashMap<>();
map.put(e, new Object());//e 表示要添加的元素
LinkedHashSet也沒有重寫remove方法,而是直接調用HashSet的刪除方法,因為LinkedHashMap沒有重寫remove方法,所以調用的也是HashMap的remove方法,源碼如下:
public boolean remove(Object o) {
//調用HashMap 的remove方法,移除元素
return map.remove(o)==PRESENT;
}
同樣的,LinkedHashSet 沒有提供 get 方法,使用迭代器或者 for 循環來遍歷元素,方法如下:
public static void main(String[] args) {
Set<String> linkedHashSet = new LinkedHashSet<String>();
System.out.println("linkedHashSet初始容量大小:"+linkedHashSet.size());
linkedHashSet.add("1");
linkedHashSet.add("2");
linkedHashSet.add("3");
linkedHashSet.add("3");
linkedHashSet.add("2");
linkedHashSet.add(null);
linkedHashSet.add(null);
}
輸出結果:
linkedHashSet初始容量大小:0
linkedHashSet容量大小:4
1,2,3,null,
===========
1,2,3,null,
可見,LinkedHashSet 與 HashSet 相比,LinkedHashSet 輸入輸出有序。
TreeSet 是一個排序的集合,實現了NavigableSet、SortedSet、Set介面,底層基於 TreeMap 來實現。TreeSet 利用 TreeMap 中的key元素來存放元素,這一點我們也可以從源碼上看出來,閱讀源碼,類定義如下:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable {
}
new TreeSet<>()對象實例化的時候,表達的意思,可以簡化為如下:
NavigableMap<E,Object> m = new TreeMap<E,Object>();
因為TreeMap實現了NavigableMap介面,所以沒啥問題。
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable{
......
}
打開TreeSet的add()方法,源碼如下:
public boolean add(E e) {
//向 TreeMap 中添加元素
return m.put(e, PRESENT)==null;
}
其中變數PRESENT,也是是一個非空對象,源碼部分如下:
private static final Object PRESENT = new Object();
可以分析出,當進行add()的時候,等價於
TreeMap map = new TreeMap<>();
map.put(e, new Object());//e 表示要添加的元素
TreeMap 類主要功能在於,給添加的集合元素,按照一個的規則進行了排序,默認以自然順序進行排序,當然也可以自定義排序,比如測試方法如下:
public static void main(String[] args) {
Map initMap = new TreeMap();
initMap.put("4", "d");
initMap.put("3", "c");
initMap.put("1", "a");
initMap.put("2", "b");
//默認自然排序,key為升序
System.out.println("默認 排序結果:" + initMap.toString());
//自定義排序,在TreeMap初始化階段傳入Comparator 內部對象
Map comparatorMap = new TreeMap<String, String>(new Comparator<String>() {
@Override
public int compare(String o1, String o2){
//根據key比較大小,採用倒敘,以大到小排序
return o2.compareTo(o1);
}
});
comparatorMap.put("4", "d");
comparatorMap.put("3", "c");
comparatorMap.put("1", "a");
comparatorMap.put("2", "b");
System.out.println("自定義 排序結果:" + comparatorMap.toString());
}
輸出結果:
默認 排序結果:{1=a, 2=b, 3=c, 4=d}
自定義 排序結果:{4=d, 3=c, 2=b, 1=a}
相信使用過TreeMap的朋友,一定知道TreeMap會自動將key按照一定規則進行排序,TreeSet正是使用了TreeMap這種特性,來實現添加的元素集合,在輸出的時候,其結果是已經排序好的。
如果您沒看過源碼TreeMap的實現過程,可以參閱集合系列文章中TreeMap的實現過程介紹,或者閱讀 jdk 源碼。
TreeSet 的刪除方法,同樣如此,也是基於 TreeMap 的底層實現,源碼如下:
public boolean remove(Object o) {
//調用TreeMap 的remove方法,移除元素
return m.remove(o)==PRESENT;
}
TreeSet 沒有重寫 get 方法,而是使用迭代器或者 for 循環來遍歷元素,方法如下:
public static void main(String[] args) {
Set<String> treeSet = new TreeSet<>();
System.out.println("treeSet初始容量大小:"+treeSet.size());
treeSet.add("1");
treeSet.add("4");
treeSet.add("3");
treeSet.add("8");
treeSet.add("5");
}
輸出結果:
treeSet初始容量大小:0
treeSet容量大小:5
1,3,4,5,8,
===========
1,3,4,5,8,
使用自定義排序,有 2 種方法,第一種在需要添加的元素類,實現Comparable介面,重寫compareTo方法來實現對元素進行比較,實現自定義排序。
/**
創建一個Person實體類,實現Comparable介面,重寫compareTo方法,通過變數age實現自定義排序 測試方法如下:
public static void main(String[] args) {
Set<Person> treeSet = new TreeSet<>();
System.out.println("treeSet初始容量大小:"+treeSet.size());
treeSet.add(new Person("李一",18));
treeSet.add(new Person("李二",17));
treeSet.add(new Person("李三",19));
treeSet.add(new Person("李四",21));
treeSet.add(new Person("李五",20));
}
輸出結果:
treeSet初始容量大小:0
treeSet容量大小:5
按照年齡從小到大,自定義排序結果:
李二:17,李一:18,李三:19,李五:20,李四:21,
第二種方法是在TreeSet初始化階段,Person不用實現Comparable介面,將Comparator介面以內部類的形式作為參數,初始化進去,方法如下:
public static void main(String[] args) {
//自定義排序
Set<Person> treeSet = new TreeSet<>(new Comparator<Person>(){
@Override
public int compare(Person o1, Person o2) {
if(o1 == null || o2 == null){
//不用比較
return 0;
}
//從小到大進行排序
return o1.getAge() - o2.getAge();
}
});
System.out.println("treeSet初始容量大小:"+treeSet.size());
treeSet.add(new Person("李一",18));
treeSet.add(new Person("李二",17));
treeSet.add(new Person("李三",19));
treeSet.add(new Person("李四",21));
treeSet.add(new Person("李五",20));
}
輸出結果:
treeSet初始容量大小:0
treeSet容量大小:5
按照年齡從小到大,自定義排序結果:
李二:17,李一:18,李三:19,李五:20,李四:21,
需要注意的是,TreeSet不能添加為空的元素,否則會報空指針錯誤!
EnumSet 是一個與枚舉類型一起使用的專用 Set 集合,繼承自AbstractSet抽象類。與 HashSet、LinkedHashSet 、TreeSet 不同的是,EnumSet 元素必須是Enum的類型,並且所有元素都必須來自同一個枚舉類型,EnumSet 定義源碼如下:
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable {
......
}
EnumSet是一個虛類,不能直接通過實例化來獲取對象,只能通過它提供的靜態方法來返回EnumSet實現類的實例。
EnumSet的實現類有兩個,分別是RegularEnumSet、JumboEnumSet兩個類,兩個實現類都繼承自EnumSet。
EnumSet會根據枚舉類型中元素的個數,來決定是返回哪一個實現類,當 EnumSet元素中的元素個數小於或者等於64,就會返回RegularEnumSet實例;當EnumSet元素個數大於64,就會返回JumboEnumSet實例。
這一點,我們可以從源碼中看出,源碼如下:
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
//當元素個數小於或者等於 64 的時候,返回 RegularEnumSet
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
//大於64,返回 JumboEnumSet
return new JumboEnumSet<>(elementType, universe);
}
noneOf是EnumSet中一個靜態方法,用於判斷是返回哪一個實現類。
我們來看看當元素個數小於等於64的時候,使用RegularEnumSet的類,源碼如下:
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
}
RegularEnumSet 通過二進制運算得到結果,直接使用long來存放元素。
我們再來看看當元素個數大於64的時候,使用JumboEnumSet的類,源碼如下:
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
}
JumboEnumSet 也是通過二進制運算得到結果,使用long來存放元素,但是它是使用數組來存放元素。
二者相比,RegularEnumSet 效率比 JumboEnumSet 高些,因為操作步驟少,大多數情況下返回的是 RegularEnumSet,只有當枚舉元素個數超過 64 的時候,會使用 JumboEnumSet。
添加元素:
//新建一個EnumEntity的枚舉類型,定義2個參數
public enum EnumEntity {
WOMAN,MAN;
}
創建一個空的 EnumSet:
//創建一個 EnumSet,內容為空
EnumSet<EnumEntity> noneSet = EnumSet.noneOf(EnumEntity.class);
System.out.println(noneSet);
輸出結果:
[]
創建一個 EnumSet,並將枚舉類型的元素全部添加進去:
//創建一個 EnumSet,將EnumEntity 元素內容添加到EnumSet中
EnumSet<EnumEntity> allSet = EnumSet.allOf(EnumEntity.class);
System.out.println(allSet);
輸出結果:
[WOMAN, MAN]
創建一個 EnumSet,添加指定的枚舉元素:
//創建一個 EnumSet,添加 WOMAN 到 EnumSet 中
EnumSet<EnumEntity> customSet = EnumSet.of(EnumEntity.WOMAN);
System.out.println(customSet);
查詢元素
EnumSet與HashSet、LinkedHashSet、TreeSet一樣,通過迭代器或者 for 循環來遍歷元素,方法如下:
EnumSet<EnumEntity> allSet = EnumSet.allOf(EnumEntity.class);
for (EnumEntity enumEntity : allSet) {
System.out.print(enumEntity + ",");
}
輸出結果:
WOMAN,MAN,
HashSet 是一個輸入輸出無序的 Set 集合,元素不重復,底層基於 HashMap 的 key 來實現,元素可以為空,如果添加的元素為對象,對象需要重寫 equals() 和 hashCode() 方法來約束是否為相同的元素。
LinkedHashSet 是一個輸入輸出有序的 Set 集合,繼承自 HashSet,元素不重復,底層基於 LinkedHashMap 的 key來實現,元素也可以為空,LinkedHashMap 使用循環鏈表結構來保證輸入輸出有序。
TreeSet 是一個排序的 Set 集合,元素不可重復,底層基於 TreeMap 的 key來實現,元素不可以為空,默認按照自然排序來存放元素,也可以使用 Comparable 和 Comparator 介面來比較大小,實現自定義排序。
EnumSet 是一個與枚舉類型搭配使用的專用 Set 集合,在 jdk1.5 中加入。EnumSet 是一個虛類,有2個實現類 RegularEnumSet、JumboEnumSet,不能顯式的實例化改類,EnumSet 會動態決定使用哪一個實現類,當元素個數小於等於64的時候,使用 RegularEnumSet;大於 64的時候,使用JumboEnumSet類,EnumSet 其內部使用位向量實現,擁有極高的時間和空間性能,如果元素是枚舉類型,推薦使用 EnumSet。
1、JDK1.7&JDK1.8 源碼
2、程序園 - java集合-EnumMap與EnumSet
3、 Java極客技術 - https://blog.csdn.net/javageektech/article/details/103077788
② nginx 源代碼分析 (一)
ngx_pool_t提供內存分配介面。
ngx_pool_t對大塊內存和小塊內存的分配使用不同的策略。
對於大塊內存(超過指定閾值,一般是內存的頁大小4096),調用malloc()動態分配。
對於小塊內存,則是先預分配大的內存塊,然後根據需要從中動態分配小塊的。
ngx_create_pool()創建這個單向鏈表的第一個元素。
ngx_palloc()從指定的ngx_pool_t實例中分配內存。如果要求大塊內存,則調用ngx_palloc_large(),否則調用ngx_palloc_small()。
對於ngx_palloc_small(),
對於ngx_palloc_large(),
ngx_free()負責釋放內存。它只是調用free()釋放大塊內存。實際上小塊內存是不能一個一個釋放的,nginx的策略是釋放就釋放全部。
ngx_reset_pool()釋放所有大塊內存,將ngx_pool_t鏈表置於未使用狀態。
ngx_destroy_pool()釋放所有大塊內存,也釋放ngx_pool_t鏈表自身佔用的內存。
nginx_pool_t還用於保存「待清理的任務」,這個任務保存在ngx_pool_cleanup_t結構中,從預分配內存中分配。這也是一個單向鏈表,保存在ngx_pool_t的成員cleanup中。
ngx_pool_cleanup_t的成員handler是任務的處理函數,成員data是處理函數的參數。
ngx_array_t實現了數組。
ngx_array_create()創建數組。
ngx_array_push()從數組中得到一個可用的元素。
ngx_list_create()實現單向鏈表。與一般鏈表不同的是,它的鏈表中每一個元素中保存的是一個數組。下圖是包含兩個ngx_list_part_t元素的鏈表。
ngx_list_create()創建一個鏈表。
ngx_list_push()從鏈表中得到一個可用的位置。
ngx_queue_t是一個雙向鏈表。
使用ngx_queue_t的方式是,在結構中包含ngx_queue_t,就可以把結構串聯起來。如下面的示意圖。
ngx_queue_data()可以根據ngx_queue_t成員在結構中的位置偏移,從成員地址計算結構地址。
ngx_rbtree_t實現紅黑樹,ngx_rbtree_node_t是樹上的節點。
對於ngx_rbtree_node_t,
對於ngx_rbtree_t,
③ 哈希演算法從原理到實戰
引言
將任意長度的二進制字元串映射為定長二進制字元串的映射規則我們稱為散列(hash)演算法,又叫哈希(hash)演算法,而通過原始數據映射之後得到的二進制值稱為哈希值。哈希表(hash表)結構是哈希演算法的一種應用,也叫散列表。用的是數組支持按照下標隨機訪問數據的特性擴展、演化而來。可以說沒有數組就沒有散列表。
哈希演算法主要特點
從哈希值不能反向推導原始數據,也叫單向哈希。
對輸入數據敏感,哪怕只改了一個Bit,最後得到的哈希值也大不相同。
散列沖突的概率要小。
哈希演算法執行效率要高,散列結果要盡量均衡。
哈希演算法的核心應用
安全加密 :對於敏感數據比如密碼欄位進行MD5或SHA加密傳輸。
唯一標識 :比如圖片識別,可針對圖像二進制流進行摘要後MD5,得到的哈希值作為圖片唯一標識。
散列函數 :是構造散列表的關鍵。它直接決定了散列沖突的概率和散列表的性質。不過相對哈希演算法的其他方面應用,散列函數對散列沖突要求較低,出現沖突時可以通過開放定址法或鏈表法解決沖突。對散列值是否能夠反向解密要求也不高。反而更加關注的是散列的均勻性,即是否散列值均勻落入槽中以及散列函數執行的快慢也會影響散列表性能。所以散列函數一般比較簡單,追求均勻和高效。
*負載均衡 :常用的負載均衡演算法有很多,比如輪詢、隨機、加權輪詢。如何實現一個會話粘滯的負載均衡演算法呢?可以通過哈希演算法,對客戶端IP地址或會話SessionID計算哈希值,將取得的哈希值與伺服器列表大小進行取模運算,最終得到應該被路由到的伺服器編號。這樣就可以把同一IP的客戶端請求發到同一個後端伺服器上。
*數據分片 :比如統計1T的日誌文件中「搜索關鍵詞」出現次數該如何解決?我們可以先對日誌進行分片,然後採用多機處理,來提高處理速度。從搜索的日誌中依次讀取搜索關鍵詞,並通過哈希函數計算哈希值,然後再跟n(機器數)取模,最終得到的值就是應該被分到的機器編號。這樣相同哈希值的關鍵詞就被分到同一台機器進行處理。每台機器分別計算關鍵詞出現的次數,再進行合並就是最終結果。這也是MapRece的基本思想。再比如圖片識別應用中給每個圖片的摘要信息取唯一標識然後構建散列表,如果圖庫中有大量圖片,單機的hash表會過大,超過單機內存容量。這時也可以使用分片思想,准備n台機器,每台機器負責散列表的一部分數據。每次從圖庫取一個圖片,計算唯一標識,然後與機器個數n求余取模,得到的值就是被分配到的機器編號,然後將這個唯一標識和圖片路徑發往對應機器構建散列表。當進行圖片查找時,使用相同的哈希函數對圖片摘要信息取唯一標識並對n求余取模操作後,得到的值k,就是當前圖片所存儲的機器編號,在該機器的散列表中查找該圖片即可。實際上海量數據的處理問題,都可以藉助這種數據分片思想,突破單機內存、CPU等資源限制。
*分布式存儲 :一致性哈希演算法解決緩存等分布式系統的擴容、縮容導致大量數據搬移難題。
JDK集合工具實現 :HashMap、 LinkedHashMap、ConcurrentHashMap、TreeMap等。Map實現類源碼分析,詳見 https://www.jianshu.com/p/602324fa59ac
總結
本文從哈希演算法的原理及特點,總結了哈希演算法的常見應用場景。
其中基於余數思想和同餘定理實現的哈希演算法(除留取余法),廣泛應用在分布式場景中(散列函數、數據分片、負載均衡)。由於組合數學中的「鴿巢」原理,理論上不存在完全沒有沖突的哈希演算法。(PS:「鴿巢」原理是指有限的槽位,放多於槽位數的鴿子時,勢必有不同的鴿子落在同一槽內,即沖突發生。同餘定理:如果a和b對x取余數操作時a%x = b%x,則a和b同餘)
構造哈希函數的常規方法有:數據分析法、直接定址法、除留取余法、折疊法、隨機法、平方取中法等 。
常規的解決哈希沖突方法有開放定址法(線性探測、再哈希)和鏈表法。JDK中的HashMap和LinkedHashMap均是採用鏈表法解決哈希沖突的。鏈表法適合大數據量的哈希沖突解決,可以使用動態數據結構(比如:跳錶、紅黑樹等)代替鏈表,防止鏈表時間復雜度過度退化導致性能下降;反之開放定址法適合少量數據的哈希沖突解決。
④ 求java學習路線圖
二進制和十進制的轉化
注釋、單行注釋、多行注釋、文本注釋、注釋內容和位元組碼的關系
標識符、關鍵字、駝峰原則
變數的本質、內存畫圖、變數聲明和初始化
變數的分類和作用域(局部變數、成員變數、靜態變數)
常量和Final
基本數據類型介紹
整型變數和整型常量
浮點類型、float、double
char字元型、轉義字元
boolean布爾型、if語句使用要點、布爾類型佔用空間問題
運算符介紹
算數運算符(二元、自增、自減)
賦值和賦值運算符
關系運算符詳解
邏輯運算符、短路運算符詳解
位運算符詳解
字元串連接符
條件運算符(三元運算符)
運算符優先順序問題
自動類型轉換詳解
強制類型裝換詳解
基本數據類型裝換常見錯誤、溢出、L問題
使用Scanner獲取鍵盤輸入
控制語句和實現邏輯對應
if單選結構
if_elseif_else多選結構
switch語句_IDEA更換主題
循環_while
循環_for循環_dowhile
嵌套循環
break和continue語句_標簽_控制語句底層原理
寫一個年薪計算機_網路查問題的秘訣(重要)
個人所得稅計算器軟體
方法核心詳解_天才思維模型教你高手學習思維模式
方法的重載
遞歸結構講解_遞歸頭_遞歸體
面向過程和面向對象的區別
類和對象的概述
類的屬性和方法
創建對象內存分析
構造方法(Construtor)及重載
對象類型的參數傳遞
this關鍵字
static關鍵字詳解
局部代碼塊、構造代碼塊和靜態代碼塊
package和import詳解
JavaDoc生成API文檔
面向對象的三大特性
面向對象之【封裝(Encapsulation)】
訪問許可權修飾符
面向對象之【繼承(Inheritance)】
Object類
方法重寫Override
super關鍵字詳解
重寫equals()和toString()
繼承中對象創建的內存分析
面向對象之【多態(Polymorphism)】
向上轉型
向下轉型
instanceof運算符
編譯時和運行時詳解
final修飾符
抽象類和抽象方法(abstrct)
介面的定義和實現
JDK8的介面新特性
介面應用:內部類比較器Comparable
內部類詳解
Java的內存管理與垃圾回收
異常的概述
異常的執行過程與分析
try-catch-finally捕捉異常
throw拋出異常
throws聲明異常
異常繼承體系
運行時異常和編譯異常
自定義異常
自動裝箱和自動拆箱
包裝類的源碼分析
String類的使用與內存原理
String類的源碼分析
StringBuffer
StringBuilder
字元串處理類性能分析
Date類
System類
DateFormat類
Calendat類
Math類
BigInteger類和BigDecimal類
Random類
枚舉類
File類
常見的面試題講述與分析
數據結構演算法
數據結構的概述
線性表
順序表
鏈表
棧和隊列
樹
二叉樹
二叉查找樹
二叉平衡樹
黑紅樹
圖
冒泡排序
選擇排序
遞歸
折半查找
集合(容器)
集合和數組的聯系和區別
集合框架體系
ArrayList的使用和源碼分析
集合中使用泛型
LinkedList的使用和源碼分析
HashSet的使用和源碼分析
哈希表及原理
TreeSet的使用和源碼分析
比較器Comparable和Comparator
HashMap的使用和源碼分析
TreeMap的使用和源碼分析
Iterator於ListIterator
Collections工具類
舊集合類Vector、Hashtable
集合總結和選擇依據
泛型介面
泛型類
泛型方法
IO流
IO流的概念
IO流的分類及其原理分析
文件流FlieInputStream、FileOutputStream
緩沖流BufferedInputStream、BufferedOutputStream
數據流ObjectInputStream、ObjectOutputStream
序列化和反序列化
轉換流InputStreamReader、OutputStreamWriter
列印流PrintWrite和PrintStream
數組流ByteArrayOutputStream、ByteArrayInputStream
使用IO復制文件夾
多線程
進程和線程
線程的創建與啟動
創建線程的三種方式對比
線程的生命周期
線程式控制制
多線程的安全問題與解決辦法
線程的同步:同步代碼塊
線程的同步:同步方法
線程的同步:Lock鎖
線程的死鎖問題
線程通信
Condition
線程的完整生命周期
線程池ThreadPoolExecutor
ForkJoin框架
ThreadLocal類
網路編程
計算機網路基礎知識
網路通信協議
OSI參考模型
TCP/IP參考模型
數據的封裝與拆封原理解析
TCP協議
UDP協議
IP地址和埠號
URL和Socket
使用TCP編程實現登錄功能
使用UDP編程實現客服系統
使用TCP編程實現文件上傳
集合提升尋訓練
手寫ArrayList
手寫單鏈表
手寫Linkedlist
手寫HashMap
手寫HashSet
最新並發集合類
多線程提升訓練
生產者消費者模式擴展
Lock鎖和Condition
ReadWriteLock
BlockingQueue
volatile關鍵字
多線程題目練習
JDK新特徵
面試題詳解
設計模式
設計模式入門
面向對象設計七大原則
簡單工廠模式
工廠方法模式
單例模式
原型模式
裝飾模式
適配器模式
外觀模式
MySQL基礎
資料庫基礎知識
MySQL基礎知識
MySQL8新特徵
安裝和卸載MySQL8
使用navicat訪問資料庫
SQL語言入門
創建資料庫表
DML
修改刪除資料庫表
表的完整性約束
表的外鍵約束
DML擴展
MySQL 查詢語句
基本select查詢
where子句
函數
group by
having
SQL99-內連接查詢
SQL99-外連接查詢
SQL99-自連接查詢
SQL92-連接查詢
不相關子查詢
相關子查詢
分頁查詢
資料庫對象
索引
事務及其特徵
事務的並發問題
事務的隔離級別
存儲過程
導入導出數據
JDBC
JDBC概述
使用JDBC完成添加/更新/刪除操作
使用JDBC完成查詢操作
JDBC常用介面
使用PreparedStatement
使用事務完成銀行轉賬
提取DBUtil工具類
使用Properties讀寫屬性文件
日誌框架log4j
開發員工管理系統
第三階段:JavaEE階段
Servlet
web開發概述
B/S和C/S架構簡介
HTTP協議
HTTP請求頭和響應頭
Tomcat安裝使用
Tomcat目錄結構
Servlet概述
Servlet快速入門
Servlet生命周期
讀取配置文件信息
HttpServletRequest
HttpServletResponse
GET和POST區別
解決中文亂碼
請求轉發與重定向
絕對路徑和相對路徑
Cookie
Session
ServletContext
ServletConfig
JSP
JSP技術介紹
JSP的執行過程
scriptlet
表達式
聲明
JSP指令元素
JSP動作元素
JSP隱式對象
JSP底層原理
九大內置對象
四個作用域
Servlet和JSP的關系和區別
MVC模式
合並Servlet
JavaScript
JavaScript概述與特點
JS基礎語法
函數
數組
Math對象
String對象
Date對象
事件event
瀏覽器開發者工具
console
DOM和BOM
window
location
navigator
history
認識DOM
DOM獲取元素
jQuery
jQuery簡介及快速入門
jQuery入口函數
jQuery對象與DOM對象互相轉換
基本選擇器
屬性選擇器
位置選擇器
表單選擇器
內容選擇器
jQuery事件
jQuery動畫效果
DOM操作-操作文本
DOM操作-操作屬性
DOM操作-操作元素
直接操作CSS樣式
操作CSS類樣式
購物車案例
表單驗證
正則表達式
EL+JSTL+過濾器+監聽器
EL介紹及使用
EL取值原理
EL隱含對象
EL邏輯運算
JSTL介紹-核心標簽庫
JSTL核心標簽庫
JSTL-格式標簽庫
Filter原理
Filter生命周期
Filter鏈
Filter登錄驗證
Filter許可權控制
Listener概述及分類
Listener監聽在線用戶
Ajax和JSON
Ajax非同步請求和局部刷新的原理
使用原生Ajax驗證用戶唯一性
jQuery Ajax
JSON的格式和使用
主要JSON解析器
Jackson的使用
Jackson的實現原理
使用jQuery Ajax實現三級聯動
使用jQuery Ajax實現自動補全
分頁和文件上傳/下載
分頁的意義
理解分頁工具類
實現基本分頁
實現帶查詢的分頁
文件上傳原理
文件上傳API
實現文件上傳
文件下載原理
文件下載響應頭
實現文件下載
第四階段:框架階段
MyBatis
MyBatis概述
MyBatis入門配置
基本的CRUD操作
核心配置文件詳解
Mapper.xml基礎詳解
模糊查詢
分頁的實現及插件PageHelper的使用
動態sql+sql片段的使用
一對多、多對一的關系處理
註解的使用
一級緩存和二級緩存說明及使用
generator逆向工程使用
Spring
Spring框架簡介
Spring官方壓縮包目錄介紹
Spring環境搭建
IoC/DI容器詳解
Spring創建Bean的三種方式
scope屬性講解
Spring中幾種注入方式
靜態代理設計模式
動態代理設計模式
AOP詳解
AOP中幾種通知類型
AOP兩種實現方式
自動注入
聲明式事務
事務傳播行為
事務隔離級別
只讀事務
事務回滾
基於註解式配置
常用註解
Spring 整合MyBatis
i18n
Spring整合Junit
SpringMVC
MVC架構模式
手寫MVC框架
SpringMVC簡介
SpringMVC運行原理
基於配置文件方式搭建環境
基於註解方式搭建環境
SpringMVC的跳轉及視圖解析器的配置
SpringMVC和Ajax的交互
Spring 參數注入
SpringMVC作用域傳值
視圖解析器
文件下載
文件上傳
Spring攔截器/攔截器棧
登錄狀態驗證
SpringMVC容器和Spring容器介紹
異常處理4種方式
SpringMVC5其他常用註解
Maven
Maven簡介
Maven原理
Linux安裝及注意事項
Maven項目結構
POM模型
Maven 中項目類型
創建WAR類型的Maven項目
scope屬性可取值
SSM項目拆分演示
Maven的常見插件講解
熱部署
BootStrap
BootStrap概述
BootStrap柵格系統
BootStrap常用全局CSS樣式
常用組件
常用JavaScript插件
RBAC
RBAC概述
RBAC發展歷史
基於RBAC的資料庫表設計
URL攔截實現
動態菜單實現
密碼學
第五階段:前後端分離階段
Spring Boot
Spring Boot簡介
Spring Boot實現Spring MVC
配置文件順序及類型講解
Spring Boot項目結構
Spring Boot 整合MyBatis
Spring Boot 整合Druid
Spring Boot 整合PageHelper
Spring Boot 整合logback
Spring Boot 整合JSP
Spring Boot 整合Thymeleaf
Spring Boot 開發者工具
Spring Boot 異常顯示頁面
Spring Boot 整合Junit4
Spring Boot 項目打包部署
Spring Boot 整合Quartz
Spring Boot 中Interceptor使用
Spring Boot Actuator
HikariCP
Logback
Logback簡介
Logback依賴說明
Logback 配置文件講解
Logback 控制台輸出
Logback 文件輸出
Logback 資料庫輸出
Spring Security
Spring Security簡介
Spring Security架構原理
什麼是認證和授權
基礎環境搭建
自定義認證流程
UserDetailsService和UserDetails
PasswordEncoder
自定義認證結果
授權-訪問路徑匹配方式
授權-許可權管理
基於註解實現許可權管理
Thymeleaf整合Security許可權管理
Rememberme 實現
退出實現
CSRF
Linux - CentOS 8
Linux簡介
VMWare安裝及使用
Linux安裝及注意事項
Linux目錄結構及路徑
Linux常用命令
VMWare常用配置
XShell安裝及使用
Xftp安裝及使用
JDK解壓版配置步驟
Tomcat配置步驟
安裝MySQL
WAR包部署
Docker
Docker簡介
Docker與VM對比
Docker特點
Docker架構
Docker安裝與啟動
鏡像加速器配置
Docker鏡像操作常用命令
Docker容器操作常用命令
DockerFile
搭建本地鏡像倉庫
推送鏡像到阿里雲及本地倉庫
Docker容器生命周期
Docker數據管理
Redis
Redis簡介
Redis 單機版安裝
Redis 數據類型介紹
Redis 常用命令
Redis 持久化方案
Redis 的主從搭建
Redis的哨兵搭建
Redis 的集群搭建
Spring Boot整合Spring Data Redis
Redis的緩存穿透
Redis的緩存雪崩
Redis的緩存擊穿
Vue
vsCode和插件安裝
webpack介紹
Vue項目創建
Vue模板語法
Vue條件渲染
Vue列表渲染
Vue事件處理
Vue計算屬性
Vue Class與Style
Vue表單處理
Vue組件
Vue組件生命周期
Vue 路由配置
Vue Axios網路請求
Vue跨域處理
Vue Element
Mock.js
Swagger
Swagger2簡介
Springfox
Swagger2基本用法
Swagger-UI用法
Swagger2配置
Swagger2常用配置
Git/GitEE
Git的下載和安裝
Git和SVN對比
Git創建版本庫
Git版本控制
Git遠程倉庫
Git分支管理
Git標簽管理
GitEE建庫
GitEE 連接及使用
GitEE 組員及管理員配置
第六階段:微服務架構
FastDFS
分布式文件系統概述
FastDFS簡介
FastDFS架構
Tracker Server
Storage Server
FastDFS安裝
安裝帶有FastDFS模塊的Nginx
Fastdfs-java-client的使用
創建Fastdfs-java-client工具類
實現文件上傳與下載
KindEditor介紹
通過KindEditor實現文件上傳並回顯
RabbitMQ
AMQP簡介
RabbitMQ簡介
安裝Erlang
安裝RabbitMQ
RabbitMQ原理
Spring Boot 集成RabbitMQ
RabbitMQ的交換器
Spring AMQP的使用
Spring Cloud Netflix Eureka
Eureka簡介
Eureka和Zookeeper 對比
搭建Eureka注冊中心
Eureka 服務管理平台介紹
搭建高可用集群
集群原理
Eureka優雅停服
Spring Cloud Netflix Ribbon
Ribbon簡介
集中式與進程內負載均衡區別
Ribbon常見的負載均衡策略
Ribbon的點對點直連
Spring Cloud OpenFeign
Feign簡介
Feign的請求參數處理
Feign的性能優化
配置Feign負載均衡請求超時時間
Spring Cloud Netflix Hystrix
Hystrix簡介
服務降級
服務熔斷
請求緩存
Feign的雪崩處理
可視化的數據監控Hystrix-dashboard
Spring Cloud Gateway
Spring Cloud Gateway簡介
Gateway基於配置文件實現路由功能
Gateway基於配置類實現路由功能
Gateway中內置過濾器的使用
Gateway中自定義GatewayFilter過濾器的使用
Gateway中自定義GlobalFilter過濾器的使用
Gateway中使用過濾器實現鑒權
Gateway結合Hystrix實現熔斷功能
Spring Cloud Config
什麼是分布式配置中心
創建配置中心服務端
創建配置中心客戶端
基於Gitee存儲配置文件
基於分布式配置中心實現熱刷新
Spring Cloud Bus
什麼是消息匯流排
基於消息匯流排實現全局熱刷新
ELK
ElasticSearch介紹
ElasticSearch單機版安裝
ElasticSearch集群版安裝
ElasticSearch索引管理
ElasticSearch文檔管理
ElasticSearch文檔搜索
SpringDataElasticSearch訪問ElasticSearch
LogStash介紹
基於LogStash收集系統日誌
TX-LCN
分布式事務簡介
分布式事務兩大理論依據
分布式事務常見解決方案
LCN簡介
TX-LCN的3種模式
LCN原理
LCN環境搭建及Demo演示
Nginx
Nginx的簡介
什麼是正向代理、反向代理
Nginx的安裝
Nginx配置虛擬主機
Nginx配置服務的反向代理
Nginx的負載均衡配置
Spring Session
Spring Session介紹
通過Spring Session共享session中的數據
通過Spring Session同步自定義對象
Spring Session的Redis存儲結構
設置Session失效時間
Spring Session序列化器
MyBatis Plus
MyBatis Plus簡介
Spring整合MyBatis Plus
MyBatis Plus的全局策略配置
MyBatis 的主鍵生成策略
MyBatis Plus的CRUD操作
條件構造器EntityWrapper講解
MyBatis Plus的分頁插件配置
MyBatis Plus的分頁查詢
MyBatis Plus的其他插件講解
MyBatis Plus的代碼生成器講解
MyBatis Plus的公共欄位自動填充
ShardingSphere
簡介
資料庫切分方式
基本概念
MySQL主從配置
切片規則
讀寫分離
實現分庫分表
第七階段:雲服務階段
Kafka
Kafka簡介
Kafka架構
分區和日誌
Kafka單機安裝
Kafka集群配置
自定義分區
自動控制
Spring for Apache Kafka
Zookeeper
Zookeeper簡介和安裝
Zookeeper 數據模型
Zookeeper 單機版安裝
Zookeeper常見命令
ZClient操作Zookeeper
Zookeeper 集群版安裝
Zookeeper 客戶端常用命令
Zookeeper分布式鎖
RPC
什麼是分布式架構
什麼是RFC、RPC
HttpClient實現RPC
RestTemplate
RMI實現RPC
基於Zookeeper實現RPC 遠程過程調用
Dubbo
SOA架構介紹
Dubbo簡介
Dubbo結構圖
Dubbo注冊中心
Dubbo 支持的協議
Dubbo 注冊中心搭建
Spring Boot 整合 Dubbo
Admin管理界面
Dubbo 搭建高可用集群
Dubbo 負載均衡
Spring Cloud Alibaba Dubbo
Spring Cloud Alibaba Dubbo簡介
基於Zookeeper發布服務
基於Zookeeper訂閱服務
實現遠程服務調用處理
Spring Cloud Alibaba Nacos
Spring Cloud Alibaba Nacos簡介
搭建Nacos伺服器
基於Nacos發布|訂閱服務
實現遠程服務調用處理
Nacos Config配置中心
Spring Cloud Alibaba Sentinel
Spring Cloud Alibaba Sentinel簡介
搭建Sentinel伺服器
Sentinel-實時監控
Sentinel-簇點鏈路
Sentinel-授權規則
Sentinel-系統規則
@SentinelResource註解
持久化規則
Spring Cloud Alibaba Seata
Spring Cloud Alibaba Seata簡介
搭建Seata伺服器
Seata支持的事務模式-AT模式
Seata支持的事務模式-TCC模式
Seata支持的事務模式-Saga模式
Seata支持的事務模式-XA模式
SeataAT事務模式應用方式
SeataTCC事務模式應用方式