Java语法进阶12-集合
集合
集合:是一种容器,用来装对象的容器,不能装基本数据类型。
数组也是容器,可以用来装基本数据类型,也可以用来装对象。
本质上,集合需要用对应的数据结构实现,是多个类实现接口Collection系列和Map接口的统称
Collection
Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
Collection<E>是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。
Collection方法:
序号 | 归类 | 方法签名 | 方法描述 |
---|---|---|---|
1 | 添加 | add(E e) | 添加一个元素对象到当前集合中 |
2 | 添加 | addAll(Collection<? extends E> other) | 添加多个元素,把other集合的所有元素都添加到当前集合中,this = this ∪ other; |
3 | 删除 | clear() | 清空集合 |
4 | 删除 | remove(Object obj) | 删除一个元素,根据元素的equals()来判断是否是要被删除的元素,如果元素的类型没有重写equals方法,那么等价于==,如果重写了equals,那么就按照equals的规则来比较,一般比较内容。 |
5 | 删除 | removeAll(Collection<?> coll) | 删除多个元素,把当前集合中和c共同的元素删除,即this = this - this ∩ coll;子集 |
6 | 删除 | retainAll(Collection<?> coll) | 删除多个元素,在当前集合中保留和c的共同的元素,即this = this ∩ coll;交集 |
7 | 查 | int size() | 获取元素的个数 |
8 | 查 | boolean contains(Object obj) | 是否包含某个元素。根据元素的equals()来判断是否是要被删除的元素,如果元素的类型没有重写equals方法,那么等价于==,如果重写了equals,那么就按照equals的规则来比较,一般比较内容。 |
9 | 查 | boolean containsAll(Collection<?> coll) | 是否包含多个元素。判断当前集合中是否包含coll集合的所有元素,即coll是否是this的子集。 |
10 | 查 | boolean isEmpty() | 集合是否为空 |
11 | 遍历 | Object[] toArray() | 将集合中的元素用数组返回 |
12 | 遍历 | Iterator iterator() | 返回一个迭代器对象,专门用于遍历集合 |
Iterator迭代器
即Collection集合元素的通用获取方式。每一种实现了Iterable接口的集合内部,都会有一个内部类实现了Iterator接口
public boolean hasNext()
【如果仍有元素可以迭代,则返回 true。】public E next()
【返回迭代的下一个元素。】
- void remove() 【使用Iterator迭代器删除元素】
在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,指向第一个元素,当第一次调用迭代器的next方法时,返回第一个元素,然后迭代器的索引会向后移动一位,指向第二个元素,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
在进行集合元素取出时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会发生java.util.NoSuchElementException没有集合元素的错误
注意:不要在使用Iterator迭代器进行迭代时,调用Collection的remove(xx)方法,否则会报异常java.util.ConcurrentModificationException,或出现不确定行为。
增强for
增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的,或者说实现了Iterable接口的其他容器名。
for(元素的数据类型 变量 : Collection集合or数组){
//写操作代码
}
Iterable接口
java.lang.Iterable接口,实现这个接口允许对象成为 "foreach" 语句的目标。
java.lang.Iterable接口的抽象方法:
public Iterator iterator(): 【获取对应的迭代器】
foreach本质上就是使用Iterator迭代器进行遍历的。
所以也不要在foreach遍历的过程使用Collection的remove()方法。
modCount
如果在Iterator、ListIterator迭代器创建后的任意时间从结构上修改了集合(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 ConcurrentModificationException。这就是Iterator迭代器的快速失败(fail-fast)机制。
结构性修改是指:改变list的size大小,或者,以其他方式改变他导致正在进行迭代时出现错误的结果。
那么如何实现快速失败(fail-fast)机制的呢?
在ArrayList等集合类中都有一个modCount变量。它用来记录集合的结构被修改的次数。
当我们给集合添加和删除操作时,会导致modCount++。
然后当我们用Iterator迭代器遍历集合时,创建集合迭代器的对象时,用一个变量记录当前集合的modCount。例如:
int expectedModCount = modCount;
,并且在迭代器每次next()迭代元素时,都要检查expectedModCount != modCount
注意,迭代器的快速失败行为不能得到保证,因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测 bug。
自定义类时如果一个实现类不希望提供fail-fast迭代器,则可以忽略这个字段。
List
List接口特点:
它是一个元素存取有序的集合。即元素的存入顺序和取出顺序有保证。
它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
List集合关心元素是否有序,而不关心是否重复
List接口的实现类有很多,常见的有:
ArrayList:动态数组 Vector:动态数组 LinkedList:双向链表 Stack:栈
List除了从Collection集合继承的方法外,List 集合里添加了一些根据索引来操作集合元素的方法。
1、添加元素
void add(int index, E ele) 【在[index]位置添加一个元素】
boolean addAll(int index, Collection<? extends E> eles) 【在[index]位置添加多个元素】
2、获取元素
E get(int index) 【返回[index]位置的元素】
List subList(int fromIndex, int toIndex) 【截取[fromIndex,toIndex)部分的元素】
3、获取元素索引
int indexOf(Object obj) 【返回obj在当前集合中第一次出现的下标】
int lastIndexOf(Object obj) 【返回obj在当前集合中最后一次出现的下标】
4、删除和替换元素
E remove(int index) 【删除[index]位置的元素,返回被删除的元素】
E set(int index, E ele) 【替换[index]位置的元素,返回被替换的元素】
5、遍历
在原来Iterator和foreach遍历的基础上增加了:
ListIterator listIterator() 【默认游标在[0]开始】
ListIterator listIterator(int index) 【默认游标在[index]位置】
ListIterator
List 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法:
void add(): 【通过迭代器添加元素到对应集合】
void set(E e): 【用指定元素替换 next 或 previous 返回的最后一个元素】
void remove(): 【从列表中移除由 next 或 previous 返回的最后一个元素】
boolean hasPrevious(): 【如果以逆向遍历列表,往前是否还有元素。则返回 true】
E previous(): 【返回列表中的前一个元素。】
int previousIndex(): 【返回列表中的前一个元素的索引】
boolean hasNext() 【以正向遍历列表时,如果列表迭代器有多个元素,则返回 true】
E next() 【返回列表中的下一个元素。】
int nextIndex() 【返回对 next 的后续调用所返回元素的索引。】
Set
set接口没有提供额外的方法。但是比Collection
接口更加严格了。
Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
Set集合支持的遍历方式和Collection集合一样:foreach和Iterator。
Set集合的实现类:TreeSet:按大小顺序,LinkedHashSet:按照添加的顺序,HashSet:无序
HashSet
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
java.util.HashSet
底层的实现其实是一个java.util.HashMap
支持,然后HashMap的底层物理实现是一个Hash表。
HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。
LinkedHashSet
LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。java.util.LinkedHashSet
,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
HashSet/LinkedHashSet:如何区别元素的不可重复。依赖于元素的hashCode和equals方法
TreeSet
底层结构:里面维护了一个TreeMap,都是基于红黑树实现的!
特点: 1、不允许重复 2、实现排序, 自然排序或定制排序
如果使用的是自然排序(Comparable),则通过调用实现的compareTo方法
自然排序:它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(T o) 方法比较返回值为0。
如果使用的是定制排序(Comparator),则通过调用比较器的compare方法
定制排序:使用定制排序判断两个元素相等的标准是:通过compare(T o1,T o2)比较两个元素返回了0。
如果希望保持一致性,在重写compareTo时,一般也会重写equals方法。不是语法要求,而且逻辑意义问题。
Collection系列的集合框架图
Map
Collection
中的集合称为单列集合,Map
中的集合称为双列集合。java.util.Map<K,V>
1、存储键值对(key,value),也称为映射关系,键值对是Map.Entry接口的实现类对象。
2、所有存储到Map中的key不能重复, 每个键只能对应一个值(这个值可以是单个值,也可以是个数组或集合值)。
3、所有存储到Map中的value可以重复
Map接口的API
1、添加
V put(K key, V value): 【将一对键值对添加到当前map中,同一个key如果put两次,第二次会覆盖上次的value】
void putAll(Map m): 【将另一个map中的所有键值对添加到当前map中】
2、删除
void clear(): 【清空所有映射关系】
V remove(Object key): 【根据key删除一整对键值对(key,value)】
3、查询
int size(): 【返回键值对的数量】
boolean containsKey(Object key): 【是否包含某个key】
boolean containsValue(Object value): 【是否包含某个value】
V get(Object key): 【根据key获取value值,如果此映射不包含该键的映射关系,则返回 null
。】
boolean isEmpty() 【如果此映射未包含键-值映射关系,则返回 true。】
4、遍历
Set<Entry<K,V>> entrySet() 【遍历所有的键值对,映射关系的 Set
视图 】
Set<K> keySet() 【遍历所有的key,键的 Set
视图】
Collection<V> values() 【遍历所有的value,值的 Collection
视图】
使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
Map集合的遍历
Map的遍历,不能支持foreach
(1)分开遍历:
单独遍历所有key
单独遍历所有value
(2)成对遍历:
遍历的是映射关系Map.Entry类型的对象,Map.Entry是Map接口的内部接口。每一种Map内部有自己的Map.Entry的实现类。在Map中存储数据,实际上是将Key---->value的数据存储在Map.Entry接口的实例中,再在Map集合中插入Map.Entry的实例化对象
Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties。其中HashMap是 Map 接口使用频率最高的实现类。
HashMap和Hashtable的区别与联系
HashMap和Hashtable都是哈希表。
HashMap和Hashtable判断两个 key 相等的标准是:两个 key 的hashCode 值相等,并且 equals() 方法也返回 true。因此,为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。
Hashtable是线程安全的,任何非 null 对象都可以用作键或值。不允许null键
HashMap是线程不安全的,并允许使用 null 值和 null 键。
LinkedHashMap
LinkedHashMap 是 HashMap 的子类。LinkedHashMap实现与 HashMap 的不同之处在于,LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。
TreeMap
基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
Properties
Properties 类是 Hashtable 的子类,Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。
更多方法请见API文档
Set集合与Map集合的关系
Set的内部实现其实是一个Map。即HashSet的内部实现是一个HashMap,TreeSet的内部实现是一个TreeMap,LinkedHashSet的内部实现是一个LinkedHashMap。
咱们存到Set中只有一个元素,又是怎么变成(key,value)的呢?
原来是,把添加到Set中的元素作为内部实现map的key,然后用一个常量对象PRESENT对象,作为value。
集合框架图
Collections工具类
Java语法进阶12-集合的更多相关文章
- Java面试进阶部分集合
框架基础 反射:反射是Java开发的一类动态相关机制.因为本身Java语言并不是一款动态语言,如果我们想要得到程序动态的效果,因此便引入了反射机制这一概念. 怎么表达反射? 能用反射做什么? PS:某 ...
- Java语法进阶13-文件、IO流
File File是文件和目录路径名的抽象表示形式,即File类是文件或目录的路径,而不是文件本身,因此File类不能直接访问文件内容本身,如果需要访问文件内容本身,则需要使用输入/输出流. File ...
- Java语法进阶10-泛型
泛型 泛型:参数化的类型,即把数据类型当做参数来传递 有的地方又称为泛化的类型,用一个单个大写字母,例如<T>来代表任意类型,这个T就是泛化的类型. 泛型的好处: (1)表示某个变量的类型 ...
- Java语法进阶16-Lambda-Stream-Optional
Lambda 大年初二,大门不出二门不迈.继续学习! 函数式接口 Lambda表达式其实就是实现SAM接口的语法糖,所谓SAM接口就是Single Abstract Method,即该接口中只有一个抽 ...
- Java学习日记-12 集合(2)
一.List<E>接口(超级接口Collection,List比Collection多重载了一些索引作为形参的方法)1.实现类ArrayList\LinkedListArrayList顺序 ...
- Java语法进阶10-多线程
多线程 并发与并行.进程,线程调度自行百度 线程(thread):是一个进程中的其中一条执行路径,CPU调度的最基本调度的单位.同一个进程中线程可以共享一些内存(堆.方法区),每一个线程又有自己的独立 ...
- Java语法进阶14-网络编程
网络编程 软件结构 C/S结构 :全称为Client/Server结构,是指客户端和服务器结构. B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构. 网络通信协议 网络通信 ...
- Java语法糖1:可变长度参数以及foreach循环原理
语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...
- Java语法知识总结
一:java概述: 1991 年Sun公司的James Gosling等人开始开发名称为 Oak 的语言,希望用于控制嵌入在有线电视交换盒.PDA等的微处理器: 1994年将Oak语言更名为Java: ...
随机推荐
- [考试反思]1012csp-s模拟测试70:盘旋
这套题比较烂... 上来看到T2是原题,一想上一次考试遇到原题就不换,这次应该也是,于是直接开始码,码了一半然后换题了 T1打表找规律或者推式子都不难... T2水的一匹暴力剪枝即可,但是我并不知道数 ...
- [考试反思]0818NOIP模拟测试25:清心
两机房分开考试.拿到了令人orz的A卷. 15本校+3外校=18人参加 排名第7,没前途.大不了去第二机房... skyh也很强了.tdcp拿来一个诡异的. 86,85,79.然后是我垃圾的.在后面差 ...
- NOIP模拟 14
垃圾成绩,一点都不稳定. 如果把数组开小的分得到的话..总分还挺不错.. 那又能怪谁,都快NOIP了还犯这种傻逼错误 nc哥是要阿卡的节奏..真是太强了 某kyh也不知道偷了谁的rp,分高的一批 wd ...
- python模块——socket
实例一. server: #socket套接字(IP + 端口号)(qq,wechat 发送接收消息依靠socket模块),cs架构import socketserver = socket.socke ...
- python中文件的基础操作
打开文件的三种方式: open(r'E:\学习日记\python\code\文件的简单操作.py') open('E:\\学习日记\\python\\code\\文件的简单操作.py') open(' ...
- static静态关键字
转载自大佬:https://www.cnblogs.com/xrq730/p/4820992.html 静态资源和静态方法 首先,静态的资源和方法等会随着类的加载而进入内存被初始化,而非静态的资源和方 ...
- Java虚拟机-字节码指令
目录 字节码指令 字节码与数据类型 加载和存储指令 运算指令 类型转换指令 对象创建与访问指令 操作数栈管理指令 控制转移指令 方法调用和返回指令 异常处理指令 同步指令 字节码指令 Java虚拟机的 ...
- 本地yum配置
yum yum(Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及 CentOS 中的 Shell 前端软件包管理器.基于 RPM 包管理,能够从 ...
- 关于RAID 10的介绍与创建
一.RAID 10的简介 定义: RAID10也被称为镜象阵列条带.象RAID0一样,数据跨磁盘抽取:象RAID1一样,每个磁盘都有一个镜象磁盘, 所以RAID 10的另一种会说法是 RAID 0+1 ...
- 🔥「课代表」帮你总结了全网最全的Redis知识点
你知道的越多,你不知道的越多 点赞再看,养成习惯 GitHub上已经开源 https://github.com/JavaFamily 有一线大厂面试点脑图.个人联系方式和人才交流群,欢迎Star和指教 ...