zoukankan      html  css  js  c++  java
  • java语言基础5--集合学习,ArrayList和Linkedlist

    Collection<E>接口

      这个接口是集合框架最顶级的接口,该接口扩展了Iterable接口,这意味着所有的集合类fore-each风格进行遍历。

    ArrayList 与 Linkedlist

    区别:

      ArrayList是实现了基于动态数组,LinkedList基于链表。对于随机访问get和set,ArrayList性能要优于LinkedList,因为LinkedList要移动指针。对于删除和新增LinkedList性能要优于ArrayList,因为ArrayList要移动数据。 

    ArrayList的扩容方式,扩容时机

      当集合中的元素超出容量,便会进行扩容操作。扩容操作也是ArrayList 的一个性能消耗比较大的地方,所以若我们可以提前预知数据的规模,应该通过public ArrayList(int initialCapacity) {}构造方法,指定集合的大小,去构建ArrayList实例,以减少扩容次数,提高效率

    ArrayList的成员属性

    public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
        private static final long serialVersionUID = 8683452581122892189L;
        //默认初始容量
        private static final int DEFAULT_CAPACITY = 10;
        //默认构造函数的空数组
        private static final Object[] EMPTY_ELEMENTDATA = {};
        //瞬态(在采用Java默认的序列化机制的时候,被该关键字修饰的属性不会被序列化)的数组,真正存放元素的数组
        transient Object[] elementData; // non-private to simplify nested class access
        //elementData存放元素的数量,这里和容量不一样
        private int size;
    }

     ArrayList的构造方法

        public ArrayList(int initialCapacity) {
            super();//即父类protected AbstractList() {}
            if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
            this.elementData = new Object[initialCapacity];//创建一个容量为initialCapacity的空的(但是size==0)对象数组
        }
    
        public ArrayList() {
            super();
            this.elementData = EMPTY_ELEMENTDATA;//将空数组赋值给elementData
        }
    
        public ArrayList(Collection<? extends E> c) {
            //调用Collection.toArray()方法得到一个对象数组,并赋值给elementData
            elementData = c.toArray();
            //设置size的值
            size = elementData.length;
            //c.toArray()如果没有返回Object[]时,利用Arrays.copyOf 来复制集合c中的元素到elementData数组中
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        }

    add方法

        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;//将数组元素追加到末尾,并修改size
            return true;
        }
        
        private void ensureCapacityInternal(int minCapacity) {
            //根据EMPTY_ELEMENTDATA  判断数组是否是用默认构造函数初始化的,(这里不考虑ArrayList(Collection<? extends E> c)这种情况是因为,minCapacity是肯定大于c的size的)
            if (elementData == EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
        
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;///如果确定要扩容,会修改modCount 
            
            // 如果传入的数大于数组原容量 则开始扩容
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
        
        private void grow(int minCapacity) {
            //
            int oldCapacity = elementData.length;
            //扩容为原来的1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            //取1.5倍的容量和传入的扩容系数的最大值
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)//这里的 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
        //最大返回 Integer.MAX_VALUE
        private static int hugeCapacity(int minCapacity) {
            // overflow
            if (minCapacity < 0) throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
        }

    指定位置插入add(int index, E element)

        public void add(int index, E element) {
            rangeCheckForAdd(index);//范围检查
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            //将index开始的数据 向后移动一位
            System.arraycopy(elementData, index, elementData, index + 1,size - index);
            elementData[index] = element;
            size++;
        }
        
        private void rangeCheckForAdd(int index) {
            if (index > size || index < 0)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

    addAl方法

        public boolean addAll(Collection<? extends E> c) {
            Object[] a = c.toArray();
            int numNew = a.length;
            //扩容准备
            ensureCapacityInternal(size + numNew);  
            // 复制数组 ,并载入数据
            System.arraycopy(a, 0, elementData, size, numNew);
            size += numNew;
            return numNew != 0;
        }

    查询

        public E get(int index) {
            rangeCheck(index);//范围检查
    
            return elementData(index);//下标获取数据
        }    
    
        @SuppressWarnings("unchecked")
        E elementData(int index) {
            return (E) elementData[index];
        }

     Linkedlist

        transient int size = 0;//集合元素数量
    
        transient Node<E> first; //头部节点
    
        transient Node<E> last;//尾部节点

    构造方法

       public LinkedList() {}
    
        public LinkedList(Collection<? extends E> c) {
            this();
            addAll(c);//将集合c所有元素插入链表中
        }

    内部类 Node

      //双向链表
      private static class Node<E> {
            E item;//元素值
            Node<E> next;//前节点引用
            Node<E> prev; //后节点引用
    
            Node(Node<E> prev, E element, Node<E> next) {
                this.item = element;
                this.next = next;
                this.prev = prev;
            }
        }

    add方法

        //尾部插入新节点
        public boolean add(E e) {
            linkLast(e);
            return true;
        }
        
        void linkLast(E e) {
            final Node<E> l = last;//记录原来的尾部节点
            final Node<E> newNode = new Node<>(l, e, null);//以原尾部节点为前节点生成新节点
            last = newNode;//将当期节点设置为尾部节点
            if (l == null)//如果原尾部节点为null  则将当前节点设置为链表的首节点
                first = newNode;
            else//否则将当前节点设置为原尾部节点的后节点
                l.next = newNode;
            size++;
            modCount++;
        }

    其他例子就不看了,总得来说 LinkedList  修改数据时,只需要设置新节点和关联前后节点关系即可,不向ArrayList那样,增加一个数据。后面的数据都要后移。因此LinkedList 对数据操作效率高。

  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/tjqBlog/p/9822307.html
Copyright © 2011-2022 走看看