2019独角兽企业重金招聘Python工程师标准>>>

List概括

List 是一个接口,它继承于Collection的接口。它代表着有序的队列。

AbstractList 是一个抽象类,它继承于AbstractCollection。AbstractList实现List接口中除size()、get(int location)之外的函数。

ArrayList, LinkedList, Vector, Stack是List的4个实现类。

ArrayList 是一个数组队列,相当于动态数组。它由数组实现,随机访问效率高,随机插入、随机删除效率低。

LinkedList 是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。LinkedList随机访问效率低,但随机插入、随机删除效率低。

Vector 是矢量队列,和ArrayList一样,它也是一个动态数组,由数组实现。但是ArrayList是非线程安全的,而Vector是线程安全的。

Stack 是栈,它继承于Vector。它的特性是:先进后出(FILO, First In Last Out)。

List使用场景

  • 需要快速插入,删除元素,应该使用LinkedList。
  • 需要快速随机访问元素,应该使用ArrayList。
  • 对于“单线程环境” 或者 “多线程环境,但List仅仅只会被单个线程操作”,此时应该使用非同步的类(如ArrayList)。
  • 对于“多线程环境,且List可能同时被多个线程操作”,此时,应该使用同步的类(如Vector)。
import java.util.*;
import java.lang.Class;/** @desc 对比ArrayList和LinkedList的插入、随机读取效率、删除的效率** @author skywang*/
public class ListCompareTest {private static final int COUNT = 100000;private static LinkedList linkedList = new LinkedList();private static ArrayList arrayList = new ArrayList();private static Vector vector = new Vector();private static Stack stack = new Stack();public static void main(String[] args) {// 换行符System.out.println();// 插入insertByPosition(stack) ;insertByPosition(vector) ;insertByPosition(linkedList) ;insertByPosition(arrayList) ;// 换行符System.out.println();// 随机读取readByPosition(stack);readByPosition(vector);readByPosition(linkedList);readByPosition(arrayList);// 换行符System.out.println();// 删除 deleteByPosition(stack);deleteByPosition(vector);deleteByPosition(linkedList);deleteByPosition(arrayList);}// 获取list的名称private static String getListName(List list) {if (list instanceof LinkedList) {return "LinkedList";} else if (list instanceof ArrayList) {return "ArrayList";} else if (list instanceof Stack) {return "Stack";} else if (list instanceof Vector) {return "Vector";} else {return "List";}}// 向list的指定位置插入COUNT个元素,并统计时间private static void insertByPosition(List list) {long startTime = System.currentTimeMillis();// 向list的位置0插入COUNT个数for (int i=0; i<COUNT; i++)list.add(0, i);long endTime = System.currentTimeMillis();long interval = endTime - startTime;System.out.println(getListName(list) + " : insert "+COUNT+" elements into the 1st position use time:" + interval+" ms");}// 从list的指定位置删除COUNT个元素,并统计时间private static void deleteByPosition(List list) {long startTime = System.currentTimeMillis();// 删除list第一个位置元素for (int i=0; i<COUNT; i++)list.remove(0);long endTime = System.currentTimeMillis();long interval = endTime - startTime;System.out.println(getListName(list) + " : delete "+COUNT+" elements from the 1st position use time:" + interval+" ms");}// 根据position,不断从list中读取元素,并统计时间private static void readByPosition(List list) {long startTime = System.currentTimeMillis();// 读取list元素for (int i=0; i<COUNT; i++)list.get(i);long endTime = System.currentTimeMillis();long interval = endTime - startTime;System.out.println(getListName(list) + " : read "+COUNT+" elements by position use time:" + interval+" ms");}
}

输出结果

Stack : insert 100000 elements into the 1st position use time:1640 ms
Vector : insert 100000 elements into the 1st position use time:1607 ms
LinkedList : insert 100000 elements into the 1st position use time:29 ms
ArrayList : insert 100000 elements into the 1st position use time:1617 msStack : read 100000 elements by position use time:9 ms
Vector : read 100000 elements by position use time:6 ms
LinkedList : read 100000 elements by position use time:10809 ms
ArrayList : read 100000 elements by position use time:5 msStack : delete 100000 elements from the 1st position use time:1916 ms
Vector : delete 100000 elements from the 1st position use time:1910 ms
LinkedList : delete 100000 elements from the 1st position use time:15 ms
ArrayList : delete 100000 elements from the 1st position use time:1909 ms

插入10万个元素,LinkedList所花时间最短:29ms。

删除10万个元素,LinkedList所花时间最短:15ms。

遍历10万个元素,LinkedList所花时间最长:10809 ms;而ArrayList、Stack和Vector则相差不多,都只用了几秒。

LinkedList和ArrayList性能差异分析

LinkedList向指定位置插入元素的代码如下:

public void add(int index, E element) {//检查是否越界checkPositionIndex(index);if (index == size)//向最末尾添加元素linkLast(element);else//向指定位置添加元素linkBefore(element, node(index));}
//检查元素是否越界
private boolean isPositionIndex(int index) {return index >= 0 && index <= size;}
private void checkPositionIndex(int index) {if (!isPositionIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}
//向末尾添加元素
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;elsel.next = newNode;size++;modCount++;}
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;}}
void linkBefore(E e, Node<E> succ) {// assert succ != null;final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;}
Node<E> node(int index) {// assert isElementIndex(index);//index < 双向链表长度的1/2,则从前向后查找; 否则,从后向前查找。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;}}

通过add(int index, E element)向LinkedList插入元素时。先是在双向链表中找到要插入节点的位置index;找到之后,再插入一个新节点。 双向链表查找index位置的节点时,有一个加速动作:若index < 双向链表长度的1/2,则从前向后查找; 否则,从后向前查找。

我们看看ArrayList中向指定位置插入元素的代码

    private static final int DEFAULT_CAPACITY = 10;public ArrayList() {super();this.elementData = EMPTY_ELEMENTDATA;}public void add(int index, E element) {//用于检查是否越界rangeCheckForAdd(index);//修改次数加一ensureCapacityInternal(size + 1);  // Increments modCount!!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));}private void ensureCapacityInternal(int minCapacity) {if (elementData == EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}//数组扩容private void grow(int minCapacity) {// overflow-conscious codeint 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);}

ensureCapacity(size+1) 的作用是“确认ArrayList的容量,若容量不够,则增加容量。” 真正耗时的操作是 System.arraycopy(elementData, index, elementData, index + 1, size - index);

System.arraycopy(arr,0,copied,1,5);//这里的arr是原数组,0是原数组拷贝的起始地址。而copied是目标数组,1是目标数组开始存放的位置,5则是数组存放的长度。

LinkedList中随机访问很慢,ArrayList中随机访问很快

LinkedList随机访问代码

    public E get(int index) {checkElementIndex(index);return node(index).item;}private void checkElementIndex(int index) {if (!isElementIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}private boolean isElementIndex(int index) {return index >= 0 && index < size;}//对元素进行二分遍历一遍,如果列表很长的时候效率将会非常低下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;}}

先是在双向链表中找到要index位置的元素;找到之后再返回。双向链表查找index位置的节点时,有一个加速动作:若index < 双向链表长度的1/2,则从前向后查找; 否则,从后向前查找。

ArrayList随机访问的代码

    public E get(int index) {rangeCheck(index);return elementData(index);}private void rangeCheck(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}//直接访问数组中的位置E elementData(int index) {return (E) elementData[index];}

转载于:https://my.oschina.net/jiansin/blog/2050217

Java 集合系列-第七篇-List总结相关推荐

  1. java集合系列——java集合概述(一)

    在JDK中集合是很重要的,学习java那么一定要好好的去了解一下集合的源码以及一些集合实现的思想! 一:集合的UML类图(网上下载的图片) Java集合工具包位置是java.util.* 二:集合工具 ...

  2. Java 集合系列(一)

    Java集合系列文章将以思维导图为主要形式来展示知识点,让零碎的知识形成体系. 这篇文章主要介绍的是[Java 集合的基本知识],即Java 集合简介. 毕业出来一直使用 PHP 进行开发,对于大学所 ...

  3. 明翰Java教学系列之多线程篇V0.2(持续更新)

    文章目录 传送门 前言 背景知识 并行与并发 线程与进程 内存模型 1. 计算机内存模型 `2. Java内存模型` 2.1 内存交互 2.1.1 交互操作 2.1.2 交互规则 `2.2 并发编程特 ...

  4. Java 集合系列02之 Collection架构

    概要 首先,我们对Collection进行说明.下面先看看Collection的一些框架类的关系图: Java 集合系列02之 Collection架构 Collection是一个接口,它主要的两个分 ...

  5. Java 集合系列06: Vector深入解析

    戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 概论 这是接着以前的文章分享的,这里给出以前的文章的连接,供小伙伴们回顾 ...

  6. 深入Java集合系列之五:PriorityQueue

    转载自  深入Java集合系列之五:PriorityQueue 前言 今天继续来分析一下PriorityQueue的源码实现,实际上在Java集合框架中,还有ArrayDeque(一种双端队列),这里 ...

  7. Java 集合系列04之 fail-fast总结

    转载自   Java 集合系列04之 fail-fast总结 概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内 ...

  8. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例

    转载自  Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例 第1部分 ArrayList介绍 ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与 ...

  9. Java 集合系列目录(Category)

    Java 集合系列目录(Category) 转自:Java 集合系列目录(Category) 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 0 ...

  10. Java集合系列之四大常用集合(ArrayList、LinkedList、HashSet、HashMap)的用法

    Java集合系列之四大常用集合(ArrayList.LinkedList.HashSet.HashMap)的用法 ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是A ...

最新文章

  1. 人脸识别损失函数综述(附开源地址)
  2. jquery 绑定动态元素
  3. PowerBI随笔(2)-分组依据进行分组汇总
  4. 一个WCF RESTSOAP Post例子
  5. mount 网络_mount系统调用(ksys_mount-gt;do_mount-gt;do_new_mount)
  6. JavaScript的10种跨域共享的方法
  7. Spring 4 MVC入门实例
  8. 爱站CMS综合管理系统源码php版
  9. 从文件中读取一个long型数_Python 从文件中读取数据
  10. python爬虫教程-Python教父|廖雪峰老师官方爬虫教程,13个案例带你全面入门!
  11. 顺无盘linux win10包,(2017.01.14)网维大师9.0.3.0无盘-xp-win7x32-x64-Win10x64公包
  12. 单片机c语言必背代码_stm32单片机编程用库函数好还是寄存器好?
  13. idea2021.3.2版本下载及安装教程
  14. YARN工作流程详解
  15. Java程序语言(基础篇)第2章 基本程序设计 编程练习题解答
  16. Notepad++ 7.6版本 安装hexeditor最新详细版本(小白版)
  17. 多线程并发篇(1024节日快乐)
  18. ORM的1+N查询问题及解决办法
  19. 2020数学建模美赛C题完整解答(结合代码)
  20. mpvue返回上一个页面_小程序返回上一页 - 芊芊一隅

热门文章

  1. 正斜杠“/”与反斜杠”\”
  2. 为Android GridView 设置行背景
  3. 谷歌中文为什么以红色高亮关键字
  4. 基于axis2的webservice和android简单的本地数据交互(下)
  5. 图片切换,带标题文字
  6. [转]c# winform tcp connect timeout 连接超时设置
  7. 292. Nim游戏
  8. 使用migration创建表时,出错的解决方法
  9. 【小聪明】图片消失在另一张图片里
  10. StringBuffer、StringBuilder、冒泡与选择排序、二分查找、基本数据类型包装类_DAY13...