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 对数据操作效率高。

  • 相关阅读:
    分解让复杂问题简单化:字符串的排列
    分解让复杂问题简单化:二叉搜索树与双向链表
    分解让复杂问题简单化:复杂链表的复制
    举例让抽象问题具体化:二叉树中和为某一值的路径
    举例让抽象问题具体化:二叉搜索树的后序遍历序列
    Java Collection Framework
    Spring Boot 项目部署到本地Tomcat,出现访问路径问题
    happens-before规则
    NoClassDefFoundError
    《Java编程思想》笔记 第十六章 数组
  • 原文地址:https://www.cnblogs.com/tjqBlog/p/9822307.html
Copyright © 2011-2022 走看看