最近正准备回顾一下Java,所以在此做一些记录。

ArrayList作为Java的基础集合,因支持动态的扩容而经常被使用,下面记录一下其常用方法的实现

1. add(E e) 在集合末尾新增一个元素

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 添加一个元素3 *4 *@parame 所要添加的元素5 *@return

6 */

7 public booleanadd(E e) {8 //将会进行判断数组是否是要扩容,需要的话将会进行扩容

9 ensureCapacityInternal(size + 1);10 //存放元素,size表示当前集合中元素的个数

11 elementData[size++] =e;12 return true;13 }14

15 /**

16 * 判断该集合是否满足最小容量并进行扩容17 *@paramminCapacity 最小容量18 */

19 private voidensureCapacityInternal (intminCapacity) {20 if (elementData ==EMPTY_ELEMENTDATA) {21 //如果本来就是空数组,则根据默认值和当前所需的最小容量取一个最大值作为新数组的大小22 //DEFAULT_CAPACITY = 10, 所以如果新建一个没有指定大小的集合,添加第一个元素后集合大小变成10

23 minCapacity =Math.max(DEFAULT_CAPACITY, minCapacity);24 }25 //扩容

26 ensureExplicitCapacity(minCapacity);27 }28

29 /**

30 * 判断当前集合大小是否需要扩容31 *@paramminCapacity 最小容量32 */

33 private void ensureExplicitCapacity(intminCapacity) {34 modCount++;35

36 //如果最小容量大于当前数组大小,则进行真正的扩容操作

37 if (minCapacity - elementData.length > 0)38 grow(minCapacity);39 }40

41 /**

42 * 真正的扩容操作43 *44 *@paramminCapacity 最小容量45 */

46 private void grow(intminCapacity) {47 //获取旧数组的值

48 int oldCapacity =elementData.length;49 //先将旧数组扩充1.5倍

50 int newCapacity = oldCapacity + (oldCapacity >> 1);51 //判断旧数组扩充1.5倍是否够用,不够就使用传入的最小容量

52 if (newCapacity - minCapacity < 0)53 newCapacity =minCapacity;54 //判断是否为超大数组 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

55 if (newCapacity - MAX_ARRAY_SIZE > 0)56 newCapacity =hugeCapacity(minCapacity);57 //使用Arrays.copyOf来生成新的数组58 //里面也是新创建了一个数组,使用System.arraycopy将旧数组的数据迁移到新数组中

59 elementData =Arrays.copyOf(elementData, newCapacity);60 }61

62 /**

63 * 超大数组的判断64 *65 *@paramminCapacity66 *@return

67 */

68 private static int hugeCapacity(intminCapacity) {69 //判断minCapacity是否已经溢出了,超过了int的最大值

70 if (minCapacity < 0)71 throw newOutOfMemoryError();72 //超过MAX_ARRAY_SIZE则返回int最大值,否则返回MAX_ARRAY_SIZE

73 return (minCapacity > MAX_ARRAY_SIZE) ?

74 Integer.MAX_VALUE :75 MAX_ARRAY_SIZE;76 }

View Code

2.add(int index, E element) 在指定位置添加元素

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 指定位置添加元素3 *4 *@paramindex 指定元素的位置5 *@paramelement 添加的元素6 */

7 public void add(intindex, E element) {8 //判断需要插入的位置是否越界

9 rangeCheckForAdd(index);10 //和add一样的扩容操作

11 ensureCapacityInternal(size + 1);12 //直接使用了System.arraycopy,将指定位置之后的元素往后移动一位

13 System.arraycopy(elementData, index, elementData, index + 1,14 size -index);15 //插入指定的元素

16 elementData[index] =element;17 //元素个数增加

18 size++;19 }20

21 /**

22 * 判断指定的位置是否越界23 */

24 private void rangeCheckForAdd(intindex) {25 if (index > size || index < 0)26 throw newIndexOutOfBoundsException(outOfBoundsMsg(index));27 }

View Code

3.get(int index)获取指定位置的元素

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 获取指定位置处的元素3 *4 *@paramindex 指定的位置5 *@return返回该位置的元素6 */

7 public E get(intindex) {8 //判断是否越界

9 rangeCheck(index);10 //获取元素

11 returnelementData(index);12 }13

14 private void rangeCheck(intindex) {15 //判断是否超出

16 if (index >=size)17 throw newIndexOutOfBoundsException(outOfBoundsMsg(index));18 }

View Code

4.remove(int index) 删除指定位置的元素

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 删除指定位置的元素3 *4 *@paramindex 指定的位置5 *@return返回删除的元素6 */

7 public E remove(intindex) {8 //判断指定的位置是否越界

9 rangeCheck(index);10

11 modCount++;12 //获取到该元素

13 E oldValue =elementData(index);14

15 //计算需要移动的元素个数

16 int numMoved = size - index - 1;17 //使用System.arraycopy将删除位置之后的元素往前移动

18 if (numMoved > 0)19 System.arraycopy(elementData, index+1, elementData, index,20 numMoved);21 //元素个数减1并制设置空

22 elementData[--size] = null;23

24 returnoldValue;25 }

View Code

5.remove(Object o) 删除指定元素

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 删除指定元素,只删除从头开始第一个匹配的3 *4 *@paramo 需要删除的元素5 */

6 public booleanremove(Object o) {7 //判断是否为null

8 if (o == null) {9 //遍历

10 for (int index = 0; index < size; index++)11 //判断是否为null

12 if (elementData[index] == null) {13 //删除

14 fastRemove(index);15 return true;16 }17 } else{18 //不为null也是遍历

19 for (int index = 0; index < size; index++)20 if(o.equals(elementData[index])) {21 //删除

22 fastRemove(index);23 return true;24 }25 }26 return false;27 }28

29 /*

30 * 删除指定位置元素31 * 和remove方法差不多,只是少了越界判断和旧元素的返回32 */

33 private void fastRemove(intindex) {34

35 modCount++;36 int numMoved = size - index - 1;37 if (numMoved > 0)38 System.arraycopy(elementData, index+1, elementData, index,39 numMoved);40 elementData[--size] = null;41 }

View Code

6.indexOf(Object o) 查询指定元素的位置  lastIndexOf也一样,只是从尾部开始遍历

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 查询指定元素的位置3 *@paramo 指定的元素4 *@return所在位置索引5 */

6 public intindexOf(Object o) {7 //判断元素值是否为null

8 if (o == null) {9 //从头开始遍历

10 for (int i = 0; i < size; i++)11 if (elementData[i]==null)12 returni;13 } else{14 //不为null,从头开始遍历

15 for (int i = 0; i < size; i++)16 if(o.equals(elementData[i]))17 returni;18 }19 return -1;20 }

View Code

7.set(int index, E element) 设置指定位置的元素值

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 设置指定位置的元素值3 *4 *@paramindex 指定的位置5 *@paramelement 元素值6 *@return返回旧值7 */

8 public E set(intindex, E element) {9 //判断是否越界

10 rangeCheck(index);11 //通过索引设置新值

12 E oldValue =elementData(index);13 elementData[index] =element;14 returnoldValue;15 }16

17 private void rangeCheck(intindex) {18 //判断是否超出

19 if (index >=size)20 throw newIndexOutOfBoundsException(outOfBoundsMsg(index));21 }

View Code

8.retainAll(Collection> c) 求两个集合的交集

java快递列表 java list菜鸟教程_java快递列表

java快递列表 java list菜鸟教程_指定位置_02

1 /**

2 * 求两个集合的交集3 *@paramc4 *@return

5 */

6 public boolean retainAll(Collection>c) {7 //判断是否为空

8 Objects.requireNonNull(c);9 return batchRemove(c, true);10 }11

12 /**

13 * 求交集或差集14 *@paramc15 *@paramcomplement 用于判断保存下来的集合是交集还是差集16 *@return

17 */

18 private boolean batchRemove(Collection> c, booleancomplement) {19 final Object[] elementData = this.elementData;20 int r = 0, w = 0;21 boolean modified = false;22 try{23 //遍历集合判断元素

24 for (; r < size; r++)25 //根据complement的值保留元素

26 if (c.contains(elementData[r]) ==complement)27 elementData[w++] =elementData[r];28 } finally{29 //r != size 应该是上面的循环抛出异常了30 //正常循环应该r == size31 //将异常之后的数据保留

32 if (r !=size) {33 System.arraycopy(elementData, r,34 elementData, w,35 size -r);36 w += size -r;37 }38 //w!=size,说明集合数量有变动39 //清空一些元素值并重新设置size大小

40 if (w !=size) {41 for (int i = w; i < size; i++)42 elementData[i] = null;43 modCount += size -w;44 size =w;45 modified = true;46 }47 }48 returnmodified;49 }

View Code

总结一下

1.ArrayList作为集合,根据索引查询的速度最快,如果需要查询指定元素,需要遍历,并不会很快

2.ArrayList使用的时候最好指定集合大小,否则插入操作多的话会经常需要扩容,需要进行数组的复制,比较慢

3.ArrayList的删除元素和插入指定位置的元素会存在部分元素迁移的情况,如果数据量大也会有影响