Java语法进阶12-集合
集合
集合:是一种容器,用来装对象的容器,不能装基本数据类型。
数组也是容器,可以用来装基本数据类型,也可以用来装对象。
本质上,集合需要用对应的数据结构实现,是多个类实现接口collection系列和map接口的统称
collection
collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
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() | 返回一个迭代器对象,专门用于遍历集合 |
即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(元素的数据类型 变量 : collection集合or数组){
//写操作代码
}
java.lang.iterable接口,实现这个接口允许对象成为 "foreach" 语句的目标。
java.lang.iterable接口的抽象方法:
-
public iterator iterator(): 【获取对应的迭代器】
foreach本质上就是使用iterator迭代器进行遍历的。
所以也不要在foreach遍历的过程使用collection的remove()方法。
如果在iterator、listiterator迭代器创建后的任意时间从结构上修改了集合(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 concurrentmodificationexception。这就是iterator迭代器的快速失败(fail-fast)机制。
结构性修改是指:改变list的size大小,或者,以其他方式改变他导致正在进行迭代时出现错误的结果。
那么如何实现快速失败(fail-fast)机制的呢?
-
在arraylist等集合类中都有一个modcount变量。它用来记录集合的结构被修改的次数。
-
当我们给集合添加和删除操作时,会导致modcount++。
-
然后当我们用iterator迭代器遍历集合时,创建集合迭代器的对象时,用一个变量记录当前集合的modcount。例如:
int expectedmodcount = modcount;
,并且在迭代器每次next()迭代元素时,都要检查expectedmodcount != modcount
注意,迭代器的快速失败行为不能得到保证,
自定义类时如果一个实现类不希望提供fail-fast迭代器,则可以忽略这个字段。
-
-
它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
-
集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
arraylist:动态数组 vector:动态数组 linkedlist:双向链表 stack:栈
1、添加元素
-
void add(int index, e ele) 【在[index]位置添加一个元素】
-
boolean addall(int index, collection<? extends e> eles) 【在[index]位置添加多个元素】
2、获取元素
-
-
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、遍历
listiterator listiterator() 【默认游标在[0]开始】
listiterator listiterator(int index) 【默认游标在[index]位置】
-
-
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 集合中,则添加操作失败。
set集合支持的遍历方式和collection集合一样:foreach和iterator。
hashset 是 set 接口的典型实现,大多数时候使用 set 集合时都使用这个实现类。
java.util.hashset
底层的实现其实是一个java.util.hashmap
支持,然后hashmap的底层物理实现是一个hash表。
hashset/linkedhashset:
底层结构:里面维护了一个treemap,都是基于红黑树实现的!
特点: 1、不允许重复 2、实现排序, 自然排序或定制排序
如果使用的是自然排序(comparable),则通过调用实现的compareto方法
自然排序:它判断两个对象是否相等的唯一标准是:两个对象通过 compareto(t o) 方法比较返回值为0。
如果使用的是定制排序(comparator),则通过调用比较器的compare方法
collection
中的集合称为单列集合,map
中的集合称为双列集合。java.util.map<k,v>
1、存储键值对(key,value),也称为映射关系,键值对是map.entry接口的实现类对象。
2、所有存储到map中的key不能重复, 每个键只能对应一个值(这个值可以是单个值,也可以是个数组或集合值)。
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
视图】
若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
map的遍历,不能支持foreach
(1)分开遍历:
-
单独遍历所有key
-
单独遍历所有value
(2)成对遍历:
map接口的常用实现类:hashmap、treemap、linkedhashmap和properties。其中hashmap是 map 接口使用频率最高的实现类。
-
hashmap和hashtable都是哈希表。
-
-
hashtable是线程安全的,任何非 null 对象都可以用作键或值。不允许null键
-
hashmap是线程不安全的,并允许使用 null 值和 null 键。
linkedhashmap
treemap
properties
properties 类是 hashtable 的子类,properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
存取数据时,建议使用setproperty(string key,string value)方法和getproperty(string key)方法。
更多方法请见api文档
set集合与map集合的关系
咱们存到set中只有一个元素,又是怎么变成(key,value)的呢?
原来是,把添加到set中的元素作为内部实现map的key,然后用一个常量对象present对象,作为value。
上一篇: 水果摆盘技巧简单吗?教你几招满分套路!
下一篇: 男朋友不再爱你会有哪些表现呢?