集合中的最上层接口只有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核心知识点总结!