【第三十一期】360後臺開發實習面經 - 兩輪技術面
集合:
·陣列其實就是一個集合;集合實際上就是一個容器;
·集合通常在實際開發中,用於查詢資料庫返回的多條資料,然後存放資料庫資料比較多;
·集合不能直接儲存基本資料型別,也不能儲存java物件;
·集合中儲存的都是java物件中的記憶體地址(引用);
·java中每個不同的集合,底層都對應了不同的資料結構;在集合中儲存不同的元素,就相當於在不同的資料結構中儲存元素,而且每種資料結構儲存元素的方式也不同;
例如:陣列,二叉樹、連結串列、雜湊表,等等;
在java中集合分為兩大類:
·一類是以單個方式儲存元素;
該類的超級父介面是:java.util.collection;
·一類以鍵值對的方式儲存元素;
該類的超級父介面是:java.util.Map;
collection單個方式儲存元素:
List集合儲存元素的特點:
·有序的、可重複的,儲存的元素有下標,該處的“有序”不是從大到小排序的意思,而是元素儲存進入是這個順序,取出來也是這個順序;
set集合儲存元素的特點:
·無序的、不可重複;該集合中,元素沒有下標,元素不可重複,該處的“無序”指的是存元素時是該順序,但取出來不一定是存進去的順序;
·可以呼叫sort()方法進行排序,但對List中的元素進行排序,需要保證List集合中的元素實現了Comparable介面;
List與set集合的特點是相對的;
List下的關係集合:
ArrayList、LinkedList、Vector的區別:
·ArrayList底層程式碼採用了陣列的資料結構,該集合是非執行緒安全的;
·LinkedList底層程式碼採用了雙向連結串列的資料結構;
·Vector底層程式碼採用了陣列的資料結構,該集合是執行緒安全的;但是效率較低;
Set下的關係集合:
·HashList 實際上,底層在new的時候,new的是一個HashMap集合,而往HashList中儲存元素,本質上就是在向HashMap集合中儲存元素,而HashMap集合是一個雜湊表資料結構;
·sortedSet集合儲存元素的特點,因為繼承了Set集合,所有它的特點也是無序不可重複的,但是放在sortedSet的元素可以自動排序,可成為有序排序,該集合中的元素自動按照 大小進行順序排序;
·SortSet 介面下有個實現類,這個實現類就是TreeSet;
·TreeSet 實際上,底層在new的時候,new的是一個TreeMap集合,而往TreeSet中儲存元素,本質上就是在向TreeMap集合中儲存元素,TreeMap集合採用了二叉樹的資料結構;
Map以鍵值對的方式儲存元素:
·Map集合與Collection集合是沒有關係的;
·Map集合以key和value的方式儲存元素;
·key和value都是儲存java物件的記憶體地址;
·Map下的兩個常用實現類,HashMap和Hashtable;
·所有Map集合,它的特點都是無序不可重複的;
·Map集合的key和set集合儲存的特點相同;
HashMap和Hashtable的區別:
·HashMap是非執行緒安全的,底層採用的是雜湊表資料結構;
·Hashtable是執行緒安全的,底層採用的是雜湊表資料結構;因為執行緒安全,該集合效率較低;
Properties的特點:
·Properties是執行緒安全的因為繼承了Hashtable,另外properties儲存元素的時候,也是採用key和value的形式儲存,並且key和value只支援String型別的資料,不支援其他型別;
Collection:
在沒有使用“泛型”之前,collection可以儲存所有object的子型別,
使用了“泛型”之後,collection只能儲存某個指定的型別;
注:集合中不能儲存基本資料型別,也不能儲存java物件,只是儲存java物件的記憶體地址;
Collection中的迭代器,iterator();迭代/遍歷;
迭代器是一個物件;
Interator();迭代器中的remove()方法,底層會調equals();只要內容一樣,即使記憶體地址不同,也可以刪除;但是前提是equals()必須重寫;
集合結構只要發生改變,迭代器必須重新獲取;
而且在迭代的過程中,不能呼叫集合的remove方法;但是可以呼叫迭代器的remove方法;
簡單的說,就是集合中的結構發生改變了,迭代器需要重新獲取,而且在迭代時,若想要刪除元素,必須使用iterator(迭代器)自帶的remove方法;
Collection中的contions和remove方法,底層都會呼叫equals方法,因此equals方法需要重寫;
ArrayList:
·ArrayList初始化的容量為10;(底層先建立了一個長度為0的陣列,當新增第一個元素時,初始化容量為10)
·ArrayList底層是一個object[]陣列;
·ArrayList集合的擴容:增長到原容量的1.5倍;
·在使用ArrayList集合的底層的陣列,陣列儘量少擴容,因為效率較低,最後先預估定一個容量值;
·ArrayList集合是非執行緒安全的;
單向連結串列:
連結串列的基本結構是節點(node),對應單向連結串列來說,任何一個節點node都有兩個屬性;
第一個屬性:儲存的資料;
第二個屬性:下一個節點的記憶體地址;(節點的記憶體地址是不連續的)
連結串列的優點:
隨機增刪元素效率較高;(因為增刪元素不涉及到大量元素位移)
連結串列的缺點:
查詢效率較低,每次查詢某個元素時,都需要從頭節點開始遍歷;
雙向連結串列(LinkedList):
雙向連結串列的基本單元還是節點node,雙向連結串列有三個屬性;
第一個屬性:上一個節點的記憶體地址;
第二個屬性:節點元素;
第三個屬性:下一個節點的記憶體地址;
LinkedList集合沒有初始化容量;最初連結串列中沒有任何元素,first和last都是null
LinkedList是一個雙向連結串列;連結串列對於隨機增刪來說,效率較高;但查詢某個元素效率較低;
連結串列中的(節點)元素在空間記憶體上,記憶體地址不連續;
Vector:
Vector底層也是一個數組,初始化容量是10,它是執行緒安全的;
Vector擴容後的容量,是原容量的2倍;原容量*2;
ArrayList集合的擴容容量是:原容量的1.5倍;原容量*1.5;
如何將一個非執行緒安全的ArrayList集合轉換為一個執行緒安全的集合:
使用集合工具類:java.util.collections;
注意:java.util.collection;是集合介面,
java.util.collections;是集合工具類,不要搞混了;
把一個非執行緒安全的ArrayList集合轉換成一個執行緒安全的,呼叫collections下的一個方法synchronizedList();即可;
語法:List myList=new ArrayList();
引入java.util.collections包;
Collections.synchronizedList(myList); //這樣就可以將一個非執行緒安全的集合轉換成一個執行緒安全的集合;
泛型機制:
泛型機制是jdk5.0之後推出的新特性;
使用泛型後,集合中,只能儲存指定的元素型別;
泛型屬性編譯階段的一個新特性,在執行時階段,沒什麼用處;
泛型的優點:
使用泛型之後,集合中,在獲取元素時,不需要進行過多的“向下轉型”;
泛型的缺點:
使用泛型之後,集合中儲存的元素相對單一,缺乏多樣性;
但是泛型在呼叫子類特有的方法時,還是需要進行“向下轉型”的;
自動型別推斷機制(鑽石表示式):
自動型別推斷機制是jdk8之後才有的新特性;
Jdk8之前:List<User> myList=new ArrayList<User>();
Jdk8之後:List<User> myList=new ArrayList<>();
Map集合:
使用時,需要引用java.util.Map;包
Map和Collection是沒有繼承關係的;
Map的儲存資料方式是以key和value的方式儲存資料,鍵值對的方式;
Key和vakue都是引用資料型別;
Key和value都是儲存物件的記憶體地址;
key起到一個主導地位,而value是key的一個附屬品;
Map中有一個Set<Map.Entry<K,Y>> entrySet();方法;
Map集合通過entrySet()方法轉換為這個Set集合,Set集合中,元素的型別是Map.Entry,Map.Entry其實是一個類,一個靜態內部類,和String差不多;是Map中的一個內部類;
(HashMap)雜湊表資料結構:
HahsMap底層是一個雜湊表/散列表的資料結構;是非執行緒安全的;
雜湊表是一個數組和單向連結串列的結合體;它結合了陣列與單向連結串列的優點;
HashMap實際上,可以理解為是一個一維陣列,然後陣列中的每一個元素是一個單向連結串列;
Map.put(k,v)的新增元素實現原理:
第一步:先將k,y封裝到node的物件中;
第二步:底層會呼叫hashCode()的方法得出hash值,然後通過雜湊函式/雜湊演算法,將hash值轉換成陣列的下標,下標位置上如果沒有任何元素,則會將node新增到這個位置上,如 果下標對應的位置上有連結串列,此時會拿著k和連結串列中所有的k進行equals對比,如果所有對比後的結果是false,那麼這個新節點則會新增到連結串列的末尾,如果有其中一個k返回的結果 是true, 那麼就會把原先相同的那個k,把該k中的value值覆蓋掉/替換掉;
Map.get(k)的獲取元素實現原理:
先呼叫k的hashCode()方法得出雜湊值,通過雜湊演算法將雜湊值轉換成陣列下標,然後通過陣列下標快速定位到某個位置上,如果這個位置上什麼都沒有,則會返回null,如果這個 位置上有連結串列,則會拿著引數k與連結串列中的所有k,呼叫equals()方法進行對比,如果equals()方法返回false,那麼get()方法也就返回null,如果equals()返回的是true,
此時就會把返回為true的這個k給到get()方法,而get()方法最終就返回要找的這個value;
HashMap集合的初始容量是16,預設載入因子是0.75,也就是當集合底層的陣列容量達到75%的時候,陣列開始擴容;
注意:HashMap的初始容量必須是2的倍數,這也是官方推薦的,因為可以達到雜湊分佈均勻,為了提高HashMap集合的存取效率,所必須的;擴容後是原容量的2倍;
在jdk8之後,如果單向連結串列中元素超過8個,單向連結串列資料結構會自動變成紅黑樹資料結構,當紅黑樹的節點數量小於6時,紅黑樹資料結構會自動變回單向連結串列資料結構;
Hashtable集合:
該集合是執行緒安全的,但hashtable對執行緒安全處理效率較低,使用較少;
Hashtable和HashMap一樣,底層都是雜湊表資料結構;
該集合的初始容量是11,預設載入因子是0.75f;擴容後的容量是:原容量*2+1;
Properties集合:
Properties是一個集合,繼承Hashtable,properties的key和value都是String型別;properties被稱為屬性類物件;
自平衡二叉樹:
自平衡二叉樹遵循的是左小右大的原則存放;
前序遍歷:根左右;
中序遍歷:左根右;
後序遍歷:左右根;
注意:中前後說的是“根”的位置;根在前面是前序,根在中間是中序,根在後是後序;
TreeSet/TreeMap集合:
TreeSet/TreeMap集合採用的是中序遍歷方式,Iterator迭代器採用的是中序遍歷方式,左根右;
Comparable和Comparator如何選擇:
當比較規則不會發生改變時,或者比較規則只有一個時,建議選擇使用Comparable介面;
如果比較規則有多個,並且多個比較規則頻繁切換的時候,建議選擇使用Comparator介面;Comparator介面設計符合OCP原則;
Collections工具類:
Collection和Collections不同;
Collection是集合介面;
Collections是集合工具類,方便集合的操作;
Collections中有一個方法,synchronizedList()方法可以將非執行緒安全的轉變成執行緒安全;