首页 > 编程语言 >Java 集合框架2:List

Java 集合框架2:List

时间:2022-11-30 18:04:50浏览次数:40  
标签:Java LinkedList 迭代 ArrayList 元素 List add 集合

目录

List

1.概述

List 是一个有序序列,除了继承了 Collection 接口的方法之外,还有下面的功能拓展:

  • 位置访问(positional access),基于索引来操作元素,包含get、set、add、addAll 和 remove。
  • 搜索,在 List 中搜索指定的元素,放回元素的索引,indexOf、lastIndexOf。
  • 迭代,利用 List 顺序的特点,对 Iterator 的语义进行了拓展,比如 ListIterator。
  • 范围视图(range-view),用于执行范围操作,sublist

2.功能拓展

位置访问

基本的位置访问方法是get、set、add、remove。(set 和 remove 会返回元素以前的值)。

典型的例子是 Conllections 中的 shuffle 函数实现:

搜索

迭代

List 的 listIterator 方法返回了一个针对于 List 的迭代器 ListIterator,可以进行双向迭代。ListIterator 的定义如下:

ListIterator 的 cursor 并不指向元素,而是指向元素之间或 List 两端,所以,对于一个长度为 n 的 List,cursor 会有 n + 1 个位置。

对于 ListIterator 的方法,hasNext、hasPrevious 分别返回是否存在下一个、上一个元素。next、previous 分别返回下一个、上一个元素,并移动迭代位置。nextIndex、previousInde 分别返回下一个、上一个元素的索引。

remove 方法,将上次调用 next 、previous 函数返回的 element 给修改为新的元素。每次调用 next 或 previous 只能进行一次此调用。在此之中不能调用 add 方法,否则会抛出异常。

set 方法,将上次调用 next 、previous 函数返回的 element 给修改为新的元素。在此之中不能调用 remove、add 方法,否则会抛出异常。

add 方法,添加一个新元素到 next 与 previous 返回元素之间(如果有的话),cursor 位于新元素之后。

AbstractList 接口中有一个成员变量为 modCount,它记录了 List 被修改的次数,用于子类某些实现,要求对于迭代器使用过程中,根据此值是否改变来确认迭代器是否快速失效,而不是去发现是否存在其它线程修改原 List。

范围视图

List 的 subList 返回 [fromIndex, toIndex) 的范围视图(fromIndex 与 toIndex 相等时返回空列表)。

需要注意到的是:

  • subList 的非结构化改变会影响原 list,反之亦然。
  • 原 list 有除 subList 以外的任何方式在结构上进行了修改,那么 subList 的行为会变得未定义。

所以,一般将 subList 作为一个 transient object 来使用,而不是长期持有。

3.实现

Java 提供了两种通用的实现:ArrayList 和 LinkedList。在绝大多数情况下,都应该选择 ArrayList,只有在频繁的在List中插入和删除元素时,才考虑使用 LinkedList。

其它实现这里先不做叙述。

ArrayList

ArrayList 是一个基于能动态改变容量的数组实现的 List,类似于 C 中动态申请内存。

实现原理

首先,我们查看 ArrayList 的成员变量,主要的如下:

其中,Array 中的元素其实是被存储到 elementData 数组中,并对元素做了类型擦涂,为 Object,所以 ArrayList 中可以存储不同类型的元素。size 的值为 elementData 中的元素数量(并非大小)。

elementData 会有 3 种值:

  • EMPTY_ELEMENTDATA:表示,当明确 ArrayList 列表的大小为 0 时。此时所有的 ArrayList 实例共享 EMPTY_ELEMENTDATA。
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA:表示,未明确指出 ArrayList 列表大小,采用的默认容器。注意,ArrayList 使用 Lazy Initialization 的方式申请内存,初始化时 elementData 为空,只有当插入第一个元素时,才会创建默认大小的底层数组。
  • new Object[length]:指明了列表长度时。

ArrayList 需要确保列表大小,以保证有足够的空间来存储元素。这里就使用了扩容的机制,当需要扩容时,会开启新大小的空间并将原列表复制进去。有关扩容的方法如下:

其中,ensureCapacity 是提供给程序员使用的,ensureCapacityInternal 是当我调用 ArrayList中的其它方法时,如 add,程序调用的函数。这两个会去调用 ensureExplicitCapacity 方法进行扩容。扩容执行函数 grow,策略为变为 1.5 倍。

CopyOnWriteArrayList

ArrayList 并不是线程安全的,我们可以使用 Collections 中的同步包装器进行装饰为同步的。

Vector 虽然是线程安全的,但他的实现原理为给方法加 synchronized,简单除暴,性能差。

CopyOnWriteArrayList 是将数据的读与写分开,读操作实现类似于 ArrayList,但对于写操作,进行了加锁。add 代码示例如下:

对于写操作,加锁后,会把原数组拷贝一份,在新的数组上进行修改,然后更新原列表,解锁。

对于 CopyOnWriteArrayList 的迭代器,其实拿到的是获取是的 snapshot 版本,数组被保存到 COWIterator 中。在使用迭代器的过程中,其它线程修改了原列表时,由于修改后其实是给了一个新数组,原数组并未改变,所以修改原列表对迭代并没有影响。

需要注意的是,CopyOnWriteArrayList 获得的迭代器,不支持 remove、set、add 方法。

LinkedList

与 ArrayList 不同的是,LinkedList 除了实现 List,也实现 Deque。但 LinkedList 未实现 RandomAccess,不支持快速随机访问,说明 LinkedList 使用迭代器访问比 for 循环更快,这与 ArrayList 相反。

实现原理

LinkedList 其实是实现了一个双向链表。size 存储了链表大小,first 与 last 分别记录头节点与尾节点。

LinkedList 中每个节点用 Node 表示。Node 中,item 为真实元素,next、prev 分别表示链表中上一个与下一个节点。

LinkedList 中涉及到查询某个 index 的节点会使用的 node 方法。对于实现,首先会根据 index 判断节点离那端近,然后从对应端进行查询:

其它方法也基于双端链表实现。

标签:Java,LinkedList,迭代,ArrayList,元素,List,add,集合
From: https://www.cnblogs.com/meyok/p/16939281.html

相关文章

  • Java高效自学,应知道的知识
    JAVA简介    Java已经多年连续占据编程语言的榜首,Java是一门面向对象编程语言,它不仅吸收了C++语言的各种优点,还摒弃了C++语言中难以理解的多继承、指针等概念,因此Jav......
  • javascript函数的理解
    参考:https://www.liaoxuefeng.com/wiki/1022910821149312/1023021087191360在js里,函数是一等公民。函数可以分配给变量函数可以作为参数传递给其他函数函数可以从其他......
  • JAVA爬虫爬取网页数据数据库中,并且去除重复数据
    pom文件<!--添加Httpclient支持--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><versio......
  • ArrayList源码
    //属性//默认初始大小privatestaticfinalintDEFAULT_CAPACITY=10;//空数组用这个privatestaticfinalObject[]EMPTY_ELEMENTDATA={};//扩展数组时用来和EM......
  • 「Java数据结构」- 栈和队列
    栈的认识========栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。压栈:栈的插入操作叫做进栈/......
  • Java-根据父级id将List结构转Tree结构
    1.方法一:List的stream()方法publicResultDataqueryMenuList(){//获取所有数据ListList<MenuVo>list=MenuDao.queryMenuList();//通过list.s......
  • java项目中使用oshi搭建监控系统
    官网地址:​​https://github.com/oshi/oshi​​首先引入jar包<dependency><groupId>com.github.oshi</groupId><artifactId>oshi-core</artifact......
  • JAVA规定时间循环定时执行某个任务
    在我们做web项目的时候有些需求需要我们定时每周每天执行什么任务,这里给大家介绍一种方式,我就直接贴代码web.xml<listener><listener-class>com.hw.util.BeginRun......
  • ArrayList的源码分析(一)
    我想大家既然能看到这篇文章我就不用解释Arraylist是啥了,简单点说就是一个动态对象数组,然后就这个集合的源代码拿出来给大家分析一下我的个人看法和收获,实例代码是jdk1.8......
  • ArrayList的源码分析(二)
    上篇文章给大家介绍了arraylist集合源码的一些属性和扩容方式add方法,接下来再和大家来聊聊这个集合的一些源码首先看看remove的方法,这个方法有两个,一个是根据下标删除对......