集合类---List
一、ArrayList详解
1.继承关系
- public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
2.属性
- //默认的数组长度
- private static final int DEFAULT_CAPACITY = 10;
- //存储list中元素的数组,transient关键字表示该对象在ArrayList序列化时不被序列化。
- transient Object[] elementData;
- //数组中实际元素的个数
- private int size;
- //数组的最大长度
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
3.构造方法:
ArrayList的构造函数总共有三个:
1)add()添加元素:
- public boolean add(E e) {
- ensureCapacityInternal(size + 1); // size为element数组的实际大小,若size+1<elementData.length,则不用动态扩容,否则需要将elementData进行动态扩容。
- elementData[size++] = e;
- return true;
- }
- private void ensureCapacityInternal(int minCapacity) {
- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
- minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
- }
- ensureExplicitCapacity(minCapacity);
- }
- private void ensureExplicitCapacity(int minCapacity) {
- modCount++;
- if (minCapacity - elementData.length > 0)
- grow(minCapacity);
- }
- //grow:elementData数组扩容
- private void grow(int minCapacity) {
- int oldCapacity = elementData.length;
- //每次增长newCapacity=oldCapacity*1.5,为原来的1.5倍
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- //如果oldCapacity*1.5倍后,容量还是比minCapacity要小,则将newCapacity的值直接置为minCapacity
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- //如果增长的新长度大于了MAX_ARRAY_SIZE,则调用hugeCapacity来获取一个不大于Integer.MAX_VALUE的值。
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- //重新申请一个newCapacity长度的数组空间,并把elementData数组中内容拷贝过去。
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
- //hugeCapacity: elementData的最大容量
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- //当最小保证的容量minCapacity比MAX_ARRAY_SIZE还大时,返回Integer.MAX_VALUE;否则直接返回MAX_ARRAY_SIZE
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
2)add()在指定位置添加元素:
- public void add(int index, E element) {
- rangeCheckForAdd(index);
- ensureCapacityInternal(size + 1); // 确保数组的长度>=size+1
- //将elementData中index到数组最后一个元素,整体向后移动一个位置,空出index这一个位置,将element填入
- System.arraycopy(elementData, index, elementData, index + 1, size - index);
- elementData[index] = element;
- size++;
- }
3)addAll():
ArrayList内部是以数组的形式实现的,直接数组后面加数组,并增长数组长度。
- public boolean addAll(int index, Collection<? extends E> c) {
- rangeCheckForAdd(index);
- Object[] a = c.toArray();
- int numNew = a.length;
- //确保数组能容下添加的所有元素,可能进行动态扩容
- ensureCapacityInternal(size + numNew);
- //计算从Index到处数组最后一个元素需要移动的元素的个数
- int numMoved = size - index;
- if (numMoved > 0)
- //直接采用System.arraycopy将elementData数组中从index开始到最后一个元素位置这一段数据,移动到index+numNew位置
- System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
- //若index等于size,则直接在原数组后面添加
- System.arraycopy(a, 0, elementData, index, numNew);
- size += numNew;
- return numNew != 0;
- }
addAll()是调用System.arraycopy()函数来进行添加list集的,以复制的方式进行。System.arraycopy()源码如下:
- /*
- * 源数组,也就是要x.addAll(y)中的y
- * @param src the source array.
- * 源数组开始复制的位置,也就是y从第几位开始添加进x
- * @param srcPos starting position in the source array.
- * 目的数组,也就是x
- * @param dest the destination array.
- * 从目的数组的哪个位置开始添加,也就是从x的第几位开始添加进y
- * @param destPos starting position in the destination data.
- * 要复制的数组长度,也就是y要添加进x的数据个数
- * @param length the number of array elements to be copied.
- */
- public static native void arraycopy(Object src, int srcPos,
- Object dest, int destPos,
- int length);
从上面可以看出,x.addAll(y)函数是在x集合的基础上再其里面加入y集合,而不是用y将x进行覆盖。
数组copy方法效率比较:
System.arraycopy > clone > Arrays.copyOf > for循环
4)remove一个区间的数值:
- //是一个前闭后开的区间,就是toIndex位置的元素不被移除,fromIndex位置元素被移除
- protected void removeRange(int fromIndex, int toIndex) {
- modCount++;
- //需要移动的元素的个数=toIndex到最后一个元素位置
- int numMoved = size - toIndex;
- System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
- // clear to let GC do its work
- int newSize = size - (toIndex-fromIndex);
- for (int i = newSize; i < size; i++) {
- elementData[i] = null;//设置为null,让gc有机会回收
- }
- size = newSize;
- }
二、LinkedList详解
1.继承关系
- public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
(1)继承自AbstractSequentialList抽象类(该类继承自AbstractList抽象类);实现了List、Deque、Cloneable和Serializable接口,对随机get、set、remove等做了基本实现。
(2)AbstractSequentialList抽象类:定义了具体方法get()、set()、add()、remove()、addAll()(提供对list的随机访问功能)和抽象方法abstract ListIterator<E> listIterator(int index)。
(3)Deque:双向队列,可以用作栈。继承自Queue接口,Queue接口又继承自Collection接口。
(4)实现方式是采用双向链表的形式。
(5)LinkedList可以被当作堆栈(实现了Deque接口)、队列或双端队列进行操作。
2.属性
- transient int size = 0;//包含元素的个数
- transient Node<E> first;//指向链表的第一个元素的指针
- transient Node<E> last;//指向链表的最后一个元素的指针
3.数据结构
- 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;
- }
- }
4.方法
(1)addFirst():链表头部添加一个新元素,调用私有方法linkFirst实现
- public void addFirst(E e) {
- linkFirst(e);
- }
- //linkFirst:在链表首添加一个元素
- private void linkFirst(E e) {
- final Node<E> f = first;
- //new Node<>(指向前一个节点的指针,数据,指向后一个节点的指针)
- final Node<E> newNode = new Node<>(null, e, f);
- first = newNode;
- //链表原先为空,现在添加了一个节点,last指针和first指针都指向该节点
- if (f == null)
- last = newNode;
- //原先的首节点的prev指针指向新节点
- else
- f.prev = newNode;
- size++;
- //修改次数+1
- modCount++;
- }
(2)addLast、add:在链表尾部添加一个新节点,调用私有方法linkLast实现
- public void addLast(E e) {
- linkLast(e);
- }
- //类似的还有add方法也是调用linkLast实现
- public boolean add(E e) {
- linkLast(e);
- return true;
- }
- //linkLast:在链表的最后添加一个节点
- void linkLast(E e) {
- final Node<E> l = last;
- //新节点的prev指针指向原先的最后一个节点
- final Node<E> newNode = new Node<>(l, e, null);
- //修改last指针指向新的最后一个节点
- last = newNode;
- if (l == null)
- first = newNode;
- //原先的最后一个节点的next指针指向新节点
- else
- l.next = newNode;
- size++;
- modCount++;
- }
(3)removeFirst:删除链表的头节点
- public E removeFirst() {
- final Node<E> f = first;
- if (f == null)
- throw new NoSuchElementException();
- return unlinkFirst(f);
- }
- //unlinkFirst:删除链表中第一个节点,并取消链接(prev和next),私有方法,供removeLast()调用
- //使用前提:f!=null,否则会抛出异常;并且f是链表的第一个节点,否则结果会删除链表首节点到f位置的所有节点(first=f.next)
- private E unlinkFirst(Node<E> f) {
- // assert f == first && f != null;
- final E element = f.item;
- final Node<E> next = f.next;
- f.item = null;
- f.next = null; // help GC
- first = next;
- //链表中已经没有节点了
- if (next == null)
- last = null;
- else
- next.prev = null;
- size--;
- modCount++;
- return element;
- }
(4)removeLast:删除链表的最后一个节点
- public E removeLast() {
- final Node<E> l = last;
- if (l == null)
- throw new NoSuchElementException();
- return unlinkLast(l);
- }
- //unlinkLast:删除链表的最后一个节点,并删除链接,私有方法,供removeFirst方法调用
- //使用前提:f!=null,否则会抛出异常;并且l是链表的最后一个节点,否则会删除f到链表尾部的所有节点(last=l.prev)
- private E unlinkLast(Node<E> l) {
- // assert l == last && l != null;
- final E element = l.item;
- final Node<E> prev = l.prev;
- l.item = null;
- l.prev = null; // help GC
- last = prev;
- //该链表中已经没有节点了
- if (prev == null)
- first = null;
- else
- prev.next = null;
- size--;
- modCount++;
- return element;
- }
三、Vector详解
1.继承关系
- public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
(1)继承自AbstractList类
(2)List接口:继承自Collection接口,同时自己也定义了一系列索引访问功能。
(3)RandomAccess:空接口,实现该接口代表该类拥有随机访问list对象的能力。
(4)Cloneable:空接口,实现该接口,重写Object的clone方法,否则会抛出异常。调用super.clone()实现对象的复制,如果对象中有引用,可以在super.clone后面进行处理。
(5)java.io.Serializable:空接口,实现该接口代表该类可序列化
2.属性
- protected Object[] elementData;//内部还是采用一个数组保存list中的元素
- protected int elementCount;//数组实际包含的元素的个数
- protected int capacityIncrement;//每次增长的大小(不是增长率),当值小于等于0时,容量每次增长的容量为elementData.length(即倍增原数组的大小)
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //数组的最大容量
3.方法
(1)构造方法,如果不提供初始容量,则默认数组大小为10
- public Vector() {
- this(10);
- }
(2)同步方法:trimToSize,将数组的容量修改成实际容量的大小,即令elementData.length=elementCount
- public synchronized void trimToSize() {
- modCount++;
- int oldCapacity = elementData.length;
- if (elementCount < oldCapacity) {
- elementData = Arrays.copyOf(elementData, elementCount);
- }
- }
(3)同步方法:ensureCapacity,保证数组的最小容量
- public synchronized void ensureCapacity(int minCapacity) {
- if (minCapacity > 0) {
- modCount++;
- ensureCapacityHelper(minCapacity);
- }
- }
- //调用了ensureCapacityHelper:
- private void ensureCapacityHelper(int minCapacity) {
- // overflow-conscious code
- if (minCapacity - elementData.length > 0)
- grow(minCapacity);
- }
- //调用了grow:
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- //如果capacityIncrement<0,则newCapacity=oldCapacity+oldCapacity;
- //否则则newCapacity=oldCapacity+capacityIncrement;
- int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
- capacityIncrement : oldCapacity);
- //如果增长后仍不能保证满足minCapacity,则令newCapacity = minCapacity
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- //若增长后的大小大于允许的最大长度,则调用hugeCapacity
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- //调用Arrays.copyof方法将elementData拷贝到一个容量为newCapacity的数组中。
- //Arrays.copyOf(elementData, newCapacity)实际上是通过System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));来实现的
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
- //调用了hugeCapacity
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- //MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
(4)同步方法:setSize,将elementData.length设置为newSize
- public synchronized void setSize(int newSize) {
- modCount++;
- if (newSize > elementCount) {
- //若newSize<elementData.length,则不用扩容,否则需要扩容
- ensureCapacityHelper(newSize);
- } else {
- //若newSize<elementData的实际大小(elementCount),则将newSize及其后面的数组都置为空
- for (int i = newSize ; i < elementCount ; i++) {
- elementData[i] = null;
- }
- }
- elementCount = newSize;
- }
(5)同步方法:capacity,返回数组的大小;size,返回数组包含的元素的个数;isEmpty,判断数组是否没有元素
- public synchronized int capacity() {
- return elementData.length;
- }
- public synchronized int size() {
- return elementCount;
- }
- public synchronized boolean isEmpty() {
- return elementCount == 0;
- }
(6)同步方法:删除index处的元素
- public synchronized void removeElementAt(int index) {
- modCount++;
- if (index >= elementCount) {
- throw new ArrayIndexOutOfBoundsException(index + " >= " +
- elementCount);
- }
- else if (index < 0) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
- int j = elementCount - index - 1;
- if (j > 0) {
- //将elementData从index+1到elementCount为止的元素向前移动一个位置,覆盖Index处的元素
- System.arraycopy(elementData, index + 1, elementData, index, j);
- }
- elementCount--;
- elementData[elementCount] = null; /* to let gc do its work */
- }
- //remove也是删除,但是没有判断index是否小于0
- public synchronized E remove(int index) {
- modCount++;
- if (index >= elementCount)
- throw new ArrayIndexOutOfBoundsException(index);
- E oldValue = elementData(index);
- int numMoved = elementCount - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index+1, elementData, index,
- numMoved);
- elementData[--elementCount] = null; // Let gc do its work
- return oldValue;
- }
(7)同步方法:insertElementAt,在index处插入obj
- public synchronized void insertElementAt(E obj, int index) {
- modCount++;
- if (index > elementCount) {
- throw new ArrayIndexOutOfBoundsException(index
- + " > " + elementCount);
- }
- //先保证容量大于elementCount+1
- ensureCapacityHelper(elementCount + 1);
- //将elementData数组中index到elementCount之间的元素向后移动一位,给Index处空出位置
- System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
- elementData[index] = obj;
- elementCount++;
- }
四、Stack详解
Stack继承于Vector,在其基础上实现了Stack所要求的后进先出(LIFO)的弹出与压入操作,其提供了push、pop、peek三个主要的方法:
push操作通过调用Vector中的addElement来完成;
pop操作通过调用peek来获取元素,并同时删除数组中的最后一个元素;
peek操作通过获取当前Object数组的大小,并获取数组上的最后一个元素。
ArrayList, LinkedList和Vector区别:
1.实现方式:
ArrayList和Vector采用数组按顺序存储元素,默认初始容量是10。
LinkedList基于双向循环链表实现(含有头结点)。
2.线程安全性
Vector线程安全,效率低,开销大。
ArrayList和LinkedList非线程安全。
3.扩容机制
ArrayList扩容为原来的1.5倍。不可以设置容量增量。
Vector扩容为原来容量+容量增量的2倍。可以设置容量增量。
4.增删改查效率
在集合末尾增加、删除元素,修改和查询时用ArrayList和Vector快。
在指定位置插入、删除元素,LinkedList快。
集合类---List的更多相关文章
- Java集合类--温习笔记
最近面试发现自己的知识框架有好多问题.明明脑子里知道这个知识点,流程原理也都明白,可就是说不好,不知道是自己表达技能没点,还是确实是自己基础有问题.不管了,再巩固下基础知识总是没错的,反正最近空闲时间 ...
- C# - 集合类
C#的集合类命名空间介绍: // 程序集 mscorlib.dll System.dll System.Core.dll // 命名空间 using System.Collections:集合的接口和 ...
- 做JavaWeb开发不知Java集合类不如归家种地
Java作为面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储.但是使用数组存储对象方面具有一些弊端,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容 ...
- Java基础知识笔记(八:集合类)
目录 1 集合类简介 2 List介绍及简单使用 2.1 LinkedList介绍及简单使用 2.2 ArrayList介绍及简单使用 2.3 Vector介绍及简单使用 2.3.1 S ...
- [转]使用Enumeration和Iterator遍历集合类
原文地址:http://www.cnblogs.com/xwdreamer/archive/2012/05/30/2526268.html 前言 在数据库连接池分析的代码实例中,看到其中使用Enume ...
- java集合类深入分析之Queue篇
简介 Queue是一种很常见的数据结构类型,在java里面Queue是一个接口,它只是定义了一个基本的Queue应该有哪些功能规约.实际上有多个Queue的实现,有的是采用线性表实现,有的基于链表实现 ...
- Android开发之Java集合类性能分析
对于Android开发者来说深入了解Java的集合类很有必要主要是从Collection和Map接口衍生出来的,目前主要提供了List.Set和 Map这三大类的集合,今天Android吧(ard8. ...
- 【转载】Java集合类Array、List、Map区别和联系
Java集合类主要分为以下三类: 第一类:Array.Arrays第二类:Collection :List.Set第三类:Map :HashMap.HashTable 一.Array , Arrays ...
- Java 集合类的特性
ArrayList: 元素单个,效率高,多用于查询 Vector: 元素单个,线程安全,多用于查询 LinkedList: 元素单个,多用于插入和删除 HashMap: 元素成对,元素可为空 H ...
- C#与Java对比学习:数据类型、集合类、栈与队列、迭达、可变参数、枚举
数据类型: C#:String与StringBuilder Java:String与StringBuffer 第一个不习惯是string的第一个字母必须大写了. 第二个不习惯是int得写成Intege ...
随机推荐
- Hive 文件格式 & Hive操作(外部表、内部表、区、桶、视图、索引、join用法、内置操作符与函数、复合类型、用户自定义函数UDF、查询优化和权限控制)
本博文的主要内容如下: Hive文件存储格式 Hive 操作之表操作:创建外.内部表 Hive操作之表操作:表查询 Hive操作之表操作:数据加载 Hive操作之表操作:插入单表.插入多表 Hive语 ...
- TouTiao开源项目 分析笔记7 加载数据的过程
1.以新闻页中的段子数据显示为例 1.1.首先执行InitApp==>SplashActivity. 因为在AndroidManifest.xml中定义了一个<intent-filter& ...
- Active Directory 域服务 (AD DS) 虚拟化
TechNet 库 Windows Server Windows Server 2012 R2 和 Windows Server 2012 服务器角色和技术 Active Directory Acti ...
- 创建、导入、导出、复制以及粘贴 WMI 筛选器
TechNet 库 Deployment Forefront Identity and Access Management 基础结构优化 浏览器 Microsoft Dynamics Products ...
- Android学习记录(1)—Android中XML文件的序列化生成与解析
xml文件是非常常用的,在android中json和xml是非常常用的两种封装数据的形式,从服务器中获取数据也经常是这两种形式的,所以学会生成和解析xml和json是非常有用的,json相对来说是比较 ...
- 剑指Offer - 九度1522 - 包含min函数的栈
剑指Offer - 九度1522 - 包含min函数的栈2013-12-01 23:44 题目描述: 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. 输入: 输入可能包含多个测 ...
- USACO Section1.2 Dual Palindromes 解题报告
dualpal解题报告 —— icedream61 博客园(转载请注明出处)-------------------------------------------------------------- ...
- .netCore 反射 :Could not load file or assembly 系统找不到指定文件
“System.IO.FileNotFoundException:“Could not load file or assembly 'ClassLibrary2, Culture=neutral, P ...
- Kotlin的数据类:节省很多行代码(KAD 10)
作者:Antonio Leiva 时间:Jan 25, 2017 原文链接:https://antonioleiva.com/data-classes-kotlin/ 在前面的文章中,我们已经见到了类 ...
- Linux认知之旅【05 进一步了解Linux装软件】!
一.Linux软件管理系统 二.Linux还可以用源码安装 三.Linux软件配置