java.util 1.8_JDK1.8源码(五)——java.util.ArrayList 类

关于 JDK 的集合类的整体介绍可以看这张图,本篇博客我们不系统的介绍整个集合的构造,重点是介绍 ArrayList 类是如何实现的。

1、ArrayList 定义

ArrayList 是一个用数组实现的集合,支持随机访问,元素有序且可以重复。

public class ArrayList extends AbstractList

implements List, RandomAccess, Cloneable, java.io.Serializable

2d3b4a42d29dc24824c515b880b76d67.png

①、实现 RandomAccess 接口

这是一个标记接口,一般此标记接口用于 List实现,以表明它们支持快速(通常是恒定时间)的随机访问。该接口的主要目的是允许通用算法改变其行为,以便在应用于随机或顺序访问列表时提供良好的性能。

比如在工具类 Collections(这个工具类后面会详细讲解)中,应用二分查找方法时判断是否实现了 RandomAccess 接口:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 int binarySearch(List extends Comparable super T>>list, T key) {2 if (list instanceof RandomAccess || list.size()

5 returnCollections.iteratorBinarySearch(list, key);6 }

View Code

②、实现 Cloneable 接口

这个类是 java.lang.Cloneable,前面我们讲解深拷贝和浅拷贝的原理时,我们介绍了浅拷贝可以通过调用 Object.clone() 方法来实现,但是调用该方法的对象必须要实现 Cloneable 接口,否则会抛出 CloneNoSupportException异常。

Cloneable 和 RandomAccess 接口一样也是一个标记接口,接口内无任何方法体和常量的声明,也就是说如果想克隆对象,必须要实现 Cloneable 接口,表明该类是可以被克隆的。

③、实现 Serializable 接口

这个没什么好说的,也是标记接口,表示能被序列化。

④、实现 List 接口

这个接口是 List 类集合的上层接口,定义了实现该接口的类都必须要实现的一组方法,如下所示,下面我们会对这一系列方法的实现做详细介绍。

216419d784e0d43496f07fb9a3cef44e.png

2、字段属性

//集合的默认大小

private static final int DEFAULT_CAPACITY = 10;//空的数组实例

private static final Object[] EMPTY_ELEMENTDATA ={};//这也是一个空的数组实例,和EMPTY_ELEMENTDATA空数组相比是用于了解添加元素时数组膨胀多少

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA ={};//存储 ArrayList集合的元素,集合的长度即这个数组的长度//1、当 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时将会清空 ArrayList//2、当添加第一个元素时,elementData 长度会扩展为 DEFAULT_CAPACITY=10

transientObject[] elementData;//表示集合的长度

private int size;

3、构造函数

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 publicArrayList() {2 this.elementData =DEFAULTCAPACITY_EMPTY_ELEMENTDATA;3 }

View Code

此无参构造函数将创建一个 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 声明的数组,注意此时初始容量是0,而不是大家以为的 10。

注意:根据默认构造函数创建的集合,ArrayList list = new ArrayList();此时集合长度是0.

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public ArrayList(intinitialCapacity) {if (initialCapacity > 0) {this.elementData = newObject[initialCapacity];

}else if (initialCapacity == 0) {this.elementData =EMPTY_ELEMENTDATA;

}else{throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);

}

}

View Code

初始化集合大小创建 ArrayList 集合。当大于0时,给定多少那就创建多大的数组;当等于0时,创建一个空数组;当小于0时,抛出异常。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public ArrayList(Collection extends E>c) {2 elementData =c.toArray();3 if ((size = elementData.length) != 0) {4 //c.toArray might (incorrectly) not return Object[] (see 6260652)

5 if (elementData.getClass() != Object[].class)6 elementData = Arrays.copyOf(elementData, size, Object[].class);7 } else{8 //replace with empty array.

9 this.elementData =EMPTY_ELEMENTDATA;10 }11 }

View Code

这是将已有的集合复制到 ArrayList 集合中去。

4、添加元素

通过前面的字段属性和构造函数,我们知道 ArrayList 集合是由数组构成的,那么向 ArrayList 中添加元素,也就是向数组赋值。我们知道一个数组的声明是能确定大小的,而使用 ArrayList 时,好像是能添加任意多个元素,这就涉及到数组的扩容。

扩容的核心方法就是调用前面我们讲过的Arrays.copyOf 方法,创建一个更大的数组,然后将原数组元素拷贝过去即可。下面我们看看具体实现:

public booleanadd(E e) {

ensureCapacityInternal(size+ 1); //添加元素之前,首先要确定集合的大小

elementData[size++] =e;return true;

}

如上所示,在通过调用 add 方法添加元素之前,我们要首先调用 ensureCapacityInternal 方法来确定集合的大小,如果集合满了,则要进行扩容操作。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 private void ensureCapacityInternal(int minCapacity) {//这里的minCapacity 是集合当前大小+12 //elementData 是实际用来存储元素的数组,注意数组的大小和集合的大小不是相等的,前面的size是指集合大小

3 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));4 }5 private static int calculateCapacity(Object[] elementData, intminCapacity) {6 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果数组为空,则从size+1的值和默认值10中取最大的

7 returnMath.max(DEFAULT_CAPACITY, minCapacity);8 }9 return minCapacity;//不为空,则返回size+1

10 }11 private void ensureExplicitCapacity(intminCapacity) {12 modCount++;13

14 //overflow-conscious code

15 if (minCapacity - elementData.length > 0)16 grow(minCapacity);17 }

View Code

在 ensureExplicitCapacity 方法中,首先对修改次数modCount加一,这里的modCount给ArrayList的迭代器使用的,在并发操作被修改时,提供快速失败行为(保证modCount在迭代期间不变,否则抛出ConcurrentModificationException异常,可以查看源码865行),接着判断minCapacity是否大于当前ArrayList内部数组长度,大于的话调用grow方法对内部数组elementData扩容,grow方法代码如下:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 private void grow(intminCapacity) {2 int oldCapacity = elementData.length;//得到原始数组的长度

3 int newCapacity = oldCapacity + (oldCapacity >> 1);//新数组的长度等于原数组长度的1.5倍

4 if (newCapacity - minCapacity < 0)//当新数组长度仍然比minCapacity小,则为保证最小长度,新数组等于minCapacity

5 newCapacity =minCapacity;6 //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 = 2147483639

7 if (newCapacity - MAX_ARRAY_SIZE > 0)//当得到的新数组长度比 MAX_ARRAY_SIZE 大时,调用 hugeCapacity 处理大数组

8 newCapacity =hugeCapacity(minCapacity);9 //调用 Arrays.copyOf 将原数组拷贝到一个大小为newCapacity的新数组(注意是拷贝引用)

10 elementData =Arrays.copyOf(elementData, newCapacity);11 }12

13 private static int hugeCapacity(intminCapacity) {14 if (minCapacity < 0) //

15 throw newOutOfMemoryError();16 return (minCapacity > MAX_ARRAY_SIZE) ? //minCapacity > MAX_ARRAY_SIZE,则新数组大小为Integer.MAX_VALUE

17 Integer.MAX_VALUE :18 MAX_ARRAY_SIZE;19 }

View Code

对于 ArrayList 集合添加元素,我们总结一下:

①、当通过 ArrayList() 构造一个空集合,初始长度是为0的,第 1 次添加元素,会创建一个长度为10的数组,并将该元素赋值到数组的第一个位置。

②、第 2 次添加元素,集合不为空,而且由于集合的长度size+1是小于数组的长度10,所以直接添加元素到数组的第二个位置,不用扩容。

③、第 11 次添加元素,此时 size+1 = 11,而数组长度是10,这时候创建一个长度为10+10*0.5 = 15 的数组(扩容1.5倍),然后将原数组元素引用拷贝到新数组。并将第 11 次添加的元素赋值到新数组下标为10的位置。

④、第 Integer.MAX_VALUE - 8 = 2147483639,然后 2147483639%1.5=1431655759(这个数是要进行扩容) 次添加元素,为了防止溢出,此时会直接创建一个 1431655759+1 大小的数组,这样一直,每次添加一个元素,都只扩大一个范围。

⑤、第 Integer.MAX_VALUE - 7 次添加元素时,创建一个大小为 Integer.MAX_VALUE 的数组,在进行元素添加。

⑥、第 Integer.MAX_VALUE + 1 次添加元素时,抛出 OutOfMemoryError 异常。

注意:能向集合中添加 null 的,因为数组可以有 null 值存在。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 Object[] obj = {null,1};2

3 ArrayList list = newArrayList();4 list.add(null);5 list.add(1);6 System.out.println(list.size());//2

View Code

5、删除元素

①、根据索引删除元素

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public E remove(intindex) {2 rangeCheck(index);//判断给定索引的范围,超过集合大小则抛出异常

3

4 modCount++;5 E oldValue = elementData(index);//得到索引处的删除元素

6

7 int numMoved = size - index - 1;8 if (numMoved > 0)//size-index-1 > 0 表示 0<= index < (size-1),即索引不是最后一个元素9 //通过 System.arraycopy()将数组elementData 的下标index+1之后长度为 numMoved的元素拷贝到从index开始的位置

10 System.arraycopy(elementData, index+1, elementData, index,11 numMoved);12 elementData[--size] = null; //将数组最后一个元素置为 null,便于垃圾回收

13

14 returnoldValue;15 }

View Code

remove(int index) 方法表示删除索引index处的元素,首先通过 rangeCheck(index) 方法判断给定索引的范围,超过集合大小则抛出异常;接着通过 System.arraycopy 方法对数组进行自身拷贝。关于这个方法的用法可以参考这篇博客。

②、直接删除指定元素

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public booleanremove(Object o) {2 if (o == null) {//如果删除的元素为null

3 for (int index = 0; index < size; index++)4 if (elementData[index] == null) {5 fastRemove(index);6 return true;7 }8 } else {//不为null,通过equals方法判断对象是否相等

9 for (int index = 0; index < size; index++)10 if(o.equals(elementData[index])) {11 fastRemove(index);12 return true;13 }14 }15 return false;16 }17

18

19 private void fastRemove(intindex) {20 modCount++;21 int numMoved = size - index - 1;22 if (numMoved > 0)23 System.arraycopy(elementData, index+1, elementData, index,24 numMoved);25 elementData[--size] = null; //

26 }

View Code

remove(Object o)方法是删除第一次出现的该元素。然后通过System.arraycopy进行数组自身拷贝。

6、修改元素

通过调用 set(int index, E element) 方法在指定索引 index 处的元素替换为 element。并返回原数组的元素。

1 public E set(intindex, E element) {2 rangeCheck(index);//判断索引合法性

3

4 E oldValue = elementData(index);//获得原数组指定索引的元素

5 elementData[index] = element;//将指定所引处的元素替换为 element

6 return oldValue;//返回原数组索引元素

7 }

通过调用 rangeCheck(index) 来检查索引合法性。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

private void rangeCheck(intindex) {if (index >=size)throw newIndexOutOfBoundsException(outOfBoundsMsg(index));

}

View Code

当索引为负数时,会抛出 java.lang.ArrayIndexOutOfBoundsException 异常。当索引大于集合长度时,会抛出 IndexOutOfBoundsException 异常。

7、查找元素

①、根据索引查找元素

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public E get(intindex) {2 rangeCheck(index);3

4 returnelementData(index);5 }

View Code

同理,首先还是判断给定索引的合理性,然后直接返回处于该下标位置的数组元素。

②、根据元素查找索引

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public intindexOf(Object o) {2 if (o == null) {3 for (int i = 0; i < size; i++)4 if (elementData[i]==null)5 returni;6 } else{7 for (int i = 0; i < size; i++)8 if(o.equals(elementData[i]))9 returni;10 }11 return -1;12 }

View Code

注意:indexOf(Object o) 方法是返回第一次出现该元素的下标,如果没有则返回 -1。

还有 lastIndexOf(Object o) 方法是返回最后一次出现该元素的下标。

8、遍历集合

①、普通 for 循环遍历

前面我们介绍查找元素时,知道可以通过get(int index)方法,根据索引查找元素,那么遍历同理:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = newArrayList();2 list.add("a");3 list.add("b");4 list.add("c");5 for(int i = 0 ; i < list.size() ; i++){6 System.out.print(list.get(i)+" ");7 }

View Code

②、迭代器 iterator

先看看具体用法:

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5 Iterator it =list.iterator();6 while(it.hasNext()){7 String str =it.next();8 System.out.print(str+" ");9 }

在介绍 ArrayList 时,我们知道该类实现了 List 接口,而 List 接口又继承了 Collection 接口,Collection 接口又继承了 Iterable 接口,该接口有个 Iterator iterator() 方法,能获取 Iterator 对象,能用该对象进行集合遍历,为什么能用该对象进行集合遍历?我们再看看 ArrayList 类中的该方法实现:

1 public Iteratoriterator() {2 return newItr();3 }

该方法是返回一个 Itr 对象,这个类是 ArrayList 的内部类。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 private class Itr implements Iterator{2 int cursor; //游标, 下一个要返回的元素的索引

3 int lastRet = -1; //返回最后一个元素的索引; 如果没有这样的话返回-1.

4 int expectedModCount =modCount;5

6 //通过 cursor != size 判断是否还有下一个元素

7 public booleanhasNext() {8 return cursor !=size;9 }10

11 @SuppressWarnings("unchecked")12 publicE next() {13 checkForComodification();//迭代器进行元素迭代时同时进行增加和删除操作,会抛出异常

14 int i =cursor;15 if (i >=size)16 throw newNoSuchElementException();17 Object[] elementData = ArrayList.this.elementData;18 if (i >=elementData.length)19 throw newConcurrentModificationException();20 cursor = i + 1;//游标向后移动一位

21 return (E) elementData[lastRet = i];//返回索引为i处的元素,并将 lastRet赋值为i

22 }23

24 public voidremove() {25 if (lastRet < 0)26 throw newIllegalStateException();27 checkForComodification();28

29 try{30 ArrayList.this.remove(lastRet);//调用ArrayList的remove方法删除元素

31 cursor = lastRet;//游标指向删除元素的位置,本来是lastRet+1的,这里删除一个元素,然后游标就不变了

32 lastRet = -1;//lastRet恢复默认值-1

33 expectedModCount = modCount;//expectedModCount值和modCount同步,因为进行add和remove操作,modCount会加1

34 } catch(IndexOutOfBoundsException ex) {35 throw newConcurrentModificationException();36 }37 }38

39 @Override40 @SuppressWarnings("unchecked")41 public void forEachRemaining(Consumer super E> consumer) {//便于进行forEach循环

42 Objects.requireNonNull(consumer);43 final int size = ArrayList.this.size;44 int i =cursor;45 if (i >=size) {46 return;47 }48 final Object[] elementData = ArrayList.this.elementData;49 if (i >=elementData.length) {50 throw newConcurrentModificationException();51 }52 while (i != size && modCount ==expectedModCount) {53 consumer.accept((E) elementData[i++]);54 }55 //update once at end of iteration to reduce heap write traffic

56 cursor =i;57 lastRet = i - 1;58 checkForComodification();59 }60

61 //前面在新增元素add() 和 删除元素 remove() 时,我们可以看到 modCount++。修改set() 是没有的62 //也就是说不能在迭代器进行元素迭代时进行增加和删除操作,否则抛出异常

63 final voidcheckForComodification() {64 if (modCount !=expectedModCount)65 throw newConcurrentModificationException();66 }67 }

View Code

注意在进行 next() 方法调用的时候,会进行 checkForComodification() 调用,该方法表示迭代器进行元素迭代时,如果同时进行增加和删除操作,会抛出 ConcurrentModificationException 异常。比如:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5 Iterator it =list.iterator();6 while(it.hasNext()){7 String str =it.next();8 System.out.print(str+" ");9 list.remove(str);//集合遍历时进行删除或者新增操作,都会抛出 ConcurrentModificationException 异常10 //list.add(str);

11 list.set(0, str);//修改操作不会造成异常

12 }

View Code

df538f73bd3bace779eb7a29a761cde4.png

解决办法是不调用 ArrayList.remove() 方法,转而调用 迭代器的 remove() 方法:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 Iterator it =list.iterator();2 while(it.hasNext()){3 String str =it.next();4 System.out.print(str+" ");5 //list.remove(str);//集合遍历时进行删除或者新增操作,都会抛出 ConcurrentModificationException 异常

6 it.remove();7 }

View Code

注意:迭代器只能向后遍历,不能向前遍历,能够删除元素,但是不能新增元素。

③、迭代器的变种 forEach

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5 for(String str : list){6 System.out.print(str + " ");7 }

View Code

这种语法可以看成是 JDK 的一种语法糖,通过反编译 class 文件,我们可以看到生成的 java 文件,其具体实现还是通过调用 Iterator 迭代器进行遍历的。如下:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = newArrayList();2 list.add("a");3 list.add("b");4 list.add("c");5 String str;6 for (Iterator iterator1 = list.iterator(); iterator1.hasNext(); System.out.print((new StringBuilder(String.valueOf(str))).append(" ").toString()))7 str = (String)iterator1.next();

View Code

④、迭代器 ListIterator

还是先看看具体用法:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5 ListIterator listIt =list.listIterator();6

7 //向后遍历

8 while(listIt.hasNext()){9 System.out.print(listIt.next()+" ");//a b c

10 }11

12 //向后前遍历,此时由于上面进行了向后遍历,游标已经指向了最后一个元素,所以此处向前遍历能有值

13 while(listIt.hasPrevious()){14 System.out.print(listIt.previous()+" ");//c b a

15 }

View Code

还能一边遍历,一边进行新增或者删除操作:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5 ListIterator listIt =list.listIterator();6

7 //向后遍历

8 while(listIt.hasNext()){9 System.out.print(listIt.next()+" ");//a b c

10 listIt.add("1");//在每一个元素后面增加一个元素 "1"

11 }12

13 //向后前遍历,此时由于上面进行了向后遍历,游标已经指向了最后一个元素,所以此处向前遍历能有值

14 while(listIt.hasPrevious()){15 System.out.print(listIt.previous()+" ");//1 c 1 b 1 a

16 }

View Code

也就是说相比于 Iterator 迭代器,这里的 ListIterator 多出了能向前迭代,以及能够新增元素。下面我们看看具体实现:

对于  Iterator 迭代器,我们查看 JDK 源码,发现还有 ListIterator 接口继承了 Iterator:

public interface ListIterator extends Iterator

该接口有如下方法:

ef76a204f452c2924c07363ddeda5d88.png

我们看在 ArrayList 类中,有如下方法可以获得 ListIterator 接口:

public ListIteratorlistIterator() {return new ListItr(0);

}

这里的 ListItr 也是一个内部类。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 //注意 内部类 ListItr 继承了另一个内部类 Itr

2 private class ListItr extends Itr implements ListIterator{3 ListItr(int index) {//构造函数,进行游标初始化

4 super();5 cursor =index;6 }7

8 public boolean hasPrevious() {//判断是否有上一个元素

9 return cursor != 0;10 }11

12 public int nextIndex() {//返回下一个元素的索引

13 returncursor;14 }15

16 public int previousIndex() {//返回上一个元素的索引

17 return cursor - 1;18 }19

20 //该方法获取当前索引的上一个元素

21 @SuppressWarnings("unchecked")22 publicE previous() {23 checkForComodification();//迭代器进行元素迭代时同时进行增加和删除操作,会抛出异常

24 int i = cursor - 1;25 if (i < 0)26 throw newNoSuchElementException();27 Object[] elementData = ArrayList.this.elementData;28 if (i >=elementData.length)29 throw newConcurrentModificationException();30 cursor = i;//游标指向上一个元素

31 return (E) elementData[lastRet = i];//返回上一个元素的值

32 }33

34

35 public voidset(E e) {36 if (lastRet < 0)37 throw newIllegalStateException();38 checkForComodification();39

40 try{41 ArrayList.this.set(lastRet, e);42 } catch(IndexOutOfBoundsException ex) {43 throw newConcurrentModificationException();44 }45 }46

47 //相比于迭代器 Iterator ,这里多了一个新增操作

48 public voidadd(E e) {49 checkForComodification();50

51 try{52 int i =cursor;53 ArrayList.this.add(i, e);54 cursor = i + 1;55 lastRet = -1;56 expectedModCount =modCount;57 } catch(IndexOutOfBoundsException ex) {58 throw newConcurrentModificationException();59 }60 }61 }

View Code

9、SubList

在 ArrayList 中有这样一个方法:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public List subList(int fromIndex, inttoIndex) {2 subListRangeCheck(fromIndex, toIndex, size);3 return new SubList(this, 0, fromIndex, toIndex);4 }

View Code

作用是返回从 fromIndex(包括) 开始的下标,到 toIndex(不包括) 结束的下标之间的元素视图。如下:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5

6 List subList = list.subList(0, 1);7 for(String str : subList){8 System.out.print(str + " ");//a

9 }

View Code

这里出现了 SubList 类,这也是 ArrayList 中的一个内部类。

注意:返回的是原集合的视图,也就是说,如果对 subList 出来的集合进行修改或新增操作,那么原始集合也会发生同样的操作。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ArrayList list = new ArrayList<>();2 list.add("a");3 list.add("b");4 list.add("c");5

6 List subList = list.subList(0, 1);7 for(String str : subList){8 System.out.print(str + " ");//a

9 }10 subList.add("d");11 System.out.println(subList.size());//2

12 System.out.println(list.size());//4,原始集合长度也增加了

View Code

想要独立出来一个集合,解决办法如下:

List subList = new ArrayList<>(list.subList(0, 1));

10、size()

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public intsize() {returnsize;

}

View Code

注意:返回集合的长度,而不是数组的长度,这里的 size 就是定义的全局变量。

11、isEmpty()

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public booleanisEmpty() {2 return size == 0;3 }

View Code

返回 size == 0 的结果。

12、trimToSize()

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public voidtrimToSize() {2 modCount++;3 if (size

View Code

该方法用于回收多余的内存。也就是说一旦我们确定集合不在添加多余的元素之后,调用 trimToSize() 方法会将实现集合的数组大小刚好调整为集合元素的大小。

注意:该方法会花时间来复制数组元素,所以应该在确定不会添加元素之后在调用。

参考文档:https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值