From e5bd19b2752862624133a37d0a911f2fed09a04c Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Sun, 10 Mar 2019 09:50:35 +0800 Subject: [PATCH] add ArrayList --- .../Android/Dalvik 和 ART.md | 0 .../Android/性能优化/IO 优化.md | 0 .../ArrayList 与 Vector 源码分析.md | 158 ++++++++++++++++++ .../Android/IO 流程.png | Bin .../Android/IO 请求流程.png | Bin .../Android/Linux IO 模型.png | Bin 6 files changed, 158 insertions(+) rename "blogs/Android/Dalvik \\ ART.md" => blogs/Android/Dalvik 和 ART.md (100%) rename "blogs/Android/性能优化/I\\O 优化.md" => blogs/Android/性能优化/IO 优化.md (100%) create mode 100644 blogs/集合/ArrayList 与 Vector 源码分析.md rename "images/Android/I\\O 流程.png" => images/Android/IO 流程.png (100%) rename "images/Android/I\\O 请求流程.png" => images/Android/IO 请求流程.png (100%) rename "images/Android/Linux I\\O 模型.png" => images/Android/Linux IO 模型.png (100%) diff --git "a/blogs/Android/Dalvik \\ ART.md" b/blogs/Android/Dalvik 和 ART.md similarity index 100% rename from "blogs/Android/Dalvik \\ ART.md" rename to blogs/Android/Dalvik 和 ART.md diff --git "a/blogs/Android/性能优化/I\\O 优化.md" b/blogs/Android/性能优化/IO 优化.md similarity index 100% rename from "blogs/Android/性能优化/I\\O 优化.md" rename to blogs/Android/性能优化/IO 优化.md diff --git a/blogs/集合/ArrayList 与 Vector 源码分析.md b/blogs/集合/ArrayList 与 Vector 源码分析.md new file mode 100644 index 0000000..efff4b1 --- /dev/null +++ b/blogs/集合/ArrayList 与 Vector 源码分析.md @@ -0,0 +1,158 @@ +--- +ArrayList 和 Vector 源码分析 +--- + +#### 前言 + +基于JDK1.10。 + +#### ArrayList + +ArrayList实现了List接口、RandomAccess接口,可以插入空数据以及支持随机访问。 + +ArrayList相当于动态数组,里面有两个重要属性,elementData以及size。 + +```java +transient Object[] elementData; //数据 +private int size; //数组大小 +``` + +首先看一下**构造方法**(只罗列其中一种): + +```java + public ArrayList(int initialCapacity) { + if (initialCapacity > 0) { + this.elementData = new Object[initialCapacity]; + } else if (initialCapacity == 0) { + this.elementData = EMPTY_ELEMENTDATA; + } else { + throw new IllegalArgumentException("Illegal Capacity: "+ + initialCapacity); + } + } +``` + +也就是说我们可以指定容量大小,这样可以避免扩容导致的性能损耗。 + +**第一种方式添加数据时:** + +```java + public boolean add(E e) { + modCount++; + add(e, elementData, size); + return true; + } + private void add(E e, Object[] elementData, int s) { + if (s == elementData.length) //第一步:扩容效验 + elementData = grow(); + elementData[s] = e; //第二步:在尾部添加数据并且size+1 + size = s + 1; + } +``` + +- 首先是扩容效验 +- 把数据插入到最后,并且 size + 1 + +**第二种方式添加数据时:** + +```java + public void add(int index, E element) { + rangeCheckForAdd(index); //第一步:判断插入的index是否合理 + modCount++; + final int s; + Object[] elementData; + if ((s = size) == (elementData = this.elementData).length) //第二步:扩容效验 + elementData = grow(); + System.arraycopy(elementData, index, elementData, index + 1,s - index); //第三步:拷贝数组,并把index后的数据往后移一位,把数据插入到index位置上,size + 1 + elementData[index] = element; + size = s + 1; + } +``` + +- 首先判断插入的index是否合理,以及依旧进行扩容效验 +- 拷贝数组插入数据,size + 1 + +**扩容效验:** + +```java + private Object[] grow() { + return grow(size + 1); + } + private Object[] grow(int minCapacity) { + return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); //拷贝旧数组,容量大小为以前的1.5倍 + } + private int newCapacity(int minCapacity) { + // overflow-conscious code + int oldCapacity = elementData.length; + int newCapacity = oldCapacity + (oldCapacity >> 1); //容量扩大为之前的1.5倍 + if (newCapacity - minCapacity <= 0) { + if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) + return Math.max(DEFAULT_CAPACITY, minCapacity); //private static final int DEFAULT_CAPACITY = 10; + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return minCapacity; + } + return (newCapacity - MAX_ARRAY_SIZE <= 0) //private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + ? newCapacity + : hugeCapacity(minCapacity); + } + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) + ? Integer.MAX_VALUE + : MAX_ARRAY_SIZE; + } +``` + +可以看出,如果是非极端的情况下(比如初始容量很小和很大),都会将容量扩大至以前的1.5倍。 + +所以,ArrayList的性能损耗主要在于数据的拷贝,所以可以适当情况下指定容量大小,应该尽量减少扩容操作,更要避免在指定位置插入数据的操作。 + +**序列化:** + +仔细看的话肯定能看到前面的elementData是用transient修饰的,也就是拒绝数据被自动序列化。因为ArrayList并不是所有位置都有数据,所以没必要全部序列话,应该只序列化有数据的部分。 + +```java + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out element count, and any hidden stuff + int expectedModCount = modCount; + s.defaultWriteObject(); + + // Write out size as capacity for behavioral compatibility with clone() + s.writeInt(size); + + // Write out all elements in the proper order. + for (int i=0; i