前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java基础系列(三十八):集合总览

Java基础系列(三十八):集合总览

作者头像
山禾说
发布2019-01-21 10:12:08
4740
发布2019-01-21 10:12:08
举报
文章被收录于专栏:Vi的技术博客

在我们日常的开发中,集合占据着举足轻重的地位。在不同的情况下,我们会去选择性能更佳(或更安全的)集合类作为一个容器去存储数据。在接下来的几节中,我会带着大家对于集合的知识进行一次系统的深入梳理,相信梳理过后,面试或日常开发再遇到有关集合的问题对我们来说都不会是问题了。

总览图

首先我们先以一个耳熟能详的集合鸟瞰图开始说起

(PS:截图自《编程思想》)

通过这个图,我们可以获得哪些有用的信息呢?

这个图由 Map指向 CollectionProduces并不是说 MapCollection的一个子类(子接口),这里的意思是指 MapKeySet获取到的一个视图是 Collection的子接口(视图是什么,我们后面会讲到)。 我们可以看到集合有两个基本接口: MapCollection。但是我个人认为 Map并不能说是一个集合,称之为映射或许更为合适,因为它的 KeySet视图是一个 Set类型的键集,所以我们姑且把它也当做集合。 Collection继承了 Iterator接口,而 Iterator的作用是给我们提供一个只能向后遍历集合元素的迭代器,也就是说所有实现 Collection的类都可以使用 Iterator遍历器去遍历。 每种接口都有一个 Abstract开头的抽象子类,这个子类中包括了一些默认的实现,我们在自定义类的时候都需要去继承这个抽象类,然后根据我们不同的需求,对于其中的方法进行重写。 从容器角度上来说,只有四种容器: MapQueueSetList

简单介绍:

下面我们对基本的分类进行一个简单的介绍和了解,后续我们会从数据结构和用法等方面去详细学习。

ArrayList: 一种可以动态增长和缩减的的索引序列 LinkedList:一种可以在任何位置进行高效地插入和删除操作的有序序列ArrayDeque:一种用循环数组实现的双端队列 HashSet:一种没有重复元素的无序集合 TreeSet:一种有序集 EnumSet:一种包含枚举类型值的集 LinkedHashSet:一种可以记住元素插入次序的集 PriorityQueue:一种允许高效删除最小元素的集合 HashMap:一种存储键/值关联的数据结构 TreeMap:一种键值有序排列的映射表 EnumMap:一种键值属于枚举类型的映射表 LinkedHashMap:一种可以记住键/值项添加次序的映射表 WeakHashMap:一种其值无用武之地后可以被垃圾回收期回收的映射表 IdentityHashMap:一种用==而不是用equals比较键值的映射表 Vector:目前使用较少,因为设计理念的陈旧和性能的问题被ArrayList所取代 Hashtable:线程非同步可以使用HashMap来替代,同步的话可以使用ConcurrentHashMap来替代

Iterator

我们接下来聊一下迭代器,从鸟瞰图中我们可以看到,所有实现 Collection的子类都继承了 Iterable接口。这个接口提供了一个 iterator()方法可以构造一个 Iterator接口对象。然后我们可以使用这个迭代器对象依次访问集合中的元素 迭代器一般使用方法是这样的:

代码语言:javascript
复制
Collection<String> c = ...;Iterator<String> iter = c.iterator();while (iter.hasNext()) {    String s = iter.next();    System.out.println(s);}

或者是这样的:

代码语言:javascript
复制
//适用于JDK1.8以后的版本iter.forEachRemaining(element -> System.out.println(element));

我们接下来看一下 Iterator的源码(Base jdk1.8):

代码语言:javascript
复制
package java.util;import java.util.function.Consumer;public interface Iterator<E> {    boolean hasNext();    E next();    default void remove() {        throw new UnsupportedOperationException("remove");    }    default void forEachRemaining(Consumer<? super E> action) {        Objects.requireNonNull(action);        while (hasNext())            action.accept(next());    }}

迭代器的 next()工作原理是这样的:

可以看出,迭代器是位于两个集合元素之间的位置,当我们调用 next()方法的时候迭代器指针就会越过一个元素,并且返回刚刚越过的元素,所以,当我们迭代器的指针在最后一个元素的时候,就会抛出会抛出一个 NoSuchElementException的异常。所以,在调用 next()之前需要调用 hasNext()去判断这个集合的迭代器是否走到了最后一个元素。

通过调用 next()方法可以逐个的去访问集合中的每个元素,而访问元素的顺序跟该容器的数据结构有关,比如 ArrayList就是按照索引值开始,每次迭代都会使索引值加1,而对于HashSet这种数据结构是散列表的集合,就会按照某种随机的次序出现。

Iterator的接口中还有一个 remove()方法,这个方法实际上删除的是上次调用next()方法返回的元素,下面我来展示一下 remove()方法的使用方法

代码语言:javascript
复制
Collection<String> c = ...;Iterator<String> iter = c.iterator();iter.next();iter.remove();

这样就可以删除该集合中的第一个元素,但是需要注意一点,如果我们需要删除两个元素,必须这样做:

代码语言:javascript
复制
iter.remove();iter.next();iter.remove();

而不能这么做:

代码语言:javascript
复制
iter.remove();iter.remove();

因为 next()方法和 remove()方法之间是有依赖性的,如果调用 remove之前没有调用 next就会抛出一个 IllegalStateException的异常。

PS: 我们日常中用的很多的 foreach循环,其实就是一种语法糖,编译器会把 foreach编译为带有迭代器的循环。

下节预告

接下来,我会陆续带领大家去从源码,数据结构等方面去深入了解每一个类,下一节我们要学习 Collection的相关知识,敬请期待~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Vi的技术博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档