ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

18_Java集合ArrayList

2022-06-08 00:34:34  阅读:167  来源: 互联网

标签:elementData Java int 18 ArrayList 元素 minCapacity public


ArrayList 集合可以理解为 存储引用类型元素 的数据容器,元素类型不限,但可以通过 指定类型参数 限制可以存储的数据类型。

常用方法

  • 增添元素
// 在末尾添加元素
public boolean add(E e)
// 在指定位置插入元素
public void add(int index, E element)
  • 删除元素
// 删除指定元素,只删除第一个相同的元素
public boolean remove(Object o)
// 删除指定索引的元素
public E remove(int index)
// 删除所有元素
public void clear()
  • 修改元素
// 修改指定索引的元素
public E set(int index, E e)
  • 查找元素
// 顺序查找,返回元素索引位置
public int indexOf(Object o)
// 倒序查找,返回元素索引位置
public int lastIndexOf(Object o)
// 是否包含指定元素
public boolean contains(Object o)
  • 访问元素
// 访问指定索引处的元素
public E get(int index)
  • 获取元素个数
// 获取容器中的元素个数
public int size()

基本原理

transient Object[] elementData;  // 存放元素
private int size; // 记录存放的元素个数

protected transient int modCount = 0; // 父类 AbstractList 中,记录修改次数

ArrayList 是基于数组实现的,Object 数组 elementData 存放元素,变量 size 记录实际存放的元素个数,modCount 记录修改次数,每次发生结构性变化的时候 modCount 都会增加。

  • add 方法
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

public boolean add(E e) {
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  elementData[size++] = e;
  return true;
}

private void ensureCapacityInternal(int minCapacity) {
  ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    return Math.max(DEFAULT_CAPACITY, minCapacity);
  }
  return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
  modCount++; // modCount 表示内部的修改次数
  
  // overflow-conscious code
  if (minCapacity - elementData.length > 0)
    grow(minCapacity);
}

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);
}

private static int hugeCapacity(int minCapacity) {
  if (minCapacity < 0) // overflow
    throw new OutOfMemoryError();
  return (minCapacity > MAX_ARRAY_SIZE) ?
    Integer.MAX_VALUE :
  MAX_ARRAY_SIZE;
}

迭代遍历

  • 普通循环遍历

可以使用 while、for 循环对 ArrayList 集合进行遍历。

  • foreach 迭代遍历
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
for (Integer ele: arrayList) {
  System.out.println(ele);
}

编译器会对 foreach 语法进行转换。

while(arrayList.hasNext()){
  System.out.println(arrayList.next());
}

ArrayList 实现了 Iterable 接口,Iterable 表示可迭代,只要实现了 Iterable 接口,就可以使用 foreach 语法。

public interface Iterable<T> {
    Iterator<T> iterator();
}

iterator 方法返回一个实现了 Iterator 接口的对象。

public interface Iterator<E> {
    boolean hasNext(); // 判断是否还有元素可访问
  
    E next(); // 返回下一个元素
  
    default void remove() { // 删除最后返回的元素
        throw new UnsupportedOperationException("remove");
    }
}

来看 ArrayList 中的 iterator:

public Iterator<E> iterator() {
  return new Itr();
}
// Itr 是内部类
private class Itr implements Iterator<E> {
  int cursor;       // index of next element to return
  int lastRet = -1; // index of last element returned; -1 if no such
  int expectedModCount = modCount; // 每次发生结构性变化的时候 modCount 都会增加

  Itr() {}

  public boolean hasNext() {
    return cursor != size;
  }

  @SuppressWarnings("unchecked")
  public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
      throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
      throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
  }

  public void remove() {
    if (lastRet < 0)
      throw new IllegalStateException();
    checkForComodification();

    try {
      ArrayList.this.remove(lastRet);
      cursor = lastRet;
      lastRet = -1;
      expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
      throw new ConcurrentModificationException();
    }
  }

  final void checkForComodification() {
    if (modCount != expectedModCount)
      throw new ConcurrentModificationException();
  }
}

注意迭代中的删除:

/**
 * foreach 遍历时不能直接调用 remove 方法进行删除
 * 因为 foreach 实际是调用 Iterator 的方法,迭代器遍历时会维护索引位置相关的数据
 * 直接 remove 会导致结构变化,导致索引数据失效
 */
for (Integer ele: arrayList) {
  if(ele == 2) arrayList.remove(ele); // 执行报错
  System.out.println(ele);
}

使用迭代器删除:

Iterator<Integer> it = arrayList.iterator();
while (it.hasNext()){
  if(it.next() == 2) it.remove();
}

实现接口

  • Collection

Collection 表示一个数据集合,数据没有位置或顺序的概念。

  • List

List 表示有顺序或位置的数据集合,主要方法都与位置有关。

  • RandomAccess

标记接口,RandomAccess 表示可以随机访问,数据在内存是连续存放的,根据索引值可以直接定位到具体的元素,访问效率很高。

主要特点

  • 只能存放引用类型数据
  • 底层结构是数组,增删慢,查询相对较快,数据在内存连续存放,可以根据索引随机快速访问
  • 线程不安全

标签:elementData,Java,int,18,ArrayList,元素,minCapacity,public
来源: https://www.cnblogs.com/knhap/p/16353963.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有