• List集合-01.ArrayList


    1.ArrayList

    1.1 实现了Access接口

    实现标记接口Access有以下特点

    • 目的是允许通用算法提供良好的性能
    • 当遍历方式不同,速度不同时,通常需要继承这个接口

    1.2 ArrayList 的迭代器

    1.2.1 Iterator

    • 继承Itrator接口
    private class Itr implements Iterator<E> 
    
    • hasNext()方法通过游标和数组长度进行比较判断
    public boolean hasNext() {
                return cursor != size;
            }
    
    • next()接口,获取游标所在位置的元素,游标向后移动一个位置;
     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];//设置lastRet为i,lastRet是锁定元素
            }
    
    • remove()方法,主要经过了以下几个步骤:
      • 删除当前位置lastRet锁定位置的值;(ArrayList的remove方法的删除,其实是将数组元素移动1个位置重新copy)
      • 删除后cursor = lastRet,也就意味着将游标指向 锁定元素的位置;
      • 将锁定元素设置为-1;
        从上面的步骤可以看出:
        1.当iterator没有移动使用next()方法,lastRet是-1,调用ArrayList的remove方法会报错;
        2.并且使用iterator逐个删除元素的时候,必须在remove之前用next()方法移动游标,将锁定元素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();
        }
    }
    
    ======ArrayList 的remove方法======
    public E remove(int index) {
            rangeCheck(index);
    
            modCount++;
            E oldValue = elementData(index);
    
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work
    
            return oldValue;
        }
    

    1.2.1 ListIterator

    • 1.继承Iterator实现类,并实现了ListIterator接口
      就是对iterator接口方法的扩充
     private class ListItr extends Itr implements ListIterator<E>
      ListItr(int index) {
                super();
                cursor = index;
            }
    
    • 2.previous方法 ,将游标cursor移动到前一个位置,并设置lastRet为当前的元素i;
         public E previous() {
                checkForComodification();
                int i = cursor - 1;
                if (i < 0)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i;
                return (E) elementData[lastRet = i];
            }
    
    • 3.set方法,根据lastRet的位置设置,不能在cursor为0时设置;add方法,是将ArrayList的元素从index+1拷贝重生成;
    public void set(E e) {
          if (lastRet < 0)
              throw new IllegalStateException();
          checkForComodification();
    
          try {
              ArrayList.this.set(lastRet, e);
          } catch (IndexOutOfBoundsException ex) {
              throw new ConcurrentModificationException();
          }
      }
    
      public void add(E e) {
          checkForComodification();
    
          try {
              int i = cursor;
              ArrayList.this.add(i, e);
              cursor = i + 1;
              lastRet = -1;
              expectedModCount = modCount;
          } catch (IndexOutOfBoundsException ex) {
              throw new ConcurrentModificationException();
          }
      }
    
    

    1.3 SubList子列表

    • 获取ArrayList的区间进行操作,可以使用ArrayList的所有操作
    pubList(AbstractList<E> parent,
                 int offset, int fromIndex, int toIndex) {
          this.parent = parent;
          this.parentOffset = fromIndex;
          this.offset = offset + fromIndex;
          this.size = toIndex - fromIndex;
          this.modCount = ArrayList.this.modCount;
      }
    
    

    1.4 ArrayListSpliterator

    1.ArrayList集合中获取

    初始的index 是0,fence是-1
    
       ======== ArrayList ==========
        @Override
        public Spliterator<E> spliterator() {
            return new ArrayListSpliterator<>(this, 0, -1, 0);
        }
        ===== ArrayListSpliterator 构造函数 ====
         ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                                 int expectedModCount) {
                this.list = list; // OK if null unless traversed
                this.index = origin;
                this.fence = fence;
                this.expectedModCount = expectedModCount;
            }
    
    

    2.进行分栏操作

      进行二分操作,返回的是以index为首,中间值mid为fence的新的ArrayListSpliterator
    
     //fence大小为 list的size
     public ArrayListSpliterator<E> trySplit() {
                int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid) ? null : // divide range in half unless too small
            new ArrayListSpliterator<E>(list, lo, index = mid,
                                        expectedModCount);
    }
    
    

    3.forEachRemaining

    就是将剩余的元素进行遍历

    if ((i = index) >= 0 && (index = hi) <= a.length) {
        for (; i < hi; ++i) {
            @SuppressWarnings("unchecked") E e = (E) a[i];
            action.accept(e);
        }
        if (lst.modCount == mc)
            return;
    }
    

    4.主要的作用是当大数据list进行遍历处理时,可以进行切分

    示例代码如下:
    在实际使用中,可以用多线程处理

    public class ArrayListTest {
    
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            list.add("zhangsan");
            list.add("wangwu");
            list.add("zhaoliu");
            list.add("job");
            list.add("tom");
            Spliterator<String> spliterator = list.spliterator();
            Spliterator<String> s1 = spliterator.trySplit();
            spliterator.forEachRemaining(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
            });
            s1.forEachRemaining(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
            });
        }
    
    }
    ==========  输出的结果 =============
    zhaoliu
    job
    tom
    zhangsan
    wangwu
    

    1.5 基本属性

    1.ArrayList元素存储及扩容

    • 默认为空数组,也可通过构造函数传参,确定初始容量大小
    • Object 数组存储元素
     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    public ArrayList() {
          this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
      }
    
    
    • Object数组进行扩容,首次add数据初始化最小为10
        private void ensureCapacityInternal(int minCapacity) {//传入最小的容量
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }
        private static final int DEFAULT_CAPACITY = 10;  
        private static int calculateCapacity(Object[] elementData, int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            }
            return minCapacity;
        }
         private void grow(int minCapacity) { //将object数组进行扩容
            // 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);
        }      
      
    

    总结一下:
    1.ArrayList,底层是通过Object对象数组存储对象,并不是通过泛型数组存储;
    2.默认初始化为空数组,首次初始化最小容量为10;
    3.提供了iterator,和listIterator两个子类,用于遍历使用;
    4.iterator遍历删除要先用next()移动游标,否则会报错;
    5.ListIterator的set方法使用,必须要进行游标移动;
    6.SubList是对ArrayList进行截取一部分进行操作;

  • 相关阅读:
    单元测试、集成测试、系统测试
    函数
    python中的math函数
    字符串和数据类型转换
    range()函数
    input()函数
    Linux如何通过命令查看日志文件的某几行(中间极几行或最后几行)
    【转】接口测试面试题
    【转】用Fiddler做抓包分析详解
    为什么要使用fiddler抓包?抓包用来干什么?
  • 原文地址:https://www.cnblogs.com/perferect/p/12945238.html
Copyright © 2020-2023  润新知