Java集合:关于ArrayList类 柔光的暖阳◎ 2024-03-31 12:21 25阅读 0赞 #### 文章目录 #### * 一、ArrayList的概念 * 二、ArrayList的方法 * * 2.1构造方法 * 2.2 \*\*ArrayList中的常用方法\*\* * 2.3代码演示 * 三、ArrayList的动态扩容 * * 3.1ArrayList 源码分析 * 3.2总结 ## 一、ArrayList的概念 ## ArrayList 类**底层数据结构是动态数组**,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。 ArrayList 继承了 AbstractList ,并实现了 List 接口。 ArrayLisy不但拥有Collection中的方法,还拥有List中的所有方法 ![img][] **特点:** 1. 有序 2. 可重复 3. 数据可为null 4. 查询快 **缺点:** 1.增删慢 ArrayList 类位于 java.util 包中,使用前需要引入它,**语法格式如下:** import java.util.ArrayList; // 引入 ArrayList 类 ArrayList<E> objectName =new ArrayList<>(); // 初始化 ## 二、ArrayList的方法 ## ### 2.1构造方法 ### ArrayList中有三种构造方法 * `public ArrayList()` 构造一个初始容量为0的空列表。在添加元素的时候,赋予默认容量10。 * `public ArrayList(Collection<? extends E> c)` 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。 * `public ArrayList(int initialCapacity)`构造具有指定初始容量的空 ### 2.2 **ArrayList中的常用方法** ### <table> <thead> <tr> <th align="left">方法</th> <th align="left">描述</th> </tr> </thead> <tbody> <tr> <td align="left">add()</td> <td align="left">将元素插入到指定位置的 arraylist 中</td> </tr> <tr> <td align="left">addAll()</td> <td align="left">添加集合中的所有元素到 arraylist 中</td> </tr> <tr> <td align="left">clear()</td> <td align="left">删除 arraylist 中的所有元素</td> </tr> <tr> <td align="left">clone()</td> <td align="left">复制一份 arraylist</td> </tr> <tr> <td align="left">contains()</td> <td align="left">判断元素是否在 arraylist</td> </tr> <tr> <td align="left">get()</td> <td align="left">通过索引值获取 arraylist 中的元素</td> </tr> <tr> <td align="left">indexOf()</td> <td align="left">返回 arraylist 中元素的索引值</td> </tr> <tr> <td align="left">removeAll()</td> <td align="left">删除存在于指定集合中的 arraylist 里的所有元素</td> </tr> <tr> <td align="left">remove()</td> <td align="left">删除 arraylist 里的单个元素</td> </tr> <tr> <td align="left">size()</td> <td align="left">返回 arraylist 里元素数量</td> </tr> <tr> <td align="left">isEmpty()</td> <td align="left">判断 arraylist 是否为空</td> </tr> <tr> <td align="left">subList()</td> <td align="left">截取部分 arraylist 的元素</td> </tr> <tr> <td align="left">set()</td> <td align="left">替换 arraylist 中指定索引的元素</td> </tr> <tr> <td align="left">sort()</td> <td align="left">对 arraylist 元素进行排序</td> </tr> <tr> <td align="left">toArray()</td> <td align="left">将 arraylist 转换为数组</td> </tr> <tr> <td align="left">toString()</td> <td align="left">将 arraylist 转换为字符串</td> </tr> <tr> <td align="left">ensureCapacity</td> <td align="left">设置指定容量大小的 arraylist</td> </tr> <tr> <td align="left">lastIndexOf()</td> <td align="left">返回指定元素在 arraylist 中最后一次出现的位置</td> </tr> <tr> <td align="left">retainAll()</td> <td align="left">保留 arraylist 中在指定集合中也存在的那些元素</td> </tr> <tr> <td align="left">containsAll()</td> <td align="left">查看 arraylist 是否包含指定集合中的所有元素</td> </tr> <tr> <td align="left">trimToSize()</td> <td align="left">将 arraylist 中的容量调整为数组中的元素个数</td> </tr> <tr> <td align="left">removeRange()</td> <td align="left">删除 arraylist 中指定索引之间存在的元素</td> </tr> <tr> <td align="left">replaceAll()</td> <td align="left">将给定的操作内容替换掉数组中每一个元素</td> </tr> <tr> <td align="left">removeIf()</td> <td align="left">删除所有满足特定条件的 arraylist 元素</td> </tr> <tr> <td align="left">forEach()</td> <td align="left">遍历 arraylist 中每一个元素并执行特定操作</td> </tr> </tbody> </table> ### 2.3代码演示 ### import java.util.ArrayList; public class DemoTest { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); //添加元素 list.add("xiaoming"); list.add("xiaoliang"); list.add("xiaodu"); //访问元素 list.get(0); //修改元素 list.set(0,"xiaozhang"); //删除元素 list.remove(0); //计算集合大小 list.size(); //排序 Collections.sort(list);//默认升序 //遍历集合 for (String str : list) { System.out.print(str);//xiaoduxiaoliang } } } ## 三、ArrayList的动态扩容 ## ### 3.1ArrayList 源码分析 ### ArrayList<String> list = new ArrayList<String>(); **ArrayList主要属性:** // 如果不指定容量(空构造器),则在添加数据时去构造器默认初始容量最小为 10 private static final int DEFAULT_CAPACITY = 10; // 出现在需要用到空数组的地方,其中一处是使用自定义初始容量构造方法时候如果你指定初始容量为0的时候,那么elementData指向该数组 // 另一处是使用包含指定collection集合元素的列表的构造方法时,如果被包含的列表中没有数据,那么elementData指向该数组 private static final Object[] EMPTY_ELEMENTDATA = { }; // 如果使用默认构造方法,那么elementData指向该数组 // 在添加元素时会判断是否是使用默认构造器第一次添加,如果是数组就会扩容至10个容量 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = { }; // 默认未初始化的储存 ArrayList集合元素的底层数组,其长度就是 ArrayList的容量 transient Object[] elementData; // 私有的elementData数组中具体的元素对象的数量,可通过size方法获得。默认初始值为0,在add、remove等方法时size会改变 private int size; **ArrayList构造方法:** // 默认的构造器 public ArrayList() { // Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {} 空数组 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 自定义容量大小的构造器 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); } } 从上面的构造器中,可以得出以下结论 * 如果使用 ArrayList 的默认构造器时,它的**初始容量就是 0** * 如果使用 ArrayList 的有参构造器时,它的初始容量就是你传入的参数 `initialCapacity`的值 根据上面的两个结论,不管是使用默认或有参构造器时,我们可以使其**初始容量为 0**,那么它的动态扩容发生在哪里?可以肯定就发生在 `add()` 方法中,那么查看 `add()` 方法源码如下 : public boolean add(E e) { // ensureCapacityInternal() 如下 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } **继续深入:** // 1.第一次 add 时,参数 minCapacity = 1 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // 2.calculateCapacity() 方法 private static int calculateCapacity(Object[] elementData, int minCapacity) { // 如果是第一次 add 元素 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // minCapacity 设置为 DEFAULT_CAPACITY 与 minCapacity 的最大值 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } // 3.ensureExplicitCapacity() 方法 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } //4. grow()方法 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } //5.hugeCapacity()方法 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } **这里的意思就是:** 如果是第一次添加元素,就默认一个10大小的容量,然后通过比较集合的大小,决定是否要动态扩容,像第一次添加元素,就不需要扩容,newCapacity=10,然后调用Arrays.copyOf(elementData, newCapacity) 创建一个新的大小为10的数组。 ### 3.2总结 ### **初始容量:** * 如果使用 ArrayList的默认无参构造器时,它的**初始容量就是 0**。 * 如果使用 ArrayList的有参构造器时,它的初始容量就是你传入的参数 `initialCapacity`的值。 **add()添加元素:** * 如果是默认无参构造器创建的集合对象,在第一次添加元素时,会创建一个默认`10`大小的数组,然后进行添加元素。 * 如果是有参构造器,就会判断集合的大小跟容量,如果**集合大小>容量**,就会新建一个`1.5倍`大小的数据,进行元素拷贝。如果**集合大小<容量**,就继续添加元素,不进行扩容。 [img]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/31/b332f58a44ea4f9a8c3fa403161a8d67.png
还没有评论,来说两句吧...