List 是有序、可重复的容器。List中每个元素都有索引标记,可以根据元素的索引标记访问元素,从而精确控制这些元素。

List 接口常用的实现类:ArrayList、LinkedList、Vector。

一、ArrayList

ArrayList 底层是用数组实现。特点:查询效率高,增删效率低,线程不安全。增删操作较多的场景使用LinkedList,线程安全使用Vector 或者封装的线程安全集合类。

1、ArrayList

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable

ArrayList 通过动态数组实现,且实现了所有可选列表操作,允许包括null在内的所有元素。除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。

2、源码解析

ArrayList 由动态对象数组实现,默认构造方法创建一个空数组。第一次添加元素时,容量扩充为10,之后的扩充算法是原容量1.5倍。

(1) 添加方法

  /**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

(2) 扩容方法

    private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}
 /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}

(3) 删除方法

    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;
}
    public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}

3 ArrayList的特点

3.1 动态数组不适合做删除、插入操作。

3.2 为了防止数组动态扩充过多,建议创建时给定初始容量。

3.3 多线程不安全,适合在单线程使用。

3.4 建议存储同类型的对象。

4 ArrayList 扩展方法

addAll(Collection c)

removeAll(Collection c)

retainAll(Collection c)

containsALll(Collection c)

indexOf(Object o)

lastIndexOf(Object o)

二、LinkedList

1 LinkedList

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable

实现原理,通过双向链表实现的。适合插入、删除操作。

2 节点

LinkedList使用双向链表实现,而双向链表通过节点来实现,我们来看看节点的定义。

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;
}
}

3 元素操作

LinkedList默认大小为0,没有扩容机制,每增加一个元素,容量加1。

(1) 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)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}

(2) remove

    public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
    E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev; if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
} if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
} x.item = null;
size--;
modCount++;
return element;
}

(3) get

    public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
    Node<E> node(int index) {
// assert isElementIndex(index); if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}

4、其他方法

getFirst()

getLast()

addFirst()

addLast()

removeFirst()

removeLast()

三、ArrayList与LinkedList 区别

1、线程安全

ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;

2、底层数据结构

Arraylist 底层使用的是Object动态数组;LinkedList 底层使用的是双向链表数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)

3、插入和删除是否受元素位置的影响

(1) ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。

(2) LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。

4、是否支持快速随机访问

LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。

5、内存空间占用

ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。

2 ArrayList 详解的更多相关文章

  1. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  2. ArrayList详解-源码分析

    ArrayList详解-源码分析 1. 概述 在平时的开发中,用到最多的集合应该就是ArrayList了,本篇文章将结合源代码来学习ArrayList. ArrayList是基于数组实现的集合列表 支 ...

  3. java集合类之ArrayList详解

    一.ArrayList源码分析 1.全局变量 (1)默认容量(主要是通过无参构造函数创建ArrayList时第一次add执行扩容操作时指定的elementData的数组容量为10) private s ...

  4. Java.util.ArrayList详解

    java.util.ArrayList就是传说中的动态数组. 继承了关系,有此可看出ArrayList与list的collection的关系 public class ArrayList<E&g ...

  5. 【Java集合类】ArrayList详解 (JDK7)

    相信对于使用过Java的人来说,ArrayList这个类大家一定不会陌生. 数据结构课上讲过, Array是数组,它能根据下标直接找到相应的地址,所以索引速度很快,但是唯一的缺点是不能动态改变数组的长 ...

  6. ArrayList详解

    一.ArrayList类介绍:(这里给出jdk1.8源码上中文翻译) ArrayList是List接口以可变数组方式实现的,实现了所有的lis接口中的操作,并容许有null等所有元素.除了实现了Lis ...

  7. Java ArrayList 详解

    只记录目前为止关注的.JDK1.8 一.基础属性 1.1 内部参数 //空存储实例.直接new ArrayList()便是以该空数组作为实例 private static final Object[] ...

  8. Java 8 ArrayList 详解

    GitHub Page: http://blog.cloudli.top/posts/Java-ArrayList/ ArrayList 继承于 AbstractList ,实现了 List.Rand ...

  9. ArrayList详解,底层是数组,实现Serializable接口

    一.对于ArrayList需要掌握的七点内容 ArrayList的创建:即构造器往ArrayList中添加对象:即add(E)方法获取ArrayList中的单个对象:即get(int index)方法 ...

随机推荐

  1. JS 编程艺术

    JS艺术片段剪贴 getFullDate: function (date) { //返回 YYYY年MM月DD日 var year = month = day = ' '; if (isNaN(dat ...

  2. web储存的初级运用

    <html> <head> <meta charset="utf-8"> <title>web存储</title>< ...

  3. Asp .Net Core 2.0 登录授权以及前后台多用户登录

    用户登录是一个非常常见的应用场景 .net core 2.0 的登录方式发生了点变化,应该是属于是良性的变化,变得更方便,更容易扩展. 配置 打开项目中的Startup.cs文件,找到Configur ...

  4. Golang之初探

    什么是Go语言 Go语言介绍 产生背景: 超级复杂的C++11特性的吹捧报告的鄙视以及最终的目标是具备动态语言的开发速度的同时并要有C/C++编译语言的性能与安全性以及设计网络和多核时代的C语言 Go ...

  5. Vim技巧----选取一个单词

    viw 它的作用是选取一个单词(word),无论光标在这个单词的哪个位置都能选中整个单词. 每日一Vim(18)Text-Object 前两节讲了Visual mode相关内容,这里提一个小问题,“如 ...

  6. Java工程师面试题集锦

    即将踏上找工作的征途,参考网上面试题库准备一波面试题,希望能找到理想中的工作,愿一切顺利. 一.Java基础 1.String类为什么是final的. 2.HashMap的源码,实现原理,底层结构. ...

  7. 06—mybatis缓存机制

    MyBatis缓存分为一级缓存和二级缓存 一级缓存MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何 ...

  8. Eclipse中给jar包导入JavaDoc注释文档的方法

    原文链接:http://www.apkbus.com/android-124056-1-1.html 第一步:将jar加入到Referenced Libraries 右键点击jar --> 选择 ...

  9. django nginx uwsgi 502 Gateway

    前提:腾讯云服务器有个内网ip和外网ip 首先检查使用的端口是否正常可用 1.检查端口是否开放,在腾讯云控制台安全组查看 2.检查防火墙端口是否开放 systemctl start firewalld ...

  10. 洛谷P1363 幻想迷宫【dfs】

    题目:https://www.luogu.org/problemnew/show/P1363 题意: 有一个地图,起点是S,障碍物用#表示.可以将这个地图不断的在四周重复,问从起点开始是否可以走到无限 ...