热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ArrayList/LinkedList/Vector源码分析

ArrayListpublicclassArrayList<E>extendsAbstractList&

ArrayList

public class ArrayList extends AbstractList
                                          implements List, RandomAccess, Cloneable, java.io.Serializable
  • ArrayList继承了AbstractList,实现了List,表示ArrayList实现了线性表的所有功能,本质上是一个Object数组
  • ArrayList实现了RandomAccess接口,表示提供随机访问功能,ArrayList可通过索引访问元素;
  • ArrayList实现了Cloneable接口,重写clone()方法,表示ArrayList可以被克隆;
  • ArrayList实现了Serializable接口,表示ArrayList可以被对象序列化;

transient Object[] elementData:ArrayList中用于存放数据的数据结构,物理上是一个Object数组,transient关键字表示在ArrayList对象被序列化时,elementData不会被序列化;elementData初始化时为一个空的Object数组,当第一添加元素时候,数组大小设置为DEFAULT_CAPACITY(JDK 1.8.0_121版本下DEFAULT_CAPACITY = 10

public Object[] toArray()
将ArrayList转换为一个Object数组;如果定义一个Integer类型的Arraylist, 直接使用Integer[] arr = list.toArray(),会抛出java.lang.ClassCastException异常,原因是Java不允许将Object []转化为其他类型;
方式一:必须得将object数组中的元素依次取出进行类型转换;
public T[] toArray(T[] a)
方式二:如果参数数组a.length >= list.size(),list中所有元素复制到a数组,完成数组转换;
方式三:如果参数数组a.length
ArrayList/LinkedList/Vector源码分析
 
public void trimToSize()将当前容量值设置数组实际元素个数(size);该方法可以最小化ArrayList当存储空间;

public void ensureCapacity(int minCapacity)
调整数组大小,确保数组至少可以容纳minCapacity个元素,追求以最小的存储代价满足要求,不改变数组实际元素个数(size);如果当前数组容量不足以容纳minCapacity个元素,计算新的容量 = 原始容量 * 1.5,然后按照下述表格动态调整数组容量以满足要求;
    newCapacity
当1.5*oldCapacity超过
最大数组容量
当minCapacity超过MAX_ARRAY_SIZE Integer.MAX_VALUE
当minCapacity不超过MAX_ARRAY_SIZE MAX_ARRAY_SIZE
当1.5*oldCapacity没有超过
最大数组容量
  min(1.5*oldCapacity, minCapacity)

private void ensureCapacityInternal(int minCapacity)
ArrayList进行set, add等要求数组容量增加的操作时,ArrayList在上述方法中通过ensureCapacityInternal方法动态增加数组大小,追求以最小的存储代价满足要求,不改变数组实际元素个数(size)

public Object clone()
将数据元素复制到一个泛型数组ArrayList,必须用Object类型接收后再进行类型强转,克隆操作属于浅拷贝,即仅仅拷贝对象引用(拷贝对象为8种基本数据类型 or 包装类型 or String类型时,进行浅拷贝操作时,效果和深拷贝操作一样);

public boolean addAll(Collection c)
直接添加其他线性表到本ArrayList,从index开始依次插入其他线性表
public boolean addAll(int index, Collection c)
直接添加其他线性表到本ArrayList,添加到ArrayList尾部;

public boolean remove(Object o)
删除o对象第一次出现的元素,后续数组元素批量前移;
public E remove(int index)
删除index对应元素,将置为null,size减1,后续数组元素批量前移;
private void fastRemove(int index)
负责remove方法的底层操作,快速删除index对应元素,前移后续数组元素;

public void clear():将所有元素值置为null,size置0;

private void writeObject(java.io.ObjectOutputStream s)
首先写入数组实际大小size,然后依次写入数组元素
private void readObject(java.io.ObjectInputStream s)
首先读取数组实际大小size,然后依次读取数组元素

ArrayList遍历方式

ArrayList支持迭代器遍历,get直接索引遍历和foreach遍历,后两者效率较高;
ArrayList/LinkedList/Vector源码分析

LinkedList
public class LinkedList extends AbstractSequentialList
                                            implements List, Deque, Cloneable, java.io.Serializable
  • LinkedList继承AbstractSequentialList,本质上是双向链表,可以被当作堆栈、队列和双端队列进行操作
  • LinkedList实现List接口,能对它进行线性表操作;
  • LinkedList实现Deque接口,即能将LinkedList当作双端队列使用
  • LinkedList实现了Cloneable接口,重写了函数clone(),表示支持克隆;
  • LinkedList实现java.io.Serializable接口,表示LinkedList支持对象序列化,能通过序列化去传输;
来源: http://www.cnblogs.com/skywang12345/p/3308807.html

private static class Node:LinkedList中的静态内部类,表示双向链表节点,包括节点数据元素item,上一个节点指针和下一个节点指针;
ArrayList/LinkedList/Vector源码分析
transient int size = 0; 默认双向链表节点个数,transient修饰表示不可被序列化;
transient Node first;  双向链表第一个节点,即双向链表的表头,transient修饰表示不可被序列化;
transient Node last; 双向链表最后一个节点,transient修饰表示不可被序列化;

public Object clone():对双向链表的一次浅拷贝,拷贝通过从first节点开始,单向遍历链表完成;

Node node(int index):查找索引为index的节点,然后双向链表无法随机访问,LinkedList计算index和size / 2的大小关系,决定是从first依次向前查找还是从last节点依次向后查找;

public Object[] toArray():从first单向遍历一遍,返回一个Object数组,用法与ArrayList类相同;
public T[] toArray(T[] a):如果a数组长度不足以容纳LinkedList节点个数,根据反射机制创建一个大小为size的T[]数组,并赋值给a;

public ListIterator listIterator(int index):返回一个迭代器,指向索引为index的元素,用于对双向链表的顺序遍历;
public ListIterator listIterator(): 返回一个迭代器,指向第一个元素;
public Iterator descendingIterator()返回一个逆序迭代器,用于对双向链表的逆序遍历;

LinkedList遍历方式

  • 不破坏结构遍历:get随机访问(双向链表极力不推荐),foreach实现,迭代器实现(顺序/逆序);
  • 破坏结构遍历: 通过pollFirst/pollLast/removeFirst/removeLast实现;
ArrayList/LinkedList/Vector源码分析
 


Vector
public class Vector extends AbstractList
                                      implements List, RandomAccess, Cloneable, java.io.Serializable
  • Vector继承了AbstractList,实现了List接口;表示Vector可作为线性表使用;
  • Vector实现了RandomAccess接口,即提供了随机访问功能;
  • Vector实现了Cloneable接口,重写了函数clone(),表示支持克隆;
  • Vector实现java.io.Serializable接口,表示Vector支持对象序列化,能通过序列化去传输;
来源: http://www.cnblogs.com/skywang12345/p/3308833.html

protected Object[] elementData; Vector内部用Object数组存储数据,本质上是一个线程安全的数组

protected int elementCount; Vectorz中的实际元素个数,与ArrayList的size相对;
protected int capacityIncrement;  Vector容量增长系数。如果capacityIncrement > 0,Vector每次动态增长时容量增加capacityIncrement大小,f否则每次容量增加一倍;
Vector中大部分方法是synchronized,因此Vector是线程安全的

public synchronized ListIterator listIterator(int index):返回一个迭代器,指向索引为index的元素;
public synchronized ListIterator listIterator(): 返回一个迭代器,指向第一个元素;

Vector遍历方式

Vector支持get随机访问,foreach,迭代器和Enumeration遍历;

fail-fast
fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。


ArrayList,Vector, LinkedList辨析

ArrayList和LinkedList比较

相同点:
  • ArrayList 和 LinkedList 都实现了 List 接口;
不同点: 
  • ArrayList 是基于索引的数据接口,底层是Object数组。随机访问时间复杂度为O(1)。与此对应,LinkedList 是以双向链表形式存储数据,查找时间复杂度是O(n);
  • 相对于 ArrayList,LinkedList的插入,添加,删除操作速度更快;
  • LinkedList 比 ArrayList更占内存,因为 LinkedList 为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素;

ArrayList和Vector比较

相同点:
  • 两者都是基于索引的,底层由一个Object数组支持;
  • 两者维护插入的顺序,可根据插入顺序来获取元素;
  • ArrayList和Vector的迭代器实现都是fail-fast的;
  • ArrayList和Vector两者允许null值,也可以使用索引值对元素进行随机访问;
不同点:
  • Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。 
  • ArrayList比Vector快,因为没有同步机制;
  • ArrayList更加通用,因为我们可以使用Collections工具类使得ArrayList变得安全;


推荐阅读
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • 深入解析for与foreach遍历集合时的性能差异
    本文将详细探讨for循环和foreach(迭代器)在遍历集合时的性能差异,并通过实际代码示例和源码分析,帮助读者理解这两种遍历方式的不同之处。文章内容丰富且专业,旨在为编程爱好者提供有价值的参考。 ... [详细]
  • 2018-2019学年第六周《Java数据结构与算法》学习总结
    本文总结了2018-2019学年第六周在《Java数据结构与算法》课程中的学习内容,重点介绍了非线性数据结构——树的相关知识及其应用。 ... [详细]
  • PHP 过滤器详解
    本文深入探讨了 PHP 中的过滤器机制,包括常见的 $_SERVER 变量、filter_has_var() 函数、filter_id() 函数、filter_input() 函数及其数组形式、filter_list() 函数以及 filter_var() 和其数组形式。同时,详细介绍了各种过滤器的用途和用法。 ... [详细]
  • 本文详细介绍了 iBatis.NET 中的 Iterate 元素,它用于遍历集合并重复生成每个项目的主体内容。通过该元素,可以实现类似于 foreach 的功能,尽管 iBatis.NET 并未直接提供 foreach 标签。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 使用lambda表达式排序Collections.sort(temp,(Stringa,Stringb)-{returnb.compareTo(a);});Collections ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • 本文详细解析了Java中hashCode()和equals()方法的实现原理及其在哈希表结构中的应用,探讨了两者之间的关系及其实现时需要注意的问题。 ... [详细]
  • 本问题探讨了在特定条件下排列儿童队伍的方法数量。题目要求计算满足条件的队伍排列总数,并使用递推算法和大数处理技术来解决这一问题。 ... [详细]
  • 本文详细介绍了如何在PHP中使用serialize()和unserialize()函数,以及它们在数据传输和存储中的应用。 ... [详细]
  • 异常要理解Java异常处理是如何工作的,需要掌握一下三种异常类型:检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常ÿ ... [详细]
  • Java每日一题:876. 链表的中间节点解析
    本文详细介绍了LeetCode上编号为876的题目——链表的中间节点,包括问题描述、解决方案和代码实现。 ... [详细]
author-avatar
廖小廖童鞋
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有