欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java语法进阶12-集合

程序员文章站 2023-11-02 16:18:34
集合 集合:是一种容器,用来装对象的容器,不能装基本数据类型。 数组也是容器,可以用来装基本数据类型,也可以用来装对象。 本质上,集合需要用对应的数据结构实现,是多个类实现接口Collection系列和Map接口的统称 Collection Collection 表示一组对象,这些对象也称为 col ......

集合

集合:是一种容器,用来装对象的容器,不能装基本数据类型。

数组也是容器,可以用来装基本数据类型,也可以用来装对象。

本质上,集合需要用对应的数据结构实现,是多个类实现接口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迭代器删除元素】

Java语法进阶12-集合

在调用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接口特点:

  1. 它是一个元素存取有序的集合。即元素的存入顺序和取出顺序有保证。

  2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。

  3. 集合中可以有重复的元素,通过元素的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):                                                                     【用指定元素替换 nextprevious 返回的最后一个元素】

  • void remove():                                                                   【从列表中移除由 nextprevious 返回的最后一个元素】

  • 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系列的集合框架图

Java语法进阶12-集合

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的实例化对象

Java语法进阶12-集合

 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工具类