集合概述
集合框架体系,Collection接口,Map接口,Collections工具类
Author: Msuenb
Date: 2023-02-17
集合是 Java 中提供的一种容器,可以用来存储多个数据。
数组也是容器,但相较于集合,数组有些不足之处:
- 数组的长度是固定的。集合的长度是可变的。
- 数组保存的必须是同一类型(或兼容) 的元素
- 数组的添加和删除元素操作比较麻烦
集合主要分为两大系列:Collection(单列集合)和Map(双列集合),Collection 表示一组对象,Map 表示一组映射关系或键值对。
Collection 和 Map 集合体系如下图:
Collection接口
Collection 表示一组对象,这些对象也称为 collection 的元素。
- 一些 collection 允许有重复的元素,而另一些则不允许;一些 collection 是有序的,而另一些则是无序的。
- JDK 不提供此接口的任何直接实现,而是提供更具体的子接口(如 Set 和 List、Queue)实现。
Collection常用API
Collection 是所有单列集合的父接口,在 Collection 中定义了单列集合(List、Set)通用的一些方法,这些方法可用于操作所有的单列集合。常用方法如下:
- add(E obj):添加单个元素
- addAll(Collection<? extends E> other):添加多个元素
- boolean remove(Object obj) :删除指定元素
- boolean removeAll(Collection<?> coll):删除多个元素
- boolean isEmpty():判断当前集合是否为空集合。
- boolean contains(Object obj):判断指定元素是否存在
- boolean containsAll(Collection<?> c):判断多个元素是否都存在
- int size():获取当前集合中实际存储的元素个数
- void clear():清空集合
由于 Collection 没有任何直接实现类,这里以 ArrayList 实现类演示
public class CollectionAPITest {
public static void main(String[] args) {
Collection coll = new ArrayList();
// 添加单个元素
coll.add("jack");
coll.add(10); // 相当于 coll.add(new Integer(10))
coll.add(true);
System.out.println(coll);
// 添加多个元素
Collection c = new ArrayList();
c.add("tom");
c.add("jerry");
coll.addAll(c);
System.out.println(coll);
// 判断是否包含指定元素
boolean b = coll.contains("tom");
System.out.println(b);
// 判断是否包含多个元素
boolean b1 = coll.containsAll(c);
System.out.println(b1);
// 获取当前集合元素个数
int size = coll.size();
System.out.println(size);
// 删除指定元素
coll.remove("tom");
System.out.println(coll);
// 删除多个元素
coll.removeAll(c);
System.out.println(coll);
// 清空集合
coll.clear();
// 判断集合是否为空集合
System.out.println(coll.isEmpty());
}
}
Iterator迭代器
Iterator 接口也是 Java 集合中的一员,但它与Collection、Map接口有所不同,Collection接口与Map接口主要用于存储元素,而 Iterator 主要用于迭代访问(遍历) Collection 中的元素,因此 Iterator 对象也被称为迭代器。
遍历 Collection 集合,需要获取该集合迭代器,然后完成迭代操作:
-
public Iterator iterator()
:获取集合对应的迭代器,用来遍历集合中的元素的。 -
public boolean hasNext()
:判断是否有下一个元素可以迭代,有则返回 true。 -
public E next()
:返回迭代的下一个元素。
Iterator 迭代集合中元素演示:
public class IteratorTest {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("tom");
coll.add("jerry");
coll.add("smith");
Iterator iterator = coll.iterator(); // 获取迭代器对象
while(iterator.hasNext()) { // 判断是否还有元素可迭代
System.out.println(iterator.next()); // 取出下一个元素
}
}
}
增强for循环
java.lang.Iterable 接口还提供了一个forEach
默认方法,用于完成集合元素的迭代。 Collection 接口继承了 java.lang.Iterable 接口,因此Collection系列的集合就可以直接使用 foreach 循环遍历。
foreach 循环的语法格式:
for(元素类型 元素名 : 集合名){
}
//这里元素名就是一个临时变量,自己命名就可以
使用演示:
Collection coll = new ArrayList();
coll.add("tom");
coll.add("jerry");
coll.add("smith");
for (Object o : coll) {
System.out.println(o);
}
对于集合类型来说,foreach 循环其实就是使用 Iterator 迭代器来完成元素的遍历的。
Java中的数组也支持这种语法糖。只不过编译器在处理 foreach 遍历数组时,是转换为普通for循环的。
List接口
java.util.List
接口继承自 Collection 接口,是单列集合的一个重要分支,习惯将实现了 List 接口的对象称为List集合。
List的常用实现类有:ArrayList、Vector、LinkedList、Stack等。
List接口特点:
- List集合所有的元素是以一种线性方式进行存储的
- 它是一个元素存取有序的集合。即元素的存入顺序和取出顺序有保证。
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
- 集合中可以有重复的元素
List 作为 Collection 集合的子接口,不但继承了 Collection 接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:
- void add(int index, E ele):把元素添加到指定位置
- boolean addAll(int index, Collection<? extends E> eles):把一组元素添加到指定位置
- E remove(int index):删除指定位置的元素
- E set(int index, E ele):替换 [index] 位置的元素
- E get(int index):返回[index]位置的元素
- List subList(int fromIndex, int toIndex):返回[fromIndex, toIndex)范围的元素
- int indexOf(Object obj):查询obj在列表中的位置,如果有重复,返回第1个
- int lastIndexOf(Object obj):查询obj在列表中的位置,如果有重复,返回最后1个
示例代码:
import java.util.ArrayList;
import java.util.List;
public class ListAPITest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("hello");
list.add("java");
list.add("world");
list.add("mysql");
list.add("java");
// 添加元素到指定位置
list.add(2, "tom");
System.out.println(list);
// 添加一组元素到指定位置
List list1 = new ArrayList();
list.add("jerry");
list.add("smith");
list.addAll(3, list1);
System.out.println(list);
// 替换指定位置元素
list.set(2, "zhangsan");
System.out.println(list);
// 返回指定位置的元素
Object o = list.get(2);
System.out.println(o);
// 删除指定位置元素
list.remove(2);
System.out.println(list);
// 返回指定范围[from, to)的元素
List list2 = list.subList(5, 7);
System.out.println(list2);
// 查询元素首次出现的位置
int java = list.indexOf("java");
System.out.println(java);
// 查询元素最后一次出现的位置
int java1 = list.lastIndexOf("java");
System.out.println(java1);
}
}
Set接口
Set 接口是 Collection 的子接口,Set 接口没有提供额外的方法。
-
Set 集合不允许包含相同的元素,即元素不可重复。
-
Set 集合支持的遍历方式和 Collection 集合一样:foreach 和 Iterator。
-
Set 的常用实现类有:HashSet、TreeSet、LinkedHashSet 等。
import java.util.HashSet;
public class TestSet {
public static void main(String[] args){
HashSet set = new HashSet();
set.add("hello");
set.add("java");
set.add("hello"); // 添加不成功
System.out.println(set);
}
}
HashSet 和 LinkedHashSet 元素不可重复是依赖于 equals 和 hashCode 方法
TreeSet 元素不可重复是依赖于元素大小关系的。
要么元素类型实现 Comparable 接口,重写 compareTo 方法,
要么创建 TreeSet 时,指定 Comparator 接口实现类对象,重写 compare 方法
Map
像IP地址与主机名,身份证号与个人等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map<K,V>
接口。
Map 接口下的集合与 Collection 接口下的集合,它们存储数据的形式不同。
- Collection 中的集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储。
- Map 中的集合,元素是成对存在的。每个元素由键与值两部分组成,通过键可以找对所对应的值。
- Collection 中的集合称为单列集合,Map 中的集合称为双列集合。
- 需要注意的是,
Map
中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。
Map常用方法:
-
V put(K key,V value):添加一对键值对
-
void putAll(Map<? extends K,? extends V> m):添加一组键值对
-
void clear():清空map
-
V remove(Object key):根据key删除一对键值对
-
default V replace(K key, V value):找到目标key,替换value
-
V get(Object key):根据key返回value
-
boolean containsKey(Object key):判断key是否存在
-
boolean containsValue(Object value):判断value是否存在
-
boolean isEmpty():判断map是否为空
-
int size():获取键值对的数量
public class MapAPITest {
public static void main(String[] args) {
//创建 map对象
HashMap<String, String> map = new HashMap<String, String>();
//添加元素到集合
map.put("黄晓明", "杨颖");
map.put("文章", "马伊琍");
map.put("文章", "姚笛");
map.put("邓超", "孙俪");
System.out.println(map.size());
System.out.println(map);
//删除键值对
map.remove("文章");
System.out.println(map);
//修改value
map.replace("文章","马伊琍");
System.out.println(map);
// 替换指定 key 对应的value
map.replace("黄晓明", "angelababy");
System.out.println(map);
// 查看key 对应的value
System.out.println(map.get("黄晓明"));
}
}
注意:Map<K,V>中,key可以为null,但只能有一个;value也可以为null,可以有多个。
map.put(null, "jerry");
map.put(null, null); // key重复 替换value
map.put("cat", null); // value 可以重复
Map集合遍历
Map不能支持foreach遍历,因为Map接口没有继承java.lang.Iterable接口,也没有实现Iterator iterator()方法。只能用如下方式遍历:
-
分开遍历:
-
单独遍历所有key:Set keySet()
-
单独遍历所有value:Collection values()
-
-
成对遍历:
-
遍历所有键值对:Set<Map.Entry<K,V>> entrySet()
-
遍历的是映射关系Map.Entry类型的对象,Map.Entry是Map接口的内部接口。每一种Map内部有自己的Map.Entry的实现类。在Map中存储数据,实际上是将Key---->value的数据存储在Map.Entry接口的实例中,再在Map集合中插入Map.Entry的实例化对象。
-
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapIterateTest {
public static void main(String[] args) {
Map map = new HashMap();
map.put("许仙", "白娘子");
map.put("董永", "七仙女");
map.put("牛郎", "织女");
map.put("许仙", "小青");
System.out.println("所有的key: ");
Set set = map.keySet();
for (Object o : set) {
System.out.print(o + " ");
}
System.out.println("所有的value: ");
Collection values = map.values();
for (Object value : values) {
System.out.print(value + " ");
}
System.out.println("所有的映射关系: ");
Set entrySet = map.entrySet();
for (Object entry : entrySet) {
System.out.println(entry);
}
}
}
Collections工具类
参考操作数组的工具类:Arrays。
Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:
- public static boolean addAll(Collection<? super T> c,T... elements):将所有指定元素添加到指定 collection 中。
- public static int binarySearch(List<? extends Comparable<? super T>> list,T key):在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
- public static int binarySearch(List<? extends T> list,T key,Comparator<? super T> c):在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。
- public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll):在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
- public static T max(Collection<? extends T> coll,Comparator<? super T> comp):在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
- public static void reverse(List<?> list):反转指定列表List中元素的顺序。
- public static void shuffle(List<?> list):List 集合元素进行随机排序,类似洗牌
- public static <T extends Comparable<? super T>> void sort(List list):根据元素的自然顺序对指定 List 集合元素按升序排序
- public static void sort(List list,Comparator<? super T> c):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- public static void swap(List<?> list,int i,int j):将指定 list 集合中的 i 处元素和 j 处元素进行交换
- public static int frequency(Collection<?> c,Object o):返回指定集合中指定元素的出现次数
- public static void copy(List<? super T> dest,List<? extends T> src):将src中的内容复制到dest中
- public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值
- Collections 类中提供了多个 synchronizedXxx():该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
- Collections类中提供了多个unmodifiableXxx():该方法返回指定 Xxx的不可修改的视图。
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class CollectionsTest {
@Test
public void test01() {
// addAll
Collection coll = new ArrayList();
Collections.addAll(coll, "hello", "java");
Collections.addAll(coll, 1, 2, 3);
System.out.println(coll);
}
@Test
public void test02() {
List list = new ArrayList();
Collections.addAll(list, "hello","world","java","php", "hello");
Collections.sort(list); // String 实现了Comparable接口
System.out.println(list);
// 反转
Collections.reverse(list);
System.out.println(list);
// 重洗
Collections.shuffle(list);
System.out.println(list);
// 交换
Collections.swap(list, 1, 2);
System.out.println(list);
// 指定元素出现次数
int hello = Collections.frequency(list, "hello");
System.out.println(hello);
}
@Test
public void test03() {
// 复制元素
List<Integer> list = new ArrayList<>();
for(int i=1; i<=5; i++){//1-5
list.add(i);
}
List<Integer> list2 = new ArrayList<>();
for(int i=11; i<=13; i++){//11-13
list2.add(i);
}
Collections.copy(list, list2);
System.out.println(list);
}
@Test
public void test4(){
List<String> list = new ArrayList<>();
Collections.addAll(list,"hello","java","world","hello","hello");
Collections.replaceAll(list, "hello","chai");
System.out.println(list);
}
}