diff --git a/second/week_01/70/ArrayList-070.adoc b/second/week_01/70/ArrayList-070.adoc new file mode 100644 index 0000000000000000000000000000000000000000..c05780c41410a957f98ea5a6742beed5b4e5c9b5 --- /dev/null +++ b/second/week_01/70/ArrayList-070.adoc @@ -0,0 +1,255 @@ += ArrayList基础入门学习笔记 +Doc Writer +v1.0, 2020-03-08 +:toc-title: 目录 +:toc: left + +== 基本要求 +=== 源码学习要求 +- 至少提交2个类的源码分析笔记 + +=== jdk环境要求 +jdk1.8 + +=== 学习后需要至少掌握的知识点 +- arraylist中默认大小是多少? +- arraylist何时扩容?每次扩容是怎么扩容的,过程是怎么样的 +- arraylist线程不安全的体现在哪里?如何解决 +- arraylist遍历时进行删除时会报异常,用迭代器就不会抛出异常的原理是什么? +- arraylist中add的过程 + +== 部分源码分析笔记 +=== arraylist无参构造方法 + +[source,adoc] +---- + /** + * Constructs an empty list with an initial capacity of ten. + */ + public ArrayList() { + this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; + } +---- + +capacity of ten体现点?查看add方法 + +=== add方法 +[source,adoc] +---- + /** + * Appends the specified element to the end of this list. + * + * @param e element to be appended to this list + * @return true (as specified by {@link Collection#add}) + */ + public boolean add(E e) { + //size为int类型,默认为0 + ensureCapacityInternal(size + 1); // Increments modCount!! + elementData[size++] = e; + return true; + } + + // DEFAULTCAPACITY_EMPTY_ELEMENTDATA为空数组 + private void ensureCapacityInternal(int minCapacity) { + //最小容量大小为10 + if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { + minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); + } + + ensureExplicitCapacity(minCapacity); + } + + private void ensureExplicitCapacity(int minCapacity) { + //modCount++,modCount默认为0,每次调用add方法时都会增加一次 + modCount++; + + // overflow-conscious code + if (minCapacity - elementData.length > 0) + grow(minCapacity); + //当minCapacity比elementData.length大时,就会执行grow操作 + + } + + + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + private void grow(int minCapacity) { + // overflow-conscious code + int oldCapacity = elementData.length; + //在旧容量的基础上右移一位,如1010变为了101,即增加原始大小的百分之50 + int newCapacity = oldCapacity + (oldCapacity >> 1); + //??????这个操作有啥用? + if (newCapacity - minCapacity < 0) + newCapacity = minCapacity; + // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;hugeCapacity确保不会让arrayList越界,同时也让证明了arraylist并不是可以无限大的 + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); + //将原始数姐进行拷贝,底曾调用的是System.arraycopy,这是一个navite方法 + // minCapacity is usually close to size, so this is a win: + elementData = Arrays.copyOf(elementData, newCapacity); + } +---- + +[NOTE] +.通过add方法可知 +==== +查看源码后可知如下内容: + +. arrayList在没有指定大小的情况下,size=0 +. arrayList的扩容不会提前先扩容,而是在原始大小装不下时才会进行扩容 +. arrayList每次扩容时的大小为原始大小是1半,用的位移运算来操作的,每次向右移动了一位 +. arrayList的最大长度为Integer.MAX_VALUE,说明arrayList并不是可以无限增长的,它也是有极限的 +. arrayList的扩容过程用的是system.arraycopy来实现的 +==== + +=== remove方法 +[source,adoc] +---- + /** + * Removes the first occurrence of the specified element from this list, + * if it is present. If the list does not contain the element, it is + * unchanged. More formally, removes the element with the lowest index + * i such that + * (o==null ? get(i)==null : o.equals(get(i))) + * (if such an element exists). Returns true if this list + * contained the specified element (or equivalently, if this list + * changed as a result of the call). + * + * @param o element to be removed from this list, if present + * @return true if this list contained the specified element + */ + public boolean remove(Object o) { + //遍历判断值是否相等,找到那个相等的值,如果找到了则调用fastRemove方法进行移除 + if (o == null) { + for (int index = 0; index < size; index++) + if (elementData[index] == null) { + fastRemove(index); + return true; + } + } else { + for (int index = 0; index < size; index++) + if (o.equals(elementData[index])) { + fastRemove(index); + return true; + } + } + return false; + } + + /* + * Private remove method that skips bounds checking and does not + * return the value removed. + */ + private void fastRemove(int index) { + //进行移除时,modCount也会增加 + modCount++; + //0 1 2 3 4 5,共6个,想要移除第2个,则需要变动的元素个数为6-2-1=3 + int numMoved = size - index - 1; + if (numMoved > 0) + System.arraycopy(elementData, index+1, elementData, index, + numMoved); + elementData[--size] = null; // clear to let GC do its work + } + + /** arraycopy中的5个参数 + * @param src the source array. + * @param srcPos starting position in the source array. + * @param dest the destination array. + * @param destPos starting position in the destination data. + * @param length the number of array elements to be copied. + **/ +---- +[NOTE] +.通过remove方法可知 +==== +查看源码后可知如下内容: + +. remove方法是也是通过system.arraycopy来实现的 +==== + +=== iterator方法 +[source,java] +---- + /** + * An optimized version of AbstractList.Itr + */ + private class Itr implements Iterator { + int cursor; // index of next element to return + int lastRet = -1; // index of last element returned; -1 if no such + int expectedModCount = modCount; + + public boolean hasNext() { + return cursor != size; + } + + @SuppressWarnings("unchecked") + public E next() { + checkForComodification(); + int i = cursor; + if (i >= size) + throw new NoSuchElementException(); + Object[] elementData = ArrayList.this.elementData; + if (i >= elementData.length) + throw new ConcurrentModificationException(); + cursor = i + 1; + return (E) elementData[lastRet = i]; + } + + //迭代器中的remove实际上调用的还是ArrayList中的remove,通过索引来remove元素的 + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + ArrayList.this.remove(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + @Override + @SuppressWarnings("unchecked") + public void forEachRemaining(Consumer consumer) { + Objects.requireNonNull(consumer); + final int size = ArrayList.this.size; + int i = cursor; + if (i >= size) { + return; + } + final Object[] elementData = ArrayList.this.elementData; + if (i >= elementData.length) { + throw new ConcurrentModificationException(); + } + while (i != size && modCount == expectedModCount) { + consumer.accept((E) elementData[i++]); + } + // update once at end of iteration to reduce heap write traffic + cursor = i; + lastRet = i - 1; + checkForComodification(); + } + + //确保在遍历期间没有对arraylist进行修改 + final void checkForComodification() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + } +---- + +[NOTE] +.通过iterator方法可知 +==== +查看源码后可知如下内容: + +. arrayList中的iterator里的remove方法调用的本质其实也是调用的arraylist的remove索引来进行删除的 + +==== diff --git a/second/week_01/70/HashMap-070.adoc b/second/week_01/70/HashMap-070.adoc new file mode 100644 index 0000000000000000000000000000000000000000..6586e1dfedc7b426d27f38058a29947fd0612be5 --- /dev/null +++ b/second/week_01/70/HashMap-070.adoc @@ -0,0 +1,106 @@ += Hashmap基础入门学习笔记 +Doc Writer +v1.0, 2020-03-08 +:toc-title: 目录 +:toc: left + +== 基本要求 +=== 源码学习要求 +- 至少提交2个类的源码分析笔记 + +=== jdk环境要求 +jdk1.8 + +=== 学习后需要至少掌握的知识点 +- hashmap中的结构何时会变为红黑树 +- hashmap线程不安全的体现点在哪里?jdk.7与jdk1.8的不同点(对于jdk1.7中hashmap线程不安全可能会导致死锁的原因这里不再重新记录源码,详见本人的历史博文 +https://blog.csdn.net/puhaiyang/article/details/90812572[hashmap从入门到死锁,再到分段式锁] +- hashmap在jdk1.7中 + +== 部分源码分析笔记 + +=== hashmap的put方法 +[source,adoc] +---- + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with key, or + * null if there was no mapping for key. + * (A null return can also indicate that the map + * previously associated null with key.) + */ + public V put(K key, V value) { + return putVal(hash(key), key, value, false, true); + } + + /** + * Implements Map.put and related methods. + * + * @param hash hash for key + * @param key the key + * @param value the value to put + * @param onlyIfAbsent if true, don't change existing value + * @param evict if false, the table is in creation mode. + * @return previous value, or null if none + */ + final V putVal(int hash, K key, V value, boolean onlyIfAbsent, + boolean evict) { + Node[] tab; Node p; int n, i; + //判断hashmap是否需要进行初始化 + if ((tab = table) == null || (n = tab.length) == 0) + n = (tab = resize()).length; + //判断value是否为null值 + if ((p = tab[i = (n - 1) & hash]) == null) + tab[i] = newNode(hash, key, value, null); + else { + Node e; K k; + if (p.hash == hash && + ((k = p.key) == key || (key != null && key.equals(k)))) + e = p; + else if (p instanceof TreeNode) + e = ((TreeNode)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); + //判断是否需要将hashmap节点转为红黑树,TREEIFY_THRESHOLD为8 + if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st + //java.util.HashMap.TreeNode为主要算法代码 + 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(); + // Callbacks to allow LinkedHashMap post-actions,此方法为一个回调方法 + afterNodeInsertion(evict); + return null; + } +---- + +[NOTE] +.通过put方法可知 +==== +查看源码后可知如下内容: + +. hashmap在jdk1.8中,如果key节点的value数大于等于8时,会将此节点转为一个红黑树,以加快查找时间 +==== diff --git a/second/week_01/70/LinkedList-070.adoc b/second/week_01/70/LinkedList-070.adoc new file mode 100644 index 0000000000000000000000000000000000000000..66932feea0cd0d8bd76ff20257aa59025e7f7e3a --- /dev/null +++ b/second/week_01/70/LinkedList-070.adoc @@ -0,0 +1,242 @@ += LinkedList基础入门学习笔记 +Doc Writer +v1.0, 2020-03-08 +:toc-title: 目录 +:toc: left + +== 基本要求 + +=== 源码学习要求 + +- 至少提交2个类的源码分析笔记 + +=== jdk环境要求 +jdk1.8 + +=== 学习后需要至少掌握的知识点 +- 与linkedList的区别?存储结构 + + +== 部分源码分析笔记 +=== LinkedList的add方法 +[source,adoc] +---- + /** + * Constructs an empty list. + */ + public LinkedList() { + } + + /** + * Appends the specified element to the end of this list. + * + *

This method is equivalent to {@link #addLast}. + * + * @param e element to be appended to this list + * @return {@code true} (as specified by {@link Collection#add}) + */ + public boolean add(E e) { + linkLast(e); + return true; + } + + /** + * Links e as last element. + */ + void linkLast(E e) { + //last默认为null + final Node l = last; + //构造节点 + final Node newNode = new Node<>(l, e, null); + last = newNode; + //如果last节点是空的,就让当前节点作为最后一个节点,链表只有一个元素 + if (l == null) + first = newNode; + else + l.next = newNode; + size++; + modCount++; + } + +---- + +[NOTE] +.通过put方法可知 +==== +查看源码后可知如下内容: + +. linkedlist由于是基于链表操作的,其存储结构便是逻辑上的关联关系,从代码上没有看到长度大小限制 +==== + +=== LinkedList的iterator方法 +[source,adoc] +---- + // Iterators + + /** + * Returns an iterator over the elements in this list (in proper + * sequence).

+ * + * This implementation merely returns a list iterator over the list. + * + * @return an iterator over the elements in this list (in proper sequence) + */ + public Iterator iterator() { + return listIterator(); + } + + /** + * {@inheritDoc} + * + *

This implementation returns {@code listIterator(0)}. + * + * @see #listIterator(int) + */ + public ListIterator listIterator() { + return listIterator(0); + } + + /** + * Returns a list-iterator of the elements in this list (in proper + * sequence), starting at the specified position in the list. + * Obeys the general contract of {@code List.listIterator(int)}.

+ * + * The list-iterator is fail-fast: if the list is structurally + * modified at any time after the Iterator is created, in any way except + * through the list-iterator's own {@code remove} or {@code add} + * methods, the list-iterator will throw a + * {@code ConcurrentModificationException}. Thus, in the face of + * concurrent modification, the iterator fails quickly and cleanly, rather + * than risking arbitrary, non-deterministic behavior at an undetermined + * time in the future. + * + * @param index index of the first element to be returned from the + * list-iterator (by a call to {@code next}) + * @return a ListIterator of the elements in this list (in proper + * sequence), starting at the specified position in the list + * @throws IndexOutOfBoundsException {@inheritDoc} + * @see List#listIterator(int) + */ + public ListIterator listIterator(int index) { + checkPositionIndex(index); + return new ListItr(index); + } + + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } +---- + +其ListItr源码为: +[source,java] +---- +private class ListItr implements ListIterator { +private Node lastReturned; +private Node next; +private int nextIndex; +private int expectedModCount = modCount; + + ListItr(int index) { + // assert isPositionIndex(index); + next = (index == size) ? null : node(index); + nextIndex = index; + } + + public boolean hasNext() { + return nextIndex < size; + } + + public E next() { + checkForComodification(); + if (!hasNext()) + throw new NoSuchElementException(); + + lastReturned = next; + next = next.next; + nextIndex++; + return lastReturned.item; + } + + public boolean hasPrevious() { + return nextIndex > 0; + } + + public E previous() { + checkForComodification(); + if (!hasPrevious()) + throw new NoSuchElementException(); + + lastReturned = next = (next == null) ? last : next.prev; + nextIndex--; + return lastReturned.item; + } + + public int nextIndex() { + return nextIndex; + } + + public int previousIndex() { + return nextIndex - 1; + } + + public void remove() { + checkForComodification(); + if (lastReturned == null) + throw new IllegalStateException(); + + Node lastNext = lastReturned.next; + unlink(lastReturned); + if (next == lastReturned) + next = lastNext; + else + nextIndex--; + lastReturned = null; + expectedModCount++; + } + + public void set(E e) { + if (lastReturned == null) + throw new IllegalStateException(); + checkForComodification(); + lastReturned.item = e; + } + + public void add(E e) { + checkForComodification(); + lastReturned = null; + if (next == null) + linkLast(e); + else + linkBefore(e, next); + nextIndex++; + expectedModCount++; + } + + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + while (modCount == expectedModCount && nextIndex < size) { + action.accept(next.item); + lastReturned = next; + next = next.next; + nextIndex++; + } + checkForComodification(); + } + + final void checkForComodification() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + } +---- + +[NOTE] +.通过iterator方法可知 +==== +查看源码后可知如下内容: + +. iterator的遍历实际上就是链表的遍历,而arraylist中的遍历是索引的遍历 +. 也是通过迭代器中可以看出linkedlist的数据删除是让节点的前后节点直接关联即可 +. 正是因为其结构的特性,linkedlist与arrayList相比,一般常认为arraylist对于数据随机访问比较快,因为linkedlist需要一个一个节点的遍历并计数才能获取出最终的结果.而arraylist的删除操作也是同样的,它的删除一般需要将数组的节点进行复制,时间与空间复杂点消耗较大 +==== \ No newline at end of file