集合中的最上層接口只有2類:Map和Collection,List和Set是Collection的下一層。java
存儲數據的流程node
key,value爲空的問題:面試
public static void main(String[] args) { HashMap<Integer, Integer> hashmap = new HashMap<>(); hashmap.put(null, null);// hashmap兩個均可以存null Hashtable<Integer, Integer> hashtable = new Hashtable<>(); hashtable.put(null, null);//hashtable任一個都不能存null,但idea不會報錯,運行會出現空指針異常 }
HashMap的長度爲何是2的冪次方?算法
答:提升數組利用率,減小衝突(碰撞)的次數,提升HashMap查詢效率數組
// 源碼計算index的操做:n是table.length if ((p = tab[i = (n - 1) & hash]) == null)
線程安全的底層原理:沒有哈希衝突就大量CAS插入+若是有哈希衝突就Syn加鎖緩存
treeMap底層使用紅黑樹,會按照Key來排序安全
public class TreeMapDemo { public static void main(String[] args) { // treeMap中自定義類須要指定比較器 // 方式一:自定義類實現Comparable接口 TreeMap<User, User> treeMap1 = new TreeMap<>(); // 方式二:建立實例指定比較器Comparator TreeMap<User, User> treeMap2 = new TreeMap<>(new Comparator<User>() { @Override public int compare(User o1, User o2) { // 定義比較規則 return 0; } }); } } public class User implements Comparable { private String id; private String username; @Override public int compareTo(Object obj) { // 這裏定義比較規則 return 0; } }
list安全類是以下兩個:Vetor、CopyOnWriteList; Collections.synchronizedLis是JDK包裝實現線程安全的工具類併發
public synchronized int capacity() { return elementData.length; } // Vetor鎖都加在方法上 public synchronized int size() { return elementCount; } public synchronized boolean isEmpty() { return elementCount == 0; } ... }
static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> { private static final long serialVersionUID = -7754090372962971524L; final List<E> list; // Collections.synchronizedList:內部類SynchronizedList,鎖加載內部類裏面 SynchronizedList(List<E> list) { super(list); this.list = list; } SynchronizedList(List<E> list, Object mutex) { super(list, mutex); this.list = list; } .... }
// CopyOnWriteList 寫加鎖 public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; // CopyOnWriteList是複製數組保證線程安全 Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
// CopyOnWriteList 讀不加鎖,原數組經過 transient volatile保證不可系列化和可見性 private transient volatile Object[] array; final Object[] getArray() { return array; } public E get(int index) { return get(getArray(), index); }
答:LinkedHashMap能夠記錄下元素的插入順序和訪問順序ide
最近最少使用算法: 根據數據的歷史訪問記錄來進行淘汰數據,其核心思想是「若是數據最近被訪問過,那麼未來被訪問的概率也更高」。函數
public class LRUTest { // 0.指定map長度size=5 private static final int size = 5; public static void main(String[] args) { // 1\. LinkedHashMap三大參數,重寫removeEldestEntry Map<String, String> map = new LinkedHashMap<String, String>(size, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry<String, String> eldest) { return size() > size; } }; // 2.添加5個數,使得map滿 map.put("1", "1"); map.put("2", "2"); map.put("3", "3"); map.put("4", "4"); map.put("5", "5"); System.out.println("map:" + map.toString()); // 3.指定map滿了,再put就會移除表頭第一個元素:1=1 map.put("6", "6"); System.out.println("map:" + map.toString()); // 4.get取出的元素,表示是經常使用的,放回到表尾 map.get("3"); System.out.println("map:" + map.toString()); } }
執行結果:
map:{1=1, 2=2, 3=3, 4=4, 5=5} map:{2=2, 3=3, 4=4, 5=5, 6=6} map:{2=2, 4=4, 5=5, 6=6, 3=3}
public class LRUCache { // 力扣146同一題 class DoubleNode { int key; int value; DoubleNode pre; DoubleNode next; DoubleNode(int key, int value) { this.key = key; this.value = value; } DoubleNode() { } } private HashMap<Integer, DoubleNode> cache = new HashMap<>(); private int size; private int capacity; private DoubleNode head, tail; public LRUCache(int capacity) { this.size = 0; this.capacity = capacity; this.head = new DoubleNode(); this.tail = new DoubleNode(); // 建立僞頭部和僞尾部,減小添加和刪除的邏輯 head.next = tail; tail.pre = head; } public int get(int key) { // 1.獲取get元素 DoubleNode node = cache.get(key); // 2.get元素不存就返回-1 if (node == null) { return -1; } // 3.get元素就移動至頭部,規定經常使用元素移動至頭部 moveToHead(node); return node.value; } public void put(int key, int value) { // 1.獲取put元素 DoubleNode node = cache.get(key); // 2.put元素不存在 if (node == null) { // 生成它 DoubleNode nowNode = new DoubleNode(key, value); // 放進cache cache.put(key, nowNode); // 添加進頭部 addToHead(nowNode); // 長度++ size++; // 判斷是否超過指定長度 if (size > capacity) { DoubleNode tail = removeTail(); cache.remove(tail.key); size--; } } else { // 3.node存在就更新value,而後移動至頭部 node.value = value; moveToHead(node); } } private void addToHead(DoubleNode node) { node.pre = head; node.next = head.next; head.next.pre = node; head.next = node; } private DoubleNode removeTail() { DoubleNode del = tail.pre; removeNode(del); return del; } private void removeNode(DoubleNode node) { node.pre.next = node.next; node.next.pre = node.pre; } private void moveToHead(DoubleNode node) { removeNode(node); addToHead(node); } }
public class IteratorDemo { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } }
迭代器在遍歷時直接訪問集合中的內容,而且在遍歷過程當中使用一個 modCount 變量。集合在被遍歷期間若是內容發生變化,就會改變modCount的值。當迭代器使用hashNext()/next()遍歷下一個元素以前,都會檢測modCount變量是否爲expectedModCount值,是的話就返回遍歷;不然拋出異常,終止遍歷
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; ... // modCount記錄當前線程更改狀態 ++modCount; ... return null; }
public class ArrayAndList { public static void main(String[] args) { // 1.數組遍歷:Arrays.toString int[] arr = {1, 2, 3}; System.out.println(Arrays.toString(arr)); // 2.數組轉成list,泛型說明不推薦使用,畫蛇添足 List<int[]> ints1 = Arrays.asList(arr); List<int[]> ints = Collections.singletonList(arr); for (int[] anInt : ints) { System.out.println(Arrays.toString(anInt)); } System.out.println("------------"); // 3.list遍歷:直接遍歷便可 ArrayList<Integer> arrayList = new ArrayList<>(); arrayList.add(1); arrayList.add(2); arrayList.add(3); System.out.println(arrayList); // 4.list轉換成數組,list名.toArray(指定數組類型和長度) Integer[] integers = arrayList.toArray(new Integer[3]); System.out.println(Arrays.toString(integers)); } }
感謝你看到這裏,文章有什麼不足還請指正,以爲文章對你有幫助的話記得給我點個贊,天天都會分享java相關技術文章或行業資訊,歡迎你們關注和轉發文章! 歡迎關注公衆號:前程有光,領取一線大廠Java面試題總結+各知識點學習思惟導+一份300頁pdf文檔的Java核心知識點總結!