标签:定位 修改 次数 span 判断 数据操作 设置 index 提高
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语言基础--集合学习,ArrayList和Linkedlist
标签:定位 修改 次数 span 判断 数据操作 设置 index 提高
原文地址:https://www.cnblogs.com/tjqBlog/p/9822307.html