Java常见集合之ArrayList深入分析

Java常见集合之ArrayList深入分析

一、继承树

  

二、ArrayList源码分析

2.1  继承结构和层次关系

  

2.2 源码分析:

  1 /*
  2 继承自AbstractList,实现了List、RandomAccess、Cloneable、Serializable接口
  3     1)RandomAccess接口:用来快速随机存取,在实现了该接口后,用普通for来遍历,性能更高
  4     2)Cloneable接口:实现了该接口,就可以使用Object.Clone()方法了
  5     3)Serializable接口:实现了该接口,表明该类可以被序列化
  6 */
  7 public class ArrayList<E> extends AbstractList<E>
  8         implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  9 {
 10     //版本号
 11     private static final long serialVersionUID = 8683452581122892189L;
 12     //缺省容量
 13     private static final int DEFAULT_CAPACITY = 10;
 14     //缺省空对象数组
 15     private static final Object[] EMPTY_ELEMENTDATA = {};
 16     //默认大小的对象数组
 17     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 18     //元素数组
 19     transient Object[] elementData;
 20     //数组的大小
 21      private int size;
 22      
 23      //构造方法
 24      //无参构造 Constructs an empty list with an initial capacity of ten
 25      public ArrayList() {
 26         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 27     }
 28     
 29     /**
 30      * Constructs an empty list with the specified initial capacity.
 31      *
 32      * @param  initialCapacity  the initial capacity of the list
 33      * @throws IllegalArgumentException if the specified initial capacity
 34      *         is negative
 35      */
 36     public ArrayList(int initialCapacity) {
 37         if (initialCapacity > 0) {
 38             this.elementData = new Object[initialCapacity];
 39         } else if (initialCapacity == 0) {
 40             this.elementData = EMPTY_ELEMENTDATA;
 41         } else {
 42             throw new IllegalArgumentException("Illegal Capacity: "+
 43                                                initialCapacity);
 44         }
 45     }
 46     
 47      /**
 48      * Constructs a list containing the elements of the specified
 49      * collection, in the order they are returned by the collection's
 50      * iterator.
 51      *
 52      * @param c the collection whose elements are to be placed into this list
 53      * @throws NullPointerException if the specified collection is null
 54      */
 55     public ArrayList(Collection<? extends E> c) {
 56         elementData = c.toArray();    //转换为数组
 57         if ((size = elementData.length) != 0) {    //数组长度大于0
 58             // c.toArray might (incorrectly) not return Object[] (see 6260652)
 59             if (elementData.getClass() != Object[].class)    
 60                 elementData = Arrays.copyOf(elementData, size, Object[].class);
 61         } else {
 62             // replace with empty array.
 63             this.elementData = EMPTY_ELEMENTDATA;
 64         }
 65     }
 66     //总体而言:arrayList的构造方法就是做一件事,初始化一下储存数据的容器,
 67     //            其实本质就是一个数组,在其中就叫elementData
 68     
 69     //核心方法
 70     /**
 71      * Appends the specified element to the end of this list.
 72      * 默认直接在末尾添加元素
 73      *
 74      * @param e element to be appended to this list
 75      * @return <tt>true</tt> (as specified by {@link Collection#add})
 76      */
 77     public boolean add(E e) {    //elementData=[1,2,3] e=6
 78         //确保数组的容量足够
 79         ensureCapacityInternal(size + 1);  // Increments modCount!!
 80         //数组尾部添加元素e
 81         elementData[size++] = e;
 82         return true;
 83     }
 84     
 85     private void ensureCapacityInternal(int minCapacity) { //minCapacity=4
 87         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
 88     }
 89     
 90     //计算容量
 91     private static int calculateCapacity(Object[] elementData, int minCapacity) {//elementData=[1,2,3],minCapacity=4
 92         //如果元素数组等于默认容量的元素数组,就返回DEFAULT_CAPACITY和minCapacity两者的最大值
 93         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
 94             return Math.max(DEFAULT_CAPACITY, minCapacity);
 95         }
 96         //否则就返回minCapacity
 97         return minCapacity; //4
 98     }
 99     
100     private void ensureExplicitCapacity(int minCapacity) { //minCapacity=4
101         modCount++;
102 
103         // overflow-conscious code
104         /*
105         这里有两种情况:
106             情况一:elementData为空数组,minCapacity=size+1=1,1-0>0,调用grow()进行扩容
107             情况二:elementData不为空数组,minCapacity=size+1,为elementData原始的数组(未调用add方法前),
108                     如果length不够用,再调用grow()进行扩容
109         */
110         if (minCapacity - elementData.length > 0)
111             grow(minCapacity);
112     }
113     
114     /**
115      * 增加容量以确保它至少可以容纳由最小容量参数指定的元素数
116      * Increases the capacity to ensure that it can hold at least the
117      * number of elements specified by the minimum capacity argument.
118      *
119      * @param minCapacity the desired minimum capacity
120      */
121     private void grow(int minCapacity) {
122         // overflow-conscious code
123         //将原始的elementData.length赋给oldCapacity
124         int oldCapacity = elementData.length;
125         //新容量=1.5*oldCapacity
126         int newCapacity = oldCapacity + (oldCapacity >> 1);
127         //如果elementData为空数组,那么oldCapacity和newCapacity都为0,将newCapacity直接赋值为10
128         if (newCapacity - minCapacity < 0)
129             newCapacity = minCapacity;
130         //如果newCapacity超过了最大的容量限制,将调用hugeCapacity()做进一步处理
131         if (newCapacity - MAX_ARRAY_SIZE > 0)
132             newCapacity = hugeCapacity(minCapacity);
133         // minCapacity is usually close to size, so this is a win:
134         //newCapacity确定好了以后,就copyof数组,进行扩容
135         elementData = Arrays.copyOf(elementData, newCapacity);
136     }
137     
138     private static int hugeCapacity(int minCapacity) {
139         if (minCapacity < 0) // overflow
140             throw new OutOfMemoryError();
141         //判断minCapacity是否大于最大的数组容量MAX_ARRAY_SIZE:是,返回Integer.MAX_VALUE(2147483647);
142         //否则返回MAX_ARRAY_SIZE
143         return (minCapacity > MAX_ARRAY_SIZE) ?
144             Integer.MAX_VALUE :
145             MAX_ARRAY_SIZE;
146     }
147     
148     /**
149      * 在指定位置插入元素
150      * Inserts the specified element at the specified position in this
151      * list. Shifts the element currently at that position (if any) and
152      * any subsequent elements to the right (adds one to their indices).
153      *
154      * @param index index at which the specified element is to be inserted
155      * @param element element to be inserted
156      * @throws IndexOutOfBoundsException {@inheritDoc}
157      */
158      public void add(int index, E element) {
159         //检查插入的位置是否合理
160         rangeCheckForAdd(index);
161 
162         //插入元素之后,将index之后的元素都往后移一位
163         ensureCapacityInternal(size + 1);  // Increments modCount!!
164         System.arraycopy(elementData, index, elementData, index + 1,
165                          size - index);
166         elementData[index] = element;
167         size++;
168     }
169     
170     /**
171      * 用于add和addAll方法的范围检查
172      * A version of rangeCheck used by add and addAll.
173      */
174     private void rangeCheckForAdd(int index) {
175         if (index > size || index < 0)
176             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
177     }
178 
179      /**
180      * 删除指定位置的元素
181      * Removes the element at the specified position in this list.
182      * Shifts any subsequent elements to the left (subtracts one from their
183      * indices).
184      *
185      * @param index the index of the element to be removed
186      * @return the element that was removed from the list
187      * @throws IndexOutOfBoundsException {@inheritDoc}
188      */
189     public E remove(int index) {
190         //范围检查
191         rangeCheck(index);
192 
193         modCount++;
194         E oldValue = elementData(index); //要删除指定index位置的值
195 
196         //计算要移动的位数
197         int numMoved = size - index - 1;
198         if (numMoved > 0)
199             /*
200             public static native void arraycopy(Object src,  int  srcPos,
201                                         Object dest, int destPos,
202                                         int length);
203             Copies an array from the specified source array, beginning at the
204             specified position, to the specified position of the destination array.                            
205             从源数组的特殊位置开始拷贝到目标数组的特定位置
206 
207             System.arraycopy(elementData, index+1, elementData, index,
208                              size - index - 1);    //size=8,index=5,8-5-1=2,src=[1,2,3,4,5,7,8]
209             */
210             System.arraycopy(elementData, index+1, elementData, index,
211                              numMoved);
212         elementData[--size] = null; // clear to let GC do its work
213 
214         return oldValue;
215     }
216     
217      /**
218      * 移除list列表中第一次出现的待删除的元素
219      * Removes the first occurrence of the specified element from this list,
220      * if it is present.  If the list does not contain the element, it is
221      * unchanged.  More formally, removes the element with the lowest index
222      * <tt>i</tt> such that
223      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
224      * (if such an element exists).  Returns <tt>true</tt> if this list
225      * contained the specified element (or equivalently, if this list
226      * changed as a result of the call).
227      *
228      * @param o element to be removed from this list, if present
229      * @return <tt>true</tt> if this list contained the specified element
230      */
231     public boolean remove(Object o) {
232         //依次遍历删除
233         if (o == null) {
234             for (int index = 0; index < size; index++)
235                 if (elementData[index] == null) {
236                     fastRemove(index);
237                     return true;
238                 }
239         } else {
240             for (int index = 0; index < size; index++)
241                 if (o.equals(elementData[index])) {
242                     fastRemove(index);
243                     return true;
244                 }
245         }
246         return false;
247     }
248     //remove函数用户移除指定下标的元素,此时会把指定下标到数组末尾的元素向前移动一个单位,
249     //并把最后一个元素置为null
250     
251     /**
252      * 将list表中指定位置的元素替换掉
253      * Replaces the element at the specified position in this list with
254      * the specified element.
255      *
256      * @param index index of the element to replace
257      * @param element element to be stored at the specified position
258      * @return the element previously at the specified position
259      * @throws IndexOutOfBoundsException {@inheritDoc}
260      */
261     public E set(int index, E element) {
262         //范围检查
263         rangeCheck(index);
264 
265         //指定位置的元素值
266         E oldValue = elementData(index);
267         //将elementData的指定位置替换为element
268         elementData[index] = element;
269         return oldValue;
270     }
271     
272     /**
273      * 返回在list列表中的指定元素第一次出现的索引值
274      * Returns the index of the first occurrence of the specified element
275      * in this list, or -1 if this list does not contain the element.
276      * More formally, returns the lowest index <tt>i</tt> such that
277      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
278      * or -1 if there is no such index.
279      */
280     public int indexOf(Object o) {
281         if (o == null) {
282             for (int i = 0; i < size; i++)
283                 if (elementData[i]==null)
284                     return i;
285         } else {
286             for (int i = 0; i < size; i++)
287                 if (o.equals(elementData[i]))
288                     return i;
289         }
290         return -1;
291     }
292     //从头开始查找元素,可以查找null值
293     
294      /**
295      * 返回在list列表中指定位置的元素
296      * Returns the element at the specified position in this list.
297      *
298      * @param  index index of the element to return
299      * @return the element at the specified position in this list
300      * @throws IndexOutOfBoundsException {@inheritDoc}
301      */
302     public E get(int index) {
303         //范围检查,只检查>=size的部分
304         rangeCheck(index);
305 
306         return elementData(index);
307     }
308     
309     E elementData(int index) {
310         return (E) elementData[index];
311     }
312     //注意:返回的值都做了向下转型(object->E)处理
313 }

 

2.3 小结:

  1、ArrayList底层就是一个elementData数组,不过跟array相区别的是,它存在一个动态扩容机制

  2、由于每次添加、删除元素,都涉及到数组元素的移动,因此效率不高

  3、由于ArrayList实现了RandomAccess接口,适合做随机访问,用for循环进行查找元素,效率较高

 
 

 

posted @ 2020-04-06 18:16  小锅牛  阅读(211)  评论(0编辑  收藏  举报