且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

ArrayList 分析以及相关方法介绍

更新时间:2022-08-14 19:29:12

ArrayList简介:

java.util.ArrayList 是我们最常用的一个类,ArrayList 底层是动态数组,读者可以把它理解为数组的实现

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

}

如上代码我们可以看到 ArrayList 继承了 AbstractList() 抽象类,并实现了 List, RandomAccess, Cloneable, Serializable 接口

AbstractList :

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>{}

可以看到AbstractList 继承了 AbstractCollection 接口, 并实现了List 接口

AbstractCollection :

public abstract class AbstractCollection<E> implements Collection<E>{}

AbstractCollection 是一个抽象类,实现了Collection 接口,并提供了某些方法的具体实现。

Collection:

Collection 是一个***接口,是很多集合类的***接口,继承了Iterable ,支持轻量级遍历其中元素

public interface Collection<E> extends Iterable<E>{}

List :

ArrayList 实现了List接口,List 也是一个和Collection 媲美的***接口,继承了Collection  接口

public interface List<E> extends Collection<E>{}

它是许多集合类的父类,

eg:

List list = new ArrayList();
List list2 = new LinkedList();

RandomAccess

RandomAccess 也是一个***接口,实现了此接口的类支持随机访问

Cloneable

Cloneable 接口是一个***接口,实现了此接口的类支持浅拷贝

Serializable

实现此接口的类支持序列化的功能

ArrayList 相关方法介绍

ArrayList 分析以及相关方法介绍

ArrayList 分析以及相关方法介绍

trimToSize()

ArrayList 分析以及相关方法介绍


代码表示

实践才是检验真理***的方式:

importjava.util.*;

/**
* 详述ArrayList 基本用法
*/
public class ArrayListTest{

   private static class SortList implements Comparator<String>{

       @Override
       public int compare(String o1, String o2) {
           Integeri1=Integer.valueOf(o1);
           Integeri2=Integer.valueOf(o2);
           if(i1<i2){
               return-1;
          }elseif(i1==i2){
               return0;
          }
           return1;
      }
  }

   // 使用可变参数,能够接受任意个参数
   public Set<String> putSet(String...args){
       Set<String> sets = new HashSet<>();
       for(String str: args){
           sets.add(str);
      }
       return sets;
  }

   public static void main(String[] args) {
       ArrayList<String> list = new ArrayList<>();
       list.add("111");
       list.add("222");

       // 在指定位置添加元素
       list.add(0,"333");
       System.out.println(list);

       // 进行外部排序
       list.sort(newSortList());
       System.out.println(list);

       list.clear();
       System.out.println(list.size());

       // 使用addAll添加元素
       ArrayList Testat = newArrayListTest();
       list.addAll(at.putSet("1","2","3"));

       Iterator<String> it = list.iterator();
       while(it.hasNext()){
           System.out.println(it.next());
           // 移除所有元素
           it.remove();
      }

       System.out.println("list是否为空 ? "+list.isEmpty());

       list.add("111");
       // 在指定位置添加一个set集合
       list.addAll(0,at.putSet("1","2","3"));
       System.out.println(list);

       // 是否包含指定元素
       if(list.contains("111")) {
           list.remove("111");
      }
       System.out.println(list);

       System.out.println(list.indexOf("1"));
       // 注意subList()这个方法是左开右闭区间,Java 中很多都是类似的
       System.out.println(list.subList(0,3));

       // 扩大list的容量
       list.ensureCapacity(10);
       // 去掉list空闲的容量
       list.trimToSize();

       // 获取某个特定的元素
       System.out.println(list.get(1));

       // 创建一个list的双向链表
       ListIterator<String> listIterator = list.listIterator();
       while(listIterator.hasNext()){
           // 移到list的末端
           System.out.println(listIterator.next());
      }
       System.out.println("--------------------------");
       while(listIterator.hasPrevious()){
           // 移到list的首端
           System.out.println(listIterator.previous());
      }

       // 把list转换为数组
       Object[] objects = list.toArray();
       System.out.println("objects = "+objects);

  }
}


相关方法源码分析

分析源码还是要有代码的实例,跟进去理解每一行的意思,俗话说,有debug,不求人!

add()方法

/**
    * Appends the specified element to the end of this list.
    * 添加指定的元素在list的末尾
    * @param e element to be appended to this list
    * @return <tt>true</tt> (as specified by {@link Collection#add})
    */

// 假设第一次添加的是 "111"
   public boolean add(E e) {
       // size是0,所以size + 1 传的是1
       ensureCapacityInternal(size+1);  // Increments modCount!!
       // elementData[0] = 111 , size++ = 1
       elementData[size++] =e;
       returntrue;
  }

// 此方法用来进行list 扩容
private void ensureCapacityInternal(int minCapacity) {
       // 此时elementData 并没有存储元素,为0
       if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
           // 则minCapacity 取默认初始容量和minCapacity 的最大值 (取1 和 10的最大值)
           minCapacity=Math.max(DEFAULT_CAPACITY, minCapacity);
      }
       // 确保清晰的容量(最小容量与List元素的比较)
       ensureExplicitCapacity(minCapacity);
  }

// 在list中添加了一个元素,所以会导致结构化的修改,"结构化的修改"见下面解释
// 此时minCapacity 为 10
private void ensureExplicitCapacity(int minCapacity) {
       // 次数 + 1 
       // 这个列表被修改结构的次数(比如添加和删除元素)会用modCount表示. 结构化修改是指的是能够
       // 改变列表容量的操作,或者其他方式改变它,导致遍历的过程会产生错误的结果。
       modCount++;

       // overflow-conscious code
       // 10 - 0 > 0 走grow 方法
       if(minCapacity-elementData.length>0)
           grow(minCapacity);
  }

/**
    * Increases the capacity to ensure that it can hold at least the
    * number of elements specified by the minimum capacity argument.
    * 增加容量确保容纳足够的元素
    *
    * @param minCapacity the desired minimum capacity
    * 参数传过来的是10
    */
   private void grow(int minCapacity) {
       // overflow-conscious code
       // oldCapacity = 0
       intoldCapacity=elementData.length;
// newCapacity = 0
       intnewCapacity=oldCapacity+(oldCapacity>>1);
  // newCapacity - minCapacity = -10
       if(newCapacity-minCapacity<0)
           // newCapacity = 10
           newCapacity=minCapacity;
       
       // MAX_ARRAY_SIZE = 数组分配的最大空间 = 2147483639
       // 一般情况下不会比 MAX_ARRAY_SIZE 还要大
       if(newCapacity-MAX_ARRAY_SIZE>0)
           newCapacity=hugeCapacity(minCapacity);
       // minCapacity is usually close to size, so this is a win:
       // 底层还是用的System.arraycopy(), 关于System.arrayCopy() 读者可以参考我的另一篇博客
       elementData=Arrays.copyOf(elementData, newCapacity);
  }

输出:

[333, 111, 222]

[111, 222, 333]

0

1

2

3

list是否为空 ? true

[1, 2, 3, 111]

[1, 2, 3]

0

[1, 2, 3]

2

1

2

3

--------------------------

3

2

1

objects = [Ljava.lang.Object;@6e8cf4c6

相关常用的基本数据类型包装类的值: Java基本数据类型包装类常用的值

add(int index, E element)


/**
    * Inserts the specified element at the specified position in this
    * list. Shifts the element currently at that position (if any) and
    * any subsequent elements to the right (adds one to their indices).
    * 在list中指定位置插入指定的元素,如果当前位置有元素,就移动当前位置的元素
    * 要插入的位置的后面所有元素的位置向前 + 1
    *
    * @param index index at which the specified element is to be inserted
    * @param element element to be inserted
    * @throws IndexOutOfBoundsException {@inheritDoc}
    */
   public void add(int index, E element) {
       // 检查 0 这个位置是否越界
       rangeCheckForAdd(index);

       // 不再赘述,读者可以自行debug
       ensureCapacityInternal(size+1);  // Increments modCount!!
       // 因为从当前位置插入元素,所以当前位置及后面的元素都会向后移动
       // 使用System.arraycopy 进行数组复制
       System.arraycopy(elementData, index, elementData, index+1,
                        size-index);
       // 为当前元素赋值
       elementData[index] =element;
       size++;
  }

/**
    * A version of rangeCheck used by add and addAll.
    * 为add 和 addall 提供的范围检查, 不符合条件,抛出IndexOutOfBoundsException 异常
    *
    */
   private void rangeCheckForAdd(intindex) {
       if(index>size||index<0)
           thrownewIndexOutOfBoundsException(outOfBoundsMsg(index));
  }