Java 模仿jdk MyArrayList

Posted wjq2017

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 模仿jdk MyArrayList相关的知识,希望对你有一定的参考价值。

 

  1 package com.wjq.javautils;
  2 
  3 import java.util.AbstractList;
  4 import java.util.ArrayList;
  5 import java.util.Arrays;
  6 import java.util.Collection;
  7 import java.util.Comparator;
  8 import java.util.ConcurrentModificationException;
  9 import java.util.List;
 10 import java.util.RandomAccess;
 11 
 12 /**
 13  * 
 14  * @author WangJingQian
 15  *
 16  * @param <E>
 17  */
 18 public class MyArrayList<E> extends AbstractList<E>
 19         implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
 20 
 21     /**
 22      * 序列化版本唯一标识符,版本向下兼容。
 23      */
 24     private static final long serialVersionUID = -6534304769377827244L;
 25 
 26     // 默认初始容量
 27     private static final int DEFAULT_CAPACITY = 10;
 28 
 29     // 容量为0的空数组
 30     private static final Object[] EMPTY_ELEMENTDATA = {};
 31 
 32     // 默认容量的空数组,向空数组中插入第1个元素时该数组可用于判断初始的容量是
 33     // 多少(0或10)从而确定扩容的大小。
 34     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 35 
 36     // 瞬态的缓冲数组 使用transient关键字目的是只序列化实际存储的那些元素,而不是整个数组。
 37     private transient Object[] elementData;
 38 
 39     // 数组实际存储的元素数量
 40     private int size;
 41     
 42     // 带初始容量的构造方法
 43     public MyArrayList(int initialCapacity) {
 44         if (initialCapacity > 0) {
 45             this.elementData = new Object[initialCapacity];
 46         } else if (initialCapacity == 0) {
 47             // 指向空数组
 48             this.elementData = EMPTY_ELEMENTDATA;
 49         } else {
 50             throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
 51         }
 52     }
 53 
 54     // 无参构造方法
 55     public MyArrayList() {
 56         // 指向默认容量为10的空数组
 57         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 58     }
 59 
 60     // Collection对象作为参数的构造方法
 61     public MyArrayList(Collection<? extends E> c) {
 62         elementData = c.toArray();
 63         if ((size = elementData.length) != 0) {
 64             // c.toArray might (incorrectly) not return Object[] (see 6260652)
 65             // 返回的数组类型可能不是Object[],要看运行时类型(实际类型),例如String[]。这样会导致向下转型,例如修改元素时指向了非继承或实现关系的对象时会出错,String->Integer。
 66             // 原因在于里面存储的元素可能不是Object类型。
 67             if (elementData.getClass() != Object[].class) {
 68                 // 重新指向Object数组。
 69                 // Arrays.copyOf会创建新数组,返回引用。
 70                 elementData = Arrays.copyOf(elementData, size, Object[].class);
 71             }
 72         } else {
 73             // replace with empty array.
 74             this.elementData = EMPTY_ELEMENTDATA;
 75         }
 76     }
 77 
 78     // 将数组长度削减到元素数量对应的长度。
 79     public void trimToSize() {
 80         int count = size;
 81         // 如果实际元素数量小于数组长度
 82         if (count < elementData.length) {
 83             elementData = (count == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, count);
 84         }
 85     }
 86 
 87     // 公有方法,保证容量。
 88     public void ensureCapacity(int minCapacity) {
 89         // 最小增量
 90         int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
 91                 // any size if not default element table
 92                 ? 0
 93                 // larger than default for default empty table. It‘s already
 94                 // supposed to be at default size.
 95                 : DEFAULT_CAPACITY;
 96 
 97         // 如果最小容量大于最小增量则确保最小容量足够。
 98         if (minCapacity > minExpand) {
 99             ensureExplicitCapacity(minCapacity);
100         }
101     }
102 
103     // 确保内部的容量足够。
104     private void ensureCapacityInternal(int minCapacity) {
105         // 如果elementData指向的是默认容量的空数组则说明当前容量为10。
106         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
107             minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
108         }
109 
110         // 确保最小容量足够。
111         ensureExplicitCapacity(minCapacity);
112     }
113 
114     // 确保最小容量足够。
115     private void ensureExplicitCapacity(int minCapacity) {
116         // overflow-conscious code
117         // 如果最小容量大于数组长度则扩容。
118         if (minCapacity - elementData.length > 0) {
119             grow(minCapacity);
120         }
121     }
122 
123     // 可分配的数组最大容量
124     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
125 
126     // 扩容
127     private void grow(int minCapacity) { // minCapacity是需要达到的最小容量。
128         // overflow-conscious code
129         // 原来的容量是数组长度。
130         int oldCapacity = elementData.length;
131         // 新的容量是1.5倍的原有容量。
132         int newCapacity = oldCapacity + (oldCapacity >> 1);
133 
134         // 如果最小容量大于1.5倍的原有容量则最小容量设为新的容量。
135         if (newCapacity - minCapacity < 0) {
136             newCapacity = minCapacity;
137         }
138         // 如果新的容量大于可分配的数组最大容量
139         if (newCapacity - MAX_ARRAY_SIZE > 0) {
140             // minCapacity is usually close to size, so this is a win:
141             newCapacity = hugeCapacity(minCapacity);
142         }
143 
144         // elementData指向扩容后的新数组。
145         elementData = Arrays.copyOf(elementData, newCapacity);
146     }
147 
148     // 确保数组容量最大为Integer.MAX_VALUE。
149     private static int hugeCapacity(int minCapacity) {
150         // 如果最小容量溢出则抛出内存不足错误。
151         // overflow
152         if (minCapacity < 0) {
153             throw new OutOfMemoryError();
154         }
155 
156         // 如果最小容量超过了可分配的数组最大容量则返回整形的最大值作为新容量,否则返回可分配的数组最大容量作为新容量。
157         return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
158     }
159 
160     // 获取实际元素数量。
161     @Override
162     public int size() {
163         return size;
164     }
165 
166     // 判断数组是否为空即判断是否存在实际元素。
167     @Override
168     public boolean isEmpty() {
169         return size == 0;
170     }
171 
172     // 判断是否包含某个元素,通过该元素对应的下标来判断。
173     @Override
174     public boolean contains(Object o) {
175         return indexOf(o) >= 0;
176     }
177 
178     // 顺序获取某个元素对应的下标。
179     @Override
180     public int indexOf(Object o) {
181         if (o == null) { // 如果该元素为空
182             for (int i = 0; i < size; i++) {
183                 if (elementData[i] == null) {
184                     return i;
185                 }
186             }
187         } else { // 否则
188             for (int i = 0; i < size; i++) {
189                 if (o.equals(elementData[i])) {
190                     return i;
191                 }
192             }
193         }
194 
195         // 没有找到该元素。
196         return -1;
197     }
198 
199     // 逆序获取某个元素对应的下标。
200     @Override
201     public int lastIndexOf(Object o) {
202         // 如果该元素为空
203         if (o == null) { 
204             for (int i = size - 1; i >= 0; i--) {
205                 if (elementData[i] == null) {
206                     return i;
207                 }
208             }
209         } else {
210             for (int i = size - 1; i >= 0; i--) {
211                 if (o.equals(elementData[i])) {
212                     return i;
213                 }
214             }
215         }
216 
217         // 没有找到该元素。
218         return -1;
219     }
220 
221     // 浅复制,没有复制数组中元素作为引用指向的对象。
222     // 该方法返回的是当前ArrayList对象的浅复制对象引用。
223     @Override
224     public Object clone() {
225         try {
226             // 调用父类复制方法。
227             // 使用E会出现警告
228             @SuppressWarnings("unchecked")
229             MyArrayList<E> v = (MyArrayList<E>) super.clone();
230             // v.elementData指向存储原来对象(元素)的新数组。
231             v.elementData = Arrays.copyOf(elementData, size);
232             
233             return v;
234         } catch (CloneNotSupportedException e) {
235             // this shouldn‘t happen, since we are Cloneable
236             throw new InternalError(e);
237         }
238     }
239 
240     // 返回一个数据拷贝后的Object数组。
241     @Override
242     public Object[] toArray() {
243         return Arrays.copyOf(elementData, size);
244     }
245 
246     // 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组
247     // 返回数组的运行时类型是指定数组的运行时类型。
248     @Override
249     @SuppressWarnings("unchecked")
250     public <T> T[] toArray(T[] a) {
251         if (a.length < size) {
252             // Make a new array of a‘s runtime type, but my contents:
253             return (T[]) Arrays.copyOf(elementData, size, a.getClass());
254         }
255 
256         System.arraycopy(elementData, 0, a, 0, size);
257 
258         if (a.length > size) {
259             a[size] = null;
260         }
261 
262         return a;
263     }
264 
265     // Positional Access Operations
266     // 按下标随机访问元素。
267     @SuppressWarnings("unchecked")
268     E elementData(int index) {
269         return (E) elementData[index];
270     }
271 
272     // 通过参数检查之后按下标随机访问元素。
273     @Override
274     public E get(int index) {
275         rangeCheck(index);
276 
277         return elementData(index);
278     }
279 
280     // 通过参数检查之后按下标修改元素内容并返回原来的元素内容。
281     @Override
282     public E set(int index, E element) {
283         rangeCheck(index);
284 
285         E oldValue = elementData(index);
286         elementData[index] = element;
287 
288         return oldValue;
289     }
290 
291     // 末尾增加元素。
292     @Override
293     public boolean add(E e) {
294         // 确保容量足够。
295         ensureCapacityInternal(size + 1);
296         elementData[size++] = e;
297 
298         return true;
299     }
300 
301     // 按下标增加元素。可能需要向后移动。
302     @Override
303     public void add(int index, E element) {
304         // 下标检查。
305         rangeCheckForAdd(index);
306 
307         // 确保容量足够。
308         ensureCapacityInternal(size + 1);
309         // 下标大于index的部分向后移。注意size>=index。
310         System.arraycopy(elementData, index, elementData, index + 1, size - index);
311         elementData[index] = element; // 插入新元素。
312         size++; // 实际元素数量增加。
313     }
314 
315     // 按下标删除元素并返回原来的元素内容。
316     @Override
317     public E remove(int index) {
318         // 下标检查。
319         rangeCheck(index);
320 
321         E oldValue = elementData(index);
322 
323         // 可能需要向前移动。注意size>=index。所以numMoved可能小于0。
324         int numMoved = size - index - 1;
325         if (numMoved > 0) {
326             System.arraycopy(elementData, index + 1, elementData, index, numMoved);
327         }
328         elementData[--size] = null; // clear to let GC do its work
329 
330         return oldValue;
331     }
332 
333     // 移除此列表中首次出现的指定元素(如果存在)。
334     @Override
335     public boolean remove(Object o) {
336         if (o == null) { // 如果是空元素
337             for (int index = 0; index < size; index++) {
338                 if (elementData[index] == null) {
339                     fastRemove(index); // 不返回旧值。
340                     return true;
341                 }
342             }
343         } else { // 否则
344             for (int index = 0; index < size; index++) {
345                 if (o.equals(elementData[index])) {
346                     fastRemove(index); // 不返回旧值。
347                     return true;
348                 }
349             }
350         }
351 
352         // 没有找到该元素。
353         return false;
354     }
355 
356     // 根据下标删除元素,但不返回旧值。
357     private void fastRemove(int index) {
358         // 可能需要向前移动。注意size>=index。所以numMoved可能小于0。
359         int numMoved = size - index - 1;
360         if (numMoved > 0) {
361             System.arraycopy(elementData, index + 1, elementData, index, numMoved);
362         }
363         elementData[--size] = null; // clear to let GC do its work
364     }
365 
366     // 移除此列表中的所有元素。
367     @Override
368     public void clear() {
369         // clear to let GC do its work
370         for (int i = 0; i < size; i++) {
371             elementData[i] = null;
372         }
373 
374         size = 0;
375     }
376 
377     // 移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
378     @Override
379     protected void removeRange(int fromIndex, int toIndex) {
380         // 可能需要向前移动。
381         int numMoved = size - toIndex; // 元素移动数量
382         System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
383 
384         // clear to let GC do its work
385         // newSize是新的实际元素数量。
386         int newSize = size - (toIndex - fromIndex);
387         for (int i = newSize; i < size; i++) {
388             elementData[i] = null;
389         }
390         size = newSize; // 更新实际元素数量。
391     }
392 
393     // 下标上界范围检查。
394     private void rangeCheck(int index) {
395         if (index >= size) {
396             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
397         }
398     }
399 
400     // 增加元素时下标范围检查。
401     private void rangeCheckForAdd(int index) {
402         if (index > size || index < 0) {
403             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
404         }
405     }
406 
407     // 输出越界异常提示。
408     private String outOfBoundsMsg(int index) {
409         return "Index: " + index + ", Size: " + size;
410     }
411 
412     // 序列化,elementData写入输出流。
413     private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
414         // Write out element count, and any hidden stuff
415         // 版本向下兼容,旧版本的反序列化值在新版本中序列化会增加新属性的默认值。
416         s.defaultWriteObject();
417 
418         // Write out size as capacity for behavioural compatibility with clone()
419         // 版本向下兼容,旧版本需要读取数组长度length。如果不写入size,会导致旧版本反序列化时出现异常。
420         s.writeInt(size);
421 
422         // Write out all elements in the proper order.
423         for (int i = 0; i < size; i++) {
424             s.writeObject(elementData[i]);
425         }
426     }
427 
428     // 反序列化,elementData从输入流中读取。
429     private void readObject(java.io.ObjectInputStream s)
430             throws java.io.IOException, ClassNotFoundException {
431         // elementData指向空数组。
432         elementData = EMPTY_ELEMENTDATA;
433 
434         // Read in size, and any hidden stuff
435         // 版本向下兼容,旧版本的序列化值在新版本中反序列化时会自动忽略新属性。
436         s.defaultReadObject();
437 
438         // Read in capacity
439         s.readInt(); // ignored
440 
441         // size是通过ObjectOutputStream类中defaultWriteFields方法和ObjectInputStream类中defaultReadFields方法得到的。
442         // 如果存在元素
443         if (size > 0) {
444             // be like clone(), allocate array based upon size not capacity
445             // 确保容量足够。
446             ensureCapacityInternal(size);
447 
448             Object[] a = elementData;
449             // Read in all elements in the proper order.
450             for (int i = 0; i < size; i++) {
451                 a[i] = s.readObject();
452             }
453         }
454     }
455 
456     // 排序
457     @Override
458     @SuppressWarnings("unchecked")
459     public void sort(Comparator<? super E> c) {
460         Arrays.sort((E[]) elementData, 0, size, c);
461     }
462 }

 

以上是关于Java 模仿jdk MyArrayList的主要内容,如果未能解决你的问题,请参考以下文章

自定义数组列表和队列

Java 模仿jdk MyString

设计模式 - 动态代理原理及模仿JDK Proxy 写一个属于自己的动态代理

javascript 一个后台UI的多片实现(模仿浏览器的多标签)

实现MyArrayList类深入理解ArrayList

自定义一个MyArrayList方法---------实现部分方法