Loading... ## List接口 ### 1.ArrayList 本质就是动态数组,动态扩容 ```java /** * Default initial capacity. 默认的数组的长度 */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. 空数组 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. 集合中存储数据的 数组对象 */ transient Object[] elementData; // non-private to simplify nested class access /** * The size of the ArrayList (the number of elements it contains). * 集合中元素的个数 * @serial */ private int size; ``` #### 初始操作 无参构造 ```java public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // this.elementData = {} } ``` 有参构造 ```java public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // 初始长度大于0 就创建一个指定大小的数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // {}数组赋值给 this.elementData this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } ``` #### add方法 初始无参构造器 ##### 第一次添加 ```java public boolean add(E e) { // 确定容量 动态扩容 size 初始 0 ensureCapacityInternal(size + 1); // Increments modCount!! // 将要添加的元素 添加到数组中 elementData[0] = 1 --> size = 1 elementData[size++] = e; return true; } ``` ```java private void ensureCapacityInternal(int minCapacity) { // ensureExplicitCapacity(10) ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } ``` ```java /** * elementData {} minCapacity 1 */ private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 10 1 return 10 return Math.max(DEFAULT_CAPACITY, minCapacity); } // 5 return minCapacity; } ``` ```java private void ensureExplicitCapacity(int minCapacity) { modCount++; // 增长 操作次数 // minCapacity 10 if (minCapacity - elementData.length > 0) grow(minCapacity); } ``` ```java private void grow(int minCapacity) { // 10 // overflow-conscious code int oldCapacity = elementData.length; // 0 // newCapacity = 0 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) // newCapacity = 10 newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // {} {,,,,,,,,,} 返回一个新的数组 长度为10 elementData = Arrays.copyOf(elementData, newCapacity); } ``` ##### 第二次添加 ```java elementData = {1,,,,,,,,,}; size = 1; ``` ```java public boolean add(E e) { // 2 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; // elementData[1] = 2 size = 2 return true; } ``` ```java private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } // 2 return minCapacity; } ``` ```java private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code 2 - 10 if (minCapacity - elementData.length > 0) grow(minCapacity); } ``` ##### 第十一次添加 ```java elementData = {1,2,3,4,5,6,7,8,9,10}; size = 10; ``` ```java public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } ``` ```java private void ensureCapacityInternal(int minCapacity) { // ensureExplicitCapacity(11) ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } ``` ```java private void ensureExplicitCapacity(int minCapacity) { modCount++; // 11 - 10 > 0 if (minCapacity - elementData.length > 0) grow(minCapacity); } ``` ```java private void grow(int minCapacity) { // 11 // 10 int oldCapacity = elementData.length; // 15 newCapacity 是oldCapacity的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: // {1,2,3,4,5,6,7,8,9,10} -- > {1,2,3,4,5,6,7,8,9,10,,,,,} elementData = Arrays.copyOf(elementData, newCapacity); } ``` #### get方法 ```java public E get(int index) { // 检查下标是否合法 rangeCheck(index); // 通过下标获取数组对应的元素 return elementData(index); } ``` #### set方法 ```java public E set(int index, E element) { rangeCheck(index); // 检查下标 // 获取下标原来的值 E oldValue = elementData(index); elementData[index] = element; return oldValue; } ``` #### remove方法 ```java public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); // 获取要移动的元素的个数 {1,2,3,4,5,6,7,8,9} // 3 size=9 index=3 // {1,2,3,5,6,7,8,9,null} int numMoved = size - index - 1; // 5 if (numMoved > 0) // 源数组 开始下标 目标数组 开始下标 长度 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work // 删除的节点对应的信息 return oldValue; } ``` #### FailFast机制 快速失败的机制,Java集合类为了应对并发访问在集合迭代过程中,内部结构发生变化的一种防护措施,这种错误检查的机制为这种可能发生错误通过抛出 java.util.ConcurrentModificationException ### 2.LinkedList LinkedList是通过双向链表去实现的,他的数据结构具有双向链表的优缺点,既然是双向链表,那么的它的顺序访问效率会非常高,而随机访问的效率会比较低,它包含一个非常重要的私有内部静态类:Node ```java private static class Node<E> { E item; // 节点的元素 Node<E> next; // 下一个节点 Node<E> prev; // 上一个节点 Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } } ``` get方法:本质上还是遍历链表中的数据 ```java Node<E> node(int index) { // assert isElementIndex(index); // index 和 长度的一半比较 if (index < (size >> 1)) { Node<E> x = first; // 从头开始循环 for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; // 从尾部开始循环 for (int i = size - 1; i > index; i--) x = x.prev; return x; } } ``` set方法 ```java public E set(int index, E element) { checkElementIndex(index);// 检查下标是否合法 Node<E> x = node(index); // 根据下标获取对应的node对象 E oldVal = x.item; // 记录原来的值 x.item = element; // 赋予新的值 return oldVal; // 返回修改之前的值 } ``` ### 3.Vector 和ArrayList很类似,都是以动态数组的形式来存储数据 Vector线程安全的 每个操作方法都加的有synchronized关键字,针对性能来说会比较大的影响,慢慢就被放弃了 Collections 可以增加代码的灵活度,在我们需要同步是时候就通过如下代码实现 ```java List syncList = Collections.synchronizedList(list); ``` 本质上 ```java public E get(int index) { synchronized (mutex) {return list.get(index);} } public E set(int index, E element) { synchronized (mutex) {return list.set(index, element);} } public void add(int index, E element) { synchronized (mutex) {list.add(index, element);} } public E remove(int index) { synchronized (mutex) {return list.remove(index);} } ``` ## Set接口 ### 1.HashSet #### 概述 HashSet实现Set接口,由哈希表支持,它不保证set的迭代顺序,特别是它不保证该顺序永久不变,运行使用null。 ```java public HashSet() { map = new HashMap<>(); } ``` add方法 ```java public boolean add(E e) { return map.put(e, PRESENT)==null; } ``` 本质上是将数据保持在 HashMap中 key就是我们添加的内容,value就是我们定义的一个Object对象 #### 特点 底层数据结构是哈希表,HashSet的本质是一个"没有重复元素"的集合,他是通过`HashMap`实现的.HashSet中含有一个HashMap类型的成员变量`map`. ### 2.TreeSet #### 概述 基于TreeMap的 NavigableSet实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator进行排序,具体取决于使用的构造方法。 ```java public TreeSet() { this(new TreeMap<E,Object>()); } ``` 本质是将数据保存在TreeMap中,key是我们添加的内容,value是定义的一个Object对象。 ## Map接口 Map集合的特点 > 1.能够存储唯一的列的数据(唯一,不可重复) Set > > 2.能够存储可以重复的数据(可重复) List > > 3.值的顺序取决于键的顺序 > > 4.键和值都是可以存储null元素的 ### TreeMap 本质上就是`红黑树`的实现 >1.每个节点要么是红色,要么是黑色。 > >2.根节点必须是黑色 > >3.每个叶子节点【NIL】是黑色 > >4.每个红色节点的两个子节点必须是黑色 > >5.任意节点到每个叶子节点的路径包含相同数量的黑节点 ```java K key; // key V value; // 值 Entry<K,V> left; // 左子节点 Entry<K,V> right; // 右子节点 Entry<K,V> parent; // 父节点 boolean color = BLACK; // 节点的颜色 默认是黑色 ``` put为例 ```java public V put(K key, V value) { // 将root赋值给局部变量 null Entry<K,V> t = root; if (t == null) { // 初始操作 // 检查key是否为空 compare(key, key); // type (and possibly null) check // 将要添加的key、 value封装为一个Entry对象 并赋值给root root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // 父节点 // split comparator and comparable paths Comparator<? super K> cpr = comparator; // 获取比较器 if (cpr != null) { // 一直找到插入节点的父节点 do { // 将root赋值给了parent parent = t; // 和root节点比较值得大小 cmp = cpr.compare(key, t.key); if (cmp < 0) // 将父节点的左子节点付给了t t = t.left; else if (cmp > 0) t = t.right; // 将父节点的右节点付给了t else // 直接和父节点的key相等,直接修改值 return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } // t 就是我们要插入节点的父节点 parent // 将我们要插入的key value 封装成了一个Entry对象 Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; // 插入的节点在parent节点的左侧 else parent.right = e; // 插入的节点在parent节点的右侧 fixAfterInsertion(e); // 实现红黑树的平衡 size++; modCount++; return null; } ``` ```java /** From CLR */ private void fixAfterInsertion(Entry<K,V> x) { // 设置添加节点的颜色为 红色 x.color = RED; // 循环的条件 添加的节点不为空 不是root节点 父节点的颜色为红色 while (x != null && x != root && x.parent.color == RED) { // 父节点是否是 祖父节点的左侧节点 if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { // 获取父节点的 兄弟节点 叔叔节点 Entry<K,V> y = rightOf(parentOf(parentOf(x))); if (colorOf(y) == RED) { // 叔叔节点是红色 // 变色 setColor(parentOf(x), BLACK); // 设置 父节点的颜色为黑色 setColor(y, BLACK); // 设置叔叔节点的颜色为 黑色 setColor(parentOf(parentOf(x)), RED); // 设置 祖父节点的颜色是 红色 // 将祖父节点设置为 插入节点 x = parentOf(parentOf(x)); } else { // 叔叔节点是黑色 if (x == rightOf(parentOf(x))) { // 判断插入节点是否是 父节点的右侧节点 x = parentOf(x); // 将父节点作为插入节点 rotateLeft(x); // 左旋 } setColor(parentOf(x), BLACK); setColor(parentOf(parentOf(x)), RED); rotateRight(parentOf(parentOf(x)));// 右旋 } } else {// 父节点是祖父节点的右侧子节点 // 获取叔叔节点 Entry<K,V> y = leftOf(parentOf(parentOf(x))); if (colorOf(y) == RED) { // 叔叔节点为红色 // recolor 变色 setColor(parentOf(x), BLACK); setColor(y, BLACK); setColor(parentOf(parentOf(x)), RED); x = parentOf(parentOf(x)); } else { // 插入节点在父节点的右侧 if (x == leftOf(parentOf(x))) { x = parentOf(x); rotateRight(x); // 右旋 } setColor(parentOf(x), BLACK); setColor(parentOf(parentOf(x)), RED); rotateLeft(parentOf(parentOf(x))); // 左旋 } } } // 根节点的颜色为黑色 root.color = BLACK; } ``` ### HashMap HashMap底层结构 Jdk1.7及以前是采用数组+链表 Jdk1.8之后 采用数组+链表 或者 数组+红黑树方式进行元素的存储 存储在hashMap集合中的元素都将是一个Map.Entry的内部接口的实现 ```java // 默认的HashMap中数组的长度 16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 // HashMap中的数组的最大容量 static final int MAXIMUM_CAPACITY = 1 << 30; // 默认的扩容的平衡因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; // 链表转红黑树的 临界值 static final int TREEIFY_THRESHOLD = 8; // 红黑树转链表的 临界值 static final int UNTREEIFY_THRESHOLD = 6 // 链表转红黑树的数组长度的临界值 static final int MIN_TREEIFY_CAPACITY = 64; // HashMap中的数组结构 transient Node<K,V>[] table; // HashMap中的元素个数 transient int size; // 对HashMap操作的次数 transient int modCount; // 扩容的临界值 int threshold; // 实际的扩容值 final float loadFactor; ``` put方法原理分析 ```java public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } ``` hash(key):获取key对应的hash值 ```java static final int hash(Object key) { int h; // key.hashCode() 32长度的二进制的值 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } ``` 为什么要右移16位? A:1000010001110001000001111000000 B:0111011100111000101000010100000 A 和 B 对 15 11111&预算 得到的都是 0 相同,会造成散列分布不均匀 ```java final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) // 初始的判断 // resize() 初始数组 扩容 初始的时候 获取了一个容量为16的数组 n = (tab = resize()).length; // n 数组长度 // 确定插入的key在数组中的下标 15 11111 // 100001000111000 // 1111 // 1000 = 8 if ((p = tab[i = (n - 1) & hash]) == null) // 通过hash值找到的数组的下标 里面没有内容就直接赋值 tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash // hash值相同&& // key也相同 ((k = p.key) == key || (key != null && key.equals(k)))) // 插入的值的key 和 数组当前位置的 key是同一个 那么直接修改里面内容 e = p; else if (p instanceof TreeNode) // 表示 数组中存放的节点是一个 红黑树节点 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { // 表示节点就是普通的链表 for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { // 到了链表的尾部 p.next = newNode(hash, key, value, null); // 将新的节点添加到了链表的尾部 // 判断是否满足 链表转红黑树的条件 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st // 转红黑树 treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } ``` 第一次resize() ```java final Node<K,V>[] resize() { // table = null Node<K,V>[] oldTab = table; // oldCap = 0 int oldCap = (oldTab == null) ? 0 : oldTab.length; // 原来的扩容因子 0 int oldThr = threshold; // 新的容量和新的扩容因子 int newCap, newThr = 0; if (oldCap > 0) { // 初始不执行 0 if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold }// 初始为0 else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // 新的数组容量 16 newCap = DEFAULT_INITIAL_CAPACITY; // 新的扩容因子 0.75 * 16 = 12 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); }// 更新了 扩容的临界值 12 threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) // 创建了一个容量为16的Node数组 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; // 更新了table if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } ``` ```java final void treeifyBin(Node<K,V>[] tab, int hash) { int n, index; Node<K,V> e; // tab为空 或者 数组的长度小于64 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); // 扩容 else if ((e = tab[index = (n - 1) & hash]) != null) { // 链表转红黑树的逻辑 TreeNode<K,V> hd = null, tl = null; do { TreeNode<K,V> p = replacementTreeNode(e, null); if (tl == null) hd = p; else { p.prev = tl; tl.next = p; } tl = p; } while ((e = e.next) != null); if ((tab[index] = hd) != null) hd.treeify(tab); } } ``` 动态扩容 ```java final Node<K,V>[] resize() { // [1,2,3,4,5,6,7,8,9,10,11,,,,] Node<K,V>[] oldTab = table; // 16 int oldCap = (oldTab == null) ? 0 : oldTab.length; // 12 int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } // 新的容量是 原来容量的两倍 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) // 扩容的临界值 原来的两倍 24 newThr = oldThr << 1; // double threshold } else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) // 创建的数组的长度是32 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; if (oldTab != null) { // 初始的时候是不需要复制的 for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) // 数组中的元素就一个 找到元素在新的数组中的位置 赋值 newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) // 移动红黑树节点 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order // 普通的链表的移动 Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } ``` Last modification:November 17, 2021 © Allow specification reprint Support Appreciate the author Like 0 欢迎留下您的脚印
One comment
《我是传奇第二季》大陆综艺高清在线免费观看:https://www.jgz518.com/xingkong/53764.html