Java核心技术-具体的集合
除了Map结尾的类之外,其他都实现了Collection接口,而以Map结尾的类实现了Map接口。
链表
在Java程序设计语言中,所有链表实际上都是双向链表的(double linked)——即每个节点还存放着指向前去节点的引用。
从链表中间删除一个元素是一个很轻松的操作, 即需要更新被删除元素附近的链接。
在链表中添加或删除元素时,绕来绕去的指针可能已经给人们留下了极坏的印象。如果真是如此的话,就会为Java集合类库提供一个LinkedList而感到拍手称快。
在下面的代码示例中,先添加3个元素,然后再将第2个元素删除;
List<String> staff = new LinkedList<>();// LinkedList implements List
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
Interator iter = staff.iterator();
String first = iter.next();//visit first element
String second = iter.next();//visit second element
iter.remove();//remove last visited element
链表是一个有序集合(ordered collection),每个对象的位置十分重要。LinkedList.add方法将对象添加到链表的尾部。由于迭代器时描述集合中位置的,所以这种依赖于位置的add方法将由迭代器负责。只有对自然有序的集合使用迭代器添加元素才有实际意义。Add方法在迭代器之前添加一个新对象。
当用一个刚刚由Iterator方法返回,并且指向链表表头的迭代器调用add操作时,新添加的元素将变成列表的新表头。当迭代器越过链表的最后一个元素时(即hasNext返回false),添加的元素将变成列表的新表尾。如果链表由n个元素,由n+1个位置可以添加新元素。这些位置与迭代器的n+1个可能的位置相对应。例如,如果链表包含3个元素,A、B、C,就有四个位置(标有|)可以插入新元素:
|ABC
A|BC
AB|C
ABC|
注释:在用“光标”类比时要格外小心。remove操作与BACKSPACE键的工作方式不太一样。在调用next之后,remove方法确实与BACKSPACE键一样删除了迭代器左侧的元素。但是如果调用previous就会将右侧的元素删除掉,并且不能连续调用两次remove。
add方法只依赖于迭代器的位置,而remove方法依赖于迭代器的状态。
例如,一个迭代器指向另一个迭代器刚刚删除的元素前面,现在这个迭代器就是无效的,并且不应该在使用。链表迭代器的设计使它能够检测到这种修改。如果迭代器发现它的集合被另一个迭代器修改了,或是被该集合自身的方法修改了,就会抛出一个ConcurrentModificationException异常。
为了避免发生并发修改的异常,请遵循下述简单规则:可以根据需要给容器附加许多的迭代器,但是这些迭代器只能读取列表。另外,再单独附加一个既能读又能写的迭代器。
有一个简单的方法可以检测到并发修改的问题。集合可以跟踪改写操作(诸如添加或删除元素)的次数。每个迭代器都维护一个独立的计数值。在每个迭代器方法的开始处检查自己改写操作的计数值是否与集合的改写操作计数值一致。如果不一致,抛出一个ConcurrentModificationException异常。
注释:对于并发修改列表的检测有一个奇怪的例外。链表只负责跟踪对列表的结构性修改,例如,添加元素、删除元素。set方法不被视为结构性修改。可以将多个迭代器附加给一个链表,所有的迭代器都调用set方法对现有节点的内容进行修改。
使用链表的唯一理由是尽可能地减少在列表中间插入或删除元素所付出的代价。如果列表只有少数几个元素,就完全可以使用ArrayList。
我们建议避免使用以整数索引表示链表中位置的所有方法。如果需要对集合进行随机访问,就使用数组或ArrayLister,而不要使用链表。
数组列表
散列集
有一种众所周知的数据结构,可以快速地查找所需要的对象,这就是散列表(hash table)。散列表为每个对象计算一个整数,称为散列码(hash code)。散列码是由对象地实例域产生的一个整数。更准确地说,具有不同数据域的对象将产生不同的散列码。
在Java中,散列表用链表数组实现。每个列表被称为桶(bucket)。
要想查找表中对象的位置,就要先计算它的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的桶的索引。当然,有时候会遇到桶被占满的情况,这也是不可避免地。这种现象被称为散列冲突(hash collision)。这时,需要用新对象与桶中的所有对象进行比较,查看这个对象是否已经存在。如果散列码是合理且随机分布的,桶的数目也足够大,需要比较的次数就会很少。
注释:在Java SE 8中,桶满时会从链表变为平衡二叉树。如果选择的散列函数不当,会产生很多冲突,或者如果有恶意代码视图在散列表中填充多个有相同散列码的值,这样就能提高性能。
如果想更多地控制散列表地运行性能,就要指定一个初始的桶数。桶数是指用于收集具有相同散列值的桶的数目。如果要插入到散列表中的元素太多,就会增加冲突的可能性,降低运行性能。入宫大致知道最终会有多少个元素要插入到散列表中,就可以设置桶数。通常,将桶数设置为预计元素个数的75%~150%。有些研究人员认为:尽管还没有确凿的证据,但最好将桶数设置为一个素数,以防键的集聚。
如果散列表太满,就需要再散列(rehashed)。如果对散列表再散列,就需要创建一个桶数更多的表,并将所有元素插入到这个新表中,然后丢弃原来的表。装填因子(load factor)决定何时对散列表进行再散列。
Java集合类库提供了一个HashSet类,它实现了基于散列表的集。可以用add方法添加元素。contains方法已经被重新定义,用来快速地查看是否某个元素已经出现在集中。散列表迭代器将依次访问所有的桶。由于散列将元素分散在表的各个位置上,所以访问他们的顺序几乎是随机的。
树集
TreeSet类与散列集十分类似,不过,它比散列集有所改进。树集是一个有序集合(sorted collection)。可以以任意顺序将元素插入到集合中。在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现。
树地排序必须是全序。也就是说,任意两个元素必须是可比的,并且只有在两个元素相等时结果才为0。
队列与双端队列
队列可以让人们有效地在尾部添加一个元素,在头部删除一个元素。有两个端头的队列,即双端队列,可以让人们有效地在头部和尾部同时添加或删除元素。不支持在队列中间添加元素。在Java SE 6中引入了Deque接口,并由ArrayDeque和LinkedList类实现。这两个类都提供了双端队列,而且在必要时可以增加队列的长度。
优先级队列
优先级队列(priority queue)中的元素可以按照任意的顺序插入,却总是按照排序的顺序进行检索。也就是说,无论何时调用remove方法,总会获得当前优先级队列中最小的元素。优先级队列使用了一个优雅且高效的数据结构,称为堆(heap)。堆是一个可以自我调整的二叉树,对树执行添加(add)和删除(remove)操作,可以让最小的元素移动到根,而不必花费时间对元素进行排序。
使用优先级队列的典型示例是任务调度。每个任务有一个优先级,任务以随机顺序添加到队列中。每当启动一个新的任务时,都将优先级最高的任务从队列中删除(由于习惯上将1设为“最高”优先级,所以会将最小的元素删除)。
Java核心技术-具体的集合的更多相关文章
- Java核心技术点之集合框架
1. 概述 Java集合框架由Java类库的一系列接口.抽象类以及具体实现类组成.我们这里所说的集合就是把一组对象组织到一起,然后再根据不同的需求操纵这些数据.集合类型就是容纳这些对象的一个容 ...
- java核心技术记录之集合
java库中的具体集合: 集合类型 描述 ArrayList 一种可以动态增长和缩减的索引序列 LinkedList 一种可以在任何位置进行高效地插入和删除操作的有序序列 ArrarDeque 一种用 ...
- [Java核心技术]第九章-集合(Java集合框架、具体的集合、映射)
9.1Java集合框架 一些有的没的 可以使用接口类型存放集合的引用.一旦改变了想法,只需要在调用构造函数的地方做一处修改. add方法用于向集合添加元素,如果添加元素确实改变了集合就返回true. ...
- [Java核心技术]第九章-集合(映射-HashMap&TreeMap)
HashMap 基本操作 HashMap<Integer,Integer> firstAccurMap=new HashMap<Integer,Integer>(); firs ...
- Java系列,《Java核心技术 卷1》,chapter 13,集合
13.1.2 Java类库中的集合接口和迭代器接口 删除元素,对于next和remove的调用是互相依赖的,如果调用remove之前没有调用next,则会跑出IllegalStateExcep ...
- Java核心技术卷一基础技术-第13章-集合-读书笔记
第13章 集合 本章内容: * 集合接口 * 具体的集合 * 集合框架 * 算法 * 遗留的集合 13.1 集合接口 Enumeration接口提供了一种用于访问任意容器中各个元素的抽象机制. 13. ...
- java核心技术之流与文件
InputStream和OutputStream构成了输入/输出类层次结构的基础.用于按字节进行读写.而与之处在同一等级的Reader/Writer同样作为抽象类定义了用于对字符进行读取的类层次结构, ...
- JAVA核心技术I---JAVA基础知识(工具类Arrays和Collections类)
一:工具类 –不存储数据,而是在数据容器上,实现高效操作 • 排序 • 搜索 –Arrays类 –Collection类 二:Arrays类(处理数组) (一)基本方法 –排序:对数组排序, sort ...
- 杨晓峰-Java核心技术-9 HashMap Hashtable TreeMap MD
目录 第9讲 | 对比Hashtable.HashMap.TreeMap有什么不同? 典型回答 考点分析 知识扩展 Map 整体结构 有序 Map HashMap 源码分析 容量.负载因子和树化 精选 ...
随机推荐
- 【变态需求】bootstrapTable列排序-选择正序倒序不排序
产品经理:那个table排序能不能点击后弹个选项选择正序倒序不排序? -- 那个是bootstrapTable的插件!不支持!改不了!! 注意:数据上假的,效果看http请求参数进行脑补 这是boot ...
- MATLAB找不到遗传算法工具箱,用不了gatool命令的解决方案
解决方案 官方解释如下: gatool was removed as of R2015b. Use optimtool 在MATLAB R2015b前的版本可以使用gatool调用遗传算法工具箱,我测 ...
- Centos6.9下RocketMQ3.4.6高可用集群部署记录(双主双从+Nameserver+Console)
之前的文章已对RocketMQ做了详细介绍,这里就不再赘述了,下面是本人在测试和生产环境下RocketMQ3.4.6高可用集群的部署手册,在此分享下: 1) 基础环境 ip地址 主机名 角色 192. ...
- windows如何查看电脑开关机记录
如何查看电脑开关机记录 (一)如果你只是想查看一下,从昨天关机到今天开机之间有没有人使用我的计算机,在“开始”菜单的运行”中输入“eventvwr.msc”,或者是按下"开始菜单" ...
- 结对编程 学习手记ver1.2
团队成员: 226 高雅智 164刘浩然: 一 结对编程 辛辛苦苦搞了好久的时间,就是没有人家的快,明明算法都差不多,哎~~~ 结对的优势,在于双方互相督促,对于代码能贡献自己的能力,人多力量 ...
- 个人作业 Last
对M1/M2阶段的总结 M1阶段的总结反思见我以前的博客,我以前曾经写过.现附上链接.http://www.cnblogs.com/jirufeng/p/4990245.html M2阶段主要是对我们 ...
- 《Linux内核设计与实现》 第八周读书笔记 第四章 进程调度
20135307 张嘉琪 第八周读书笔记 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有 ...
- ubuntu ftp服务
apt-get install vsftpd apt-get update vi /etc/apt/sources.list vim /etc/vsftpd.conf service vsftpd ...
- 转《canvas实现滤镜效果》
<code class="language-html"><html> <head> <style type="text/css& ...
- python使用原始套接字 解析原始ip头数据
使用底层套接字解码底层流量,是这次做的重点工作. 首先来捕获第一个包 # coding:utf-8import socket # 监听的主机IP host = "192.168.1.100& ...