List集合

List集合的学习

  1. 特点:有序(存储顺序和取出顺序是一致的),可重复

    		List A = new ArrayList();
            A.add("a");
            A.add("b");
            A.add("c");
            A.add("d");
            A.add("d");
            for (int i = 0; i < A.size(); i++) {
                System.out.println(A.get(i));
            }
    
  2. 关于 迭代器 与Collection的区别

    1. 返回的是自己特有的 ListIterator extends Iterator
    2. 增强了 iterator 的方法,不止于 hasNext() next() remove()
    3. 列表有双向列表,所有增加了 pervious() hasPervious();
    4. add(),set() 可以添加、设置元素

List 集合常用子类

  1. List集合的常用子类 三个
    1. ArrayList
      • 底层的数据结构是数组。线程不安全的
    2. LinkedList
      • 底层结构是链表。线程不安全的
    3. Vector
      • 底层结构是数组。线程安全的

Set 集合常用的子类

  1. HashSet
    • 底层结构是哈希表(每一个元素为一个链表的数组)
  2. TreeSet
    • 底层结构是红黑树(是一个自平衡的二叉树)
    • 保证元素的排序方式
  3. LinkedHashSet
    • 底层结构是哈希表和链表

ArrayList

  1. 属性

    1. 初始化容量

      private static final int DEFAULT_CAPACITY = 10;
      
    2. 指定构造函数容量为0时返回的空数组

      private static final Object[] EMPTY_ELEMENTDATA = {};
      
    3. 用户不指定,默认返回的空数组,也就是空构造

      private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
      
    4. ArrayList的实际大小

      private int size;
      
    5. 底层数组:当第一次Add元素时,这个数组会扩容到初始化容量DEFAULT_CAPACITY

      transient Object[] elementData; // non-private to simplify nested class access
      
  2. 构造函数方面

    1. 如果用户指定了初始容量,那么就会构造处对应容量的对象数组,若初始化容量为0时,就返回的是 EMPTY_ELEMENTDATA
    2. 如果用户不指定初始容量(空构造),返回的是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  3. Add方法

    1. add(E e) 直接添加元素的

      1. 注意点

        1. 检查是否需要扩容
        2. 插入元素
      2. 底层步骤

        1. 检查容量是否需要扩容

        2. 容量足够,那么直接添加

        3. 容量不足,扩容 核心是根据 size 和 length 判断,个数-长度>0那么就需要扩容

          1. 扩容到原来的1.5倍
          2. 如果第一次扩容的容量,还是比minCapacity小,那么直接扩容到minCapacity
        4.  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);
              }
          
    2. add(int index, E e) 将元素插入到指定的位置

      1. 注意点

        1. 检查角标
        2. 检查是否需要扩容
        3. 插入元素
      2. 底层步骤

        1. 检查角标是否越界

          1. private void rangeCheckForAdd(int index) {
                    if (index > size || index < 0)
                        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
                }
            
          2. 如果插入位置,都已经超出了元素个数了,或者为负数,都是越界的情况

        2. 检查是否需要扩容

          1. 调用的就是 add 的扩容检查方法
        3. 调用

           System.arraycopy(elementData, index, elementData, index + 1,
                                   size - index);
          

          拷贝数组,其实本质就是所有的下表往后移了一位的处理

        4. 在指定位置赋值元素,size++

          1. elementData[index] = element;
                    size++;
            
    3. get(int index) 获取指定位置的元素

      1. 注意点

        1. 检查角标
        2. 返回元素
      2. 底层步骤

        1. 检查角标,调用的就是 add(index,e)的检查越界的方法

        2. 返回元素

          1. 不是直接底层数组[下标]

          2. 而是又包了一层,可能是做后期的扩展

            1. E elementData(int index) {
                      return (E) elementData[index];
                  }
              
            2. public E get(int index) {
                      rangeCheck(index);
              
                      return elementData(index);
                  }
              
    4. set(int index, E e) 设置指定位置的元素

      1. 注意点

        1. 检查角标
        2. 替代元素
        3. 返回旧值
      2. 底层实现步骤

        1. 检查角标,同add(index,e)

        2. 替代元素

          1. 让一个 变量等于 索引处的值

            E oldValue = elementData(index);
            
          2. 替换索引处的元素

            elementData[index] = element;
            
          3. 返回旧值

            return oldValue;
            
          4. 源码

            public E set(int index, E element) {
                    rangeCheck(index);
            
                    E oldValue = elementData(index);
                    elementData[index] = element;
                    return oldValue;
            }
            
    5. remove(int index) 删除指定位置的元素

      1. 注意点

        1. 检查角标
        2. 删除元素
        3. 计算出需要移动的个数并且移动
        4. 设置为 null,让GC回收
        5. 返回删除元素
      2. 底层实现

        1. 检查角标,同add(index, e)

        2. 删除元素

          1. 通过数组拷贝,index位置直接被下一个覆盖带掉
        3. 计算移动个数

          int numMoved = size - index - 1;
          
原文地址:https://www.cnblogs.com/JQ04/p/15092886.html