java容器类1:Collection,List,ArrayList,LinkedList深入解读

1、 Iterable 与 Iterator

Iterable 是个接口,实现此接口使集合对象可以通过迭代器遍历自身元素.

public interface Iterable<T>

修饰符和返回值方法名描述
Iterator<T>iterator()返回一个内部元素为T类型的迭代器
default voidforEach(Consumer<? super T> action)对内部元素进行遍历,并对元素进行指定的操作
default Spliterator<T>spliterator()创建并返回一个可分割迭代器

第一个接口iterator()是jdk1.5引入的,需要子类实现一个内部迭代器Iterator遍历元素。

后两个接口是JDK1.8后新添加的,forEach(Consumer action)是为了方便遍历操作集合内的元素,spliterator()则提供了一个可以并行遍历元素的迭代器,以适应现在cpu多核时代并行遍历的需求.

其中我们可以看下default修饰符,这也是Java 8后新出现的,我们知道,如果我们给一个接口新添加一个方法,那么所有他的具体子类都必须实现此方法,为了能给接口拓展新功能,而又不必每个子类都要实现此方法,Java 8新加了default关键字,被其修饰的方法可以不必由子类实现,并且由dafault修饰的方法在接口中有方法体,这打破了Java之前对接口方法的规范.

Iterator 为迭代器类,用于遍历容器。

public interface Iterator<E>

修饰符和返回值方法名描述
booleanhasNext()判断迭代器所指元素是否为最后一个
Enext()下一个元素
default Voidremove()移除迭代器指向的当前元素
default VoidforEachRemaining(Consumer<? super E> action)遍历迭代器指向元素后面的所有元素

AbstartList中实现了Iterator类作为List内部的迭代器,用于访问内部元素,其代码如下:

复制代码

  1 private class Itr implements Iterator<E> {
  2         /**
  3          * Index of element to be returned by subsequent call to next.
  4          */
  5         int cursor = 0;
  6 
  7         /**
  8          * Index of element returned by most recent call to next or
  9          * previous.  Reset to -1 if this element is deleted by a call
 10          * to remove.
 11          */
 12         int lastRet = -1;
 13 
 14         /**
 15          * The modCount value that the iterator believes that the backing
 16          * List should have.  If this expectation is violated, the iterator
 17          * has detected concurrent modification.
 18          */
 19         int expectedModCount = modCount;
 20 
 21         public boolean hasNext() {
 22             return cursor != size();
 23         }
 24 
 25         public E next() {
 26             checkForComodification();
 27             try {
 28                 int i = cursor;
 29                 E next = get(i);
 30                 lastRet = i;
 31                 cursor = i + 1;
 32                 return next;
 33             } catch (IndexOutOfBoundsException e) {
 34                 checkForComodification();
 35                 throw new NoSuchElementException();
 36             }
 37         }
 38 
 39         public void remove() {
 40             if (lastRet < 0)
 41                 throw new IllegalStateException();
 42             checkForComodification();
 43 
 44             try {
 45                 AbstractList.this.remove(lastRet);
 46                 if (lastRet < cursor)
 47                     cursor--;
 48                 lastRet = -1;
 49                 expectedModCount = modCount;
 50             } catch (IndexOutOfBoundsException e) {
 51                 throw new ConcurrentModificationException();
 52             }
 53         }
 54 
 55         final void checkForComodification() {
 56             if (modCount != expectedModCount)
 57                 throw new ConcurrentModificationException();
 58         }
 59     }
 60 

复制代码

2、Collection

Collection 是容器类的接口,里面可以存放很多Elements,很多容器都实现了该接口。

public interface Collection<E> extends Iterable<E>

修饰符和返回值方法名描述
intsize()判断容器的大小
booleanisEmpty()判空
booleancontains(Object o)是否包含某元素
Object[]toArray()转化为数组
<T> T[]toArray(T[] a)将容器中所有元素拷贝到a中,如果a不够大,则拷贝到返回的数组中。(见AbstactCollection中实现)
booleanadd(E e)添加元素
booleanremove(Object o)移除容器中第一个出现Object对象,如果Object为null,则移除第一个出现的null。如果没有Object对象返回false
booleancontainsAll(Collection<?> c)包含c中所有元素
booleanaddAll(Collection<? extends E> c);将c中所有元素添加到容器中
booleanremoveAll(Collection<?> c)如果容器中包含c中的元素,删除。(调用remove(Object))
default booleanremoveIf(Predicate<? super E> filter)移除所有符合条件的元素(JDK1.8中引入)
booleanretainAll(Collection<?> c)保留在c中出现的元素,其它全部移除
booleanclear() 
booleanequals(Object o)与o中所有元素都相等则相等
int hashCode()c1.equals(c2) 那么他们的hashCode()一定相等,反之不成立 
default Spliterator<E>spliterator()在所有元素之上创建一个Spliterator
default Stream<E>stream() 
default Stream<E>parallelStream() 

上述很多函数的实现可以参考 AbstactList中的实现。

3. List

List是一个接口,继承了Collection中的所有接口,并且添加了自身相关接口和具体实现。

由上图可以看出,Collection分成了三个分支,List就是其中一个,下面我们具体分析一下增加的接口。

public interface List<E> extends Collection<E>

修饰符和返回值方法名描述
 Collection中的所有接口 
default void replaceAll(UnaryOperator<E> operator)将运算操作后的结果替换List中原有元素
default voidsort(Comparator<? super E> c)将List中所有元素排序
get(int index); 
set(int index, E element) 
remove(int index) 
intindexOf(Object o)o在List中第一次出现的位置
intlastIndexOf(Object o)o在List中最后一次出现的位置
ListIterator<E>listIterator()获取List的迭代器
ListIterator<E>listIterator(int index)获取从某个位置开始的迭代器,index为迭代器起始位置
List<E>subList(int fromIndex, int toIndex)子List

上表可以看出,增加了 和index相关的接口,根据index对List进行的get、set、remove等操作。另一类添加的接口是ListIteator相关的,获取List的迭代器。

3.1 ListIterator

public interface ListIterator<E> extends Iterator<E>

ListIterator 不光包含Iterator中的三个接口还增加了作为一个List迭代器应该有的接口,如 next(),previous()等

修饰符和返回值方法名描述
 Iterator中的所有接口 
boolean hasNext() 
Enext() 
boolean hasPrevious() 
Eprevious() 
intnextIndex() 
intpreviousIndex() 
void remove()删除next()返回元素
void set(E e)替换next()返回的元素
void add(E e)在nextIndex()后插入元素

首先需要明确ListIterator迭代器的作用:

  1. 允许我们向前、向后两个方向遍历 List;
  2. 在遍历时修改 List 的元素;
  3. 遍历时获取迭代器当前游标所在位置。

注意,迭代器 没有当前所在元素一说,它只有一个游标( cursor )的概念,这个游标总是在元素之间,比如这样:

迭代器的初始位置:

这里写图片描述

调用next()后迭代器的位置这里写图片描述

调用 previous() 游标就会回到之前位置。当向后遍历完元素,游标就会在元素 N 的后面

这里写图片描述

也就是说长度为 N 的集合会有 N+1 个游标的位置。

3.2 AbstractCollection / AbstractList

        在上面的继承关系图中并没有显示出AbstractCollect和AbstractList的存在,但是在阅读源码的时候经常遇到这两个类,下面讲一下这两个类的作用。

      首先需要明确的一点是AbstractCollect和AbstractList都是抽象类而不是接口,它们分别实现了Collection和List接口中的部分函数。这样继承者直接继承AbstractXXXX 而不需要自己重复实现里面的所有接口。这两个抽象类抽离了公共部分,进行了实现,减少后续类的工作量。

       ArrayList 和LinkedList都直接或者间接继承了AbstartList类。下图为这两个类的继承关系:

这里写图片描述

        具体这两个类里面实现了哪些接口,请自己阅读源码不再讲解。

LinkedList中modCount和expectedModCount作用

在AbstractList中可以看到这两个变量,它们用于表示List被修改的次数,这其中包括了调用集合本身的add等方法等修改方法时进行的修改和调用集合迭代器的修改方法进行的修改。而expectedModCount则是表示迭代器对集合进行修改的次数。

那么知道这两个值有什么作用呢?

如果创建多个迭代器对一个集合对象进行修改的话,那么就会有一个modCount和多个expectedModCount,且modCount的值之间也会不一样,这就导致了moCount和expectedModCount的值不一致,从而产生异常。

https://www.cnblogs.com/zhangcaiwang/p/7131035.html

3.3 ArrayList

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable我们看到ArrayList的定义的时候很可能会出现一个疑问,为什么它已经继承了AbstractList了还需要去实现List<E>接口? 答案是,后面的List<E>可以去掉,这里只是让阅读者明白ArrayList是个List。 终于好不容易到了开发者常用的类了,有点窃喜:transient Object[] elementData;这个很重要的成员变量elementData数组用来存放ArrayList中的元素,当第一个元素添加进来后,它的默认长度变为10。(java中“transient”关键字修饰的成员变量在类序列化的过程中不会被持久化到文件中,保证该成员变量保存信息的安全。)
ArrayList的构造函数中可以直接指定elementData数组的长度,那么问题来了,当数组已经完全被占用再向ArrayList中添加元素时,如何再分配更大长度的数组?如何把旧数据拷贝到新数组中?答案见下面这段源码

复制代码

  1 private void grow(int minCapacity) {  //最少需要的容量 
  2         // overflow-conscious code
  3         int oldCapacity = elementData.length;
  4         int newCapacity = oldCapacity + (oldCapacity >> 1);   // 分配最小容量的 1.5倍
  5         if (newCapacity - minCapacity < 0)       
  6             newCapacity = minCapacity;
  7         if (newCapacity - MAX_ARRAY_SIZE > 0)
  8             newCapacity = hugeCapacity(minCapacity);   // 最大容量比较(Inter.MAX_VALUE)
  9         // minCapacity is usually close to size, so this is a win:
 10         elementData = Arrays.copyOf(elementData, newCapacity);  // 将旧数据拷贝到新数组中
 11     }

复制代码

其它接口不再细说。

3.4 LinkedList

 

  1 public class LinkedList<E>
  2     extends 

AbstractSequentialList<E>

  3     implements List<E>, Deque<E>, Cloneable, java.io.Serializable

作为一个链表类型,首先需要熟悉一下节点类:Node(LinkedList静态内部类)

复制代码

  1 private static class Node<E> {
  2         E item;
  3         Node<E> next;
  4         Node<E> prev;
  5 
  6         Node(Node<E> prev, E element, Node<E> next) {
  7             this.item = element;
  8             this.next = next;
  9             this.prev = prev;
 10         }
 11     }

复制代码

在LinkedList中有三个主要成员变量:

  • transient int size = 0;      // 链表长度
  • transient Node<E> first;  // 链表的首节点
  • transient Node<E> last;  // 链表的末节点

LinkedList构造方法:

复制代码

  1  /**
  2      * Constructs an empty list.
  3      */
  4     public LinkedList() {
  5     }
  6 
  7     /**
  8      * Constructs a list containing the elements of the specified
  9      * collection, in the order they are returned by the collection's
 10      * iterator.
 11      *
 12      * @param  c the collection whose elements are to be placed into this list
 13      * @throws NullPointerException if the specified collection is null
 14      */
 15     public LinkedList(Collection<? extends E> c) {
 16         this();
 17         addAll(c);
 18     }

复制代码

clear()方法:遍历LinkedList 置null

View Code

public E set(int index, E element):将某个Index指向的Node置变为element

View Code

public void add(int index, E element):在链表的index位置添加一个节点

这里还有众多的插入删除等函数,其主要思想还是对链表的操作(插入删除等),详情阅读源码。

3.5 ArrayList 与LinkedList 性能比较

两种List的存储结构决定了两者的性能:ArrayList以数组形式存储,LinkedList以链表形式存储

ArrayList是以数组的形式存储的,所以他的遍历很快,可以根据index很快找到对应元素。但是,ArrayList的插入和删除操作较慢,如果需要在数组中插入一个元素或者删除一个元素较麻烦。

LinkedList的索引操作较慢(需要遍历列表才能找到对应索引元素),但是它的插入和删除操作效率高(只需要控制前后指针就能实现插入和删除)。


参考:

https://www.cnblogs.com/bushi/p/6647006.html

https://www.jianshu.com/p/047e33fdefd2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无限场景开放式仿真器 PGDrive:Improving the Generalization of End-to-End Driving through Procedural Generation

本文介绍一个拥有无限场景开放式驾驶仿真器&#xff1a;PGDrive&#xff0c;通过 Procedural Generation 技术可以生成无限多的驾驶场景&#xff0c;由香港中文大学周博磊团队开发。 论文地址&#xff1a;https://arxiv.org/pdf/2012.13681.pdf 项目地址&#xff1a;https://…

java容器类2:Map及HashMap深入解读

Java的编程过程中经常会和Map打交道&#xff0c;现在我们来一起了解一下Map的底层实现&#xff0c;其中的思想结构对我们平时接口设计和编程也有一定借鉴作用。(以下接口分析都是以jdk1.8源码为参考依据) 1. Map An object that maps keys to values. A map cannot contain du…

两阶段3D目标检测网络 SIENet: Spatial Information Enhancement Network for 3D Object Detection from Point Cloud

本文介绍一篇两阶段的3D目标检测网络&#xff1a;SIENet。 这里重点是理解本文提出的 Hybrid-Paradigm Region Proposal Network 和 Spatial Information Enhancement module。 论文链接为&#xff1a;https://arxiv.org/abs/2103.15396 项目链接为&#xff1a;https://githu…

java容器类3:set/HastSet/MapSet深入解读

介绍 Set&#xff1a;集合&#xff0c;是一个不包含重复数据的集合。&#xff08;A collection that contains no duplicate elements. &#xff09; set中最多包含一个null元素&#xff0c;否者包含了两个相同的元素&#xff0c;不符合定义。 上一篇学习了Java中的容器类的一…

Bandit算法原理及Python实战

目录 1&#xff09;什么是Bandit算法 为选择而生。 Bandit算法与推荐系统 怎么选择Bandit算法&#xff1f; 2)常用Bandit算法 Thompson sampling算法 UCB算法 Epsilon-Greedy算法 Greedy算法 3&#xff09;Bandit算法Python实战 参考资料&#xff1a; 推荐系统里面有…

ava容器类4:Queue深入解读

Collection的其它两大分支&#xff1a;List和Set在前面已近分析过&#xff0c;这篇来分析一下Queue的底层实现。 前三篇关于Java容器类的文章&#xff1a; java容器类1&#xff1a;Collection,List,ArrayList,LinkedList深入解读 java容器类2&#xff1a;Map及HashMap深入解…

Waymo离线点云序列3D物体检测网络 (3D Auto Labeling): Offboard 3D Object Detection from Point Cloud Sequences

本文介绍一篇Waymo基于点云序列的3D物体检测网络&#xff1a;3D Auto Labeling&#xff0c;论文已收录于CVPR 2021。 这里重点是理解本文提出的 Object-centric Auto Labeling。 论文链接为&#xff1a;https://arxiv.org/abs/2103.05073 2021-09-02补充&#xff1a;本文作者…

Waymo自动驾驶数据集介绍与使用教程

本文将对Waymo自动驾驶数据集&#xff08;Waymo Open Dataset&#xff09;进行介绍。 论文链接为&#xff1a;https://arxiv.org/abs/1912.04838v7 项目链接为&#xff1a;https://github.com/waymo-research/waymo-open-dataset 数据集链接为&#xff1a;https://waymo.com…

Java 并发基础——线程安全性

线程安全&#xff1a;多个线程访问某个类时&#xff0c;不管运行时环境采用何种调度方式或者这些线程将如何交替执行&#xff0c;并且在主调代码中不需要任何额外的同步或协调&#xff0c;这个类都能表现出正确的行为&#xff0c;那么久称这个类是线程安全的。 在线程安全类中封…

详解一阶段3D物体检测网络 SE-SSD: Self-Ensembling Single-Stage Object Detector From Point Cloud

本文介绍一篇一阶段的3D物体检测网络&#xff1a;SE-SSD&#xff0c;论文已收录于 CVPR 2021。 这里重点是理解本文提出的 Consistency Loss 、Orientation-Aware Distance-IoU Loss、Shape-Aware Data Augmentation。 论文链接为&#xff1a;https://arxiv.org/pdf/2104.0980…

详解3D点云分割网络 Cylindrical and Asymmetrical 3D Convolution Networksfor LiDAR Segmentation

本文介绍一篇3D点云分割网络&#xff1a;Cylinder3D&#xff0c;论文已收录于 CVPR 2021。 这里重点是理解本文提出的 Cylindrical Partition 和 Asymmetrical 3D Convolution Network。 论文链接为&#xff1a;https://arxiv.org/pdf/2011.10033.pdf 项目链接为&#xff1a;…

自动驾驶3D物体检测研究综述 3D Object Detection for Autonomous Driving: A Survey

本文介绍一篇最新的自动驾驶3D物体检测研究综述&#xff08;2021年6月份发布&#xff09;&#xff0c;来源于中国人民大学&#xff0c;论文共26页&#xff0c;99篇参考文献。 论文链接为&#xff1a;https://arxiv.org/pdf/2106.10823.pdf 0. Abstract 自动驾驶被看作是避免人…

Java中接口的多继承

我们知道Java的类只能继承一个类&#xff0c;但可以实现多个接口。但是你知道么&#xff1f;Java中的接口却可以继承多个接口。本文就来说一说Java中接口的多继承。 进入主题之前&#xff0c;先扩展一下。Java为什么只支持单继承呢&#xff1f; 我们不妨假设Java支持多继承&a…

详解基于IMU/GPS的行人定位: IMU/GPS Based Pedestrian Localization

本文介绍一篇使用 IMU/GPS 数据融合的行人定位论文&#xff0c;这里重点是理解本文提出的 Stop Detection 和 GPS Correction。 论文地址为&#xff1a;https://www.researchgate.net/publication/261452498_IMUGPS_based_pedestrian_localization 1. Introduction 低成本的 …

每次maven刷新jdk都要重新设置

pom.xml <java.version>17</java.version> 改为<java.version>1.8</java.version>

【CodeForces - 706D】Vasiliy's Multiset(01字典树)

题干&#xff1a; Author has gone out of the stories about Vasiliy, so here is just a formal task description. You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries: " x" — add integer …

详解自动驾驶仿真框架OpenCDA: An Open Cooperative Driving Automation Framework Integrated with Co-Simulation

本文介绍一款同时支持协同驾驶开发与测试、自动驾驶全栈开发 和 CARLA-SUMO联合仿真的开源框架 OpenCDA&#xff0c;论文已收录于 ITSC 2021。主要feature有&#xff1a; 支持CARLA-SUMO联合仿真&#xff0c;CARLA端主管环境渲染、传感器模拟、车辆动力&#xff0c;Sumo端主管…

JavaMonitor 监视器

为什么wait(), notify()和notifyAll()必须在同步方法或者同步块中被调用&#xff1f; 当一个线程需要调用对象的wait()方法的时候&#xff0c;这个线程必须拥有该对象的锁&#xff0c;接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的notify()方法。同样的…

KITTI自动驾驶数据集可视化教程

本文介绍关于自动驾驶数据集KITTI的基本操作&#xff0c;包括Camera和LiDAR可视化教程&#xff0c;源码已上传&#xff1a;https://download.csdn.net/download/cg129054036/20907604 1. 数据准备 将 KITTI 数据 (calib, image_2, label_2, velodyne) 添加到 dataset/KITTI/ob…

重读经典《Quaternion kinematics for the error-state Kalman filter》

本文将介绍一篇关于 四元数运动学的误差卡尔曼滤波 经典论文。本文结构如下&#xff1a; 第1章四元数定义和性质介绍&#xff0c;包括&#xff1a;加法、减法、乘法&#xff08;矩阵表示&#xff09;、模、幂数、指数运算等。第2章旋转群定义和性质介绍&#xff0c;包括&#…