九、集合框架—双列集合
1、Map集合
Map集合称为双列集合,格式: {key1=value1 , key2=value2 , key3=value3…,一次需要存一 对数据做为一 个元素。
Map集合的每个元素"key=value" 称为一个键值对/键值对对象/一个Entry对象, Map集合也被叫做"键值对集合”。
Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的, 每-个键只能找到自己对应的值。
Map集合系列特点:
Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的。
HashMap (由键决定特点) : 无序、不重复、无索引; (用的最多)
LinkedHashMap ( 由键决定特点) :有序、不重复、无索引。
TreeMap(由键决定特点):按照键按大小排序,默认升序排序,可排序,不重复、无索引
1.1 Map集合提供的常用方法
Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的。
方法名称 | 说明 |
---|---|
public V put( K key , V value ) | 添加元素 |
public int size( ) | 获取集合的大小 |
public void clear( ) | 清空集合 |
public boolean isEmpty() | 判断集合是否为空,为空返回:true,反之为:false |
public V get ( Object key ) | 根据键获取对应值 |
public V remove( Object key ) | 根据键删除整个元素 |
public boolean containsKey(Object key) | 判断是否包含某个键 |
public boolean containsValue( Object value ) | 判断是否包含某个值 |
public Set keySet( ) | 获取全部键的集合,返回一个Set集合 |
public Collection values( ) | 获取Map集合的全部值,返回一个Collection集合 |
public void putAll( Map map ) | 将Map集合的所有元素添加到,另一个集合中 |
public class MapDemo {
public static void main(String[] args) {
//创建一个 HashMap对象:无序、不重复、无索引的
//Map<键类型,值类型>
Map<String,Integer> map=new HashMap<>();
//添加数据
map.put("手机",1999);
map.put("电视",1999);
map.put("手表",399);
map.put("电脑",5500);
System.out.println(map); //{手表=399, 电脑=5500, 手机=1999, 电视=1999}
//判断map双列集合是否为空
System.out.println(map.isEmpty()); //false
//获取map的长度
System.out.println(map.size()); //4
//获取双列表的键值,返回类型为Set集合
Set<String> key=map.keySet();
System.out.println(key); //[手表, 电脑, 手机, 电视]
//获取双列表的所有的值,返回值类型为Collection
Collection<Integer> list=map.values();
System.out.println(list); //[399, 5500, 1999, 1999]
//根据键来获取值
System.out.println(map.get("电脑")); //5500
//判断双列表中是否包含对应的键
System.out.println(map.containsKey("手表")); //true
//判断双列表中是否包含对应的值
System.out.println(map.containsValue(399));//true
//创建一新的map集合
Map<String,Integer> map1=new HashMap<>();
map1.put("冰箱",2999);
//将map中所有的元素添加到map1中
System.out.println(map1); //{冰箱=2999}
map1.putAll(map);
System.out.println(map1); //{手表=399, 电脑=5500, 手机=1999, 冰箱=2999, 电视=1999}
//清空map中的所有元素
map.clear();
System.out.println(map); //{}
}
}
1.2、Map集合的遍历方式
方式一:键找值(先获取Map集合全部的键,再通过遍历键来找值 )
方式二:键值对(把“键值对“看成一个整体进行遍历(难度较大))
方式三:Lambda(jDK 1.8开始之后的新技术(非常的简单))
public class MapDemo02 {
public static void main(String[] args) {
Map<String,Integer> map =new HashMap<>();
//添加数据
map.put("手机",1999);
map.put("电视",1999);
map.put("手表",399);
map.put("电脑",5500);
System.out.println(map); //{手表=399, 电脑=5500, 手机=1999, 电视=1999}
//方式一:通过键找到值的方式来遍历
//第一步:通过KeySet方法来获取所有的键
Set<String> keys=map.keySet();
//第二步,通过增强for循环获取键,并通过get方法来遍历值
for (String key : keys) {
//获取值
int price=map.get(key);
System.out.println(key+"------"+price);
}
//方式二:调用Map集合提供entrySet方法,把Map 集合转换成键值对类型的Set集合
//第一步:将Map集合转换为Set集合
Set<Map.Entry<String,Integer>> entries=map.entrySet();
System.out.println(entries); //[手表=399, 电脑=5500, 手机=1999, 电视=1999]
//第二步:通过增强for循环,遍历set集合
for (Map.Entry<String, Integer> entry : entries) {
//提供Entry提供的getKey和getValue来获取对应的键和值
String key=entry.getKey();
Integer value=entry.getValue();
System.out.println(key+"-----"+value);
}
//方式三:通过Lambda方式遍历Map集合(k和v是随便定义的变量)
map.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String k, Integer v) {
System.out.println(k+"----"+v);
}
});
//缩写方式
map.forEach((k,v)->{
System.out.println(k+"----"+v);
});
}
}
案例:Map集合的案例-统计投票人数
需求:某个班级80名学生,现在需要组织秋游活动,班长提供了四个景点依次是(A、B、C、D) ,每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。
分析:
①将80个学生选择的数据拿到程序中去, [A,A,B,A,B, C,D,…]
②准备一个Map集合用于存储统计的结果,Map<String, Integer>, 键是景点,值代表投票数量。
③遍历80个学生选择的景点,每遍历一一个景点,就看Map集合中是否存在该景点,不存在存入“景点=1“存在则其对应值+1,
public class MapCount {
public static void main(String[] args) {
//调用学生进行投票(传入学生数量,返回值为学生投完票的集合)
List<String> list=studentVote(80);
//学生随机投票的的结果
System.out.println(list); //[C, A, D, B, A, A, C, C, C, B,...]
//对投票进行统计处理(传入list集合,返回值为一个map集合)
Map<String,Integer> map=studentVoteCount(list);
//展示随机投票进行统计后的结果
System.out.println(map); //{A=19, B=17, C=20, D=24}
}
//通过studentVote方法获取学生的投票信息
public static List<String> studentVote(int count){
//创建一个List集合,用来装学生投的票
List<String> list=new ArrayList<>();
//创建一个随机数,将用来产生count个随机投票
Random random=new Random();
for (int i = 0; i < count; i++) {
//通过随机数来产生65-68的整数(分别是A-D的AscII码)
int option= random.nextInt(4)+65;
//将数值型类型转换为String类型的数据(先要将数值转换为char类型的A)
//也可以:String vote=(char)option+"";
String vote=String.valueOf((char)option);
//将产生的随机数添加到List集合中去
list.add(vote);
}
return list;
}
//统计学生们投票的票数
public static Map<String,Integer> studentVoteCount(List<String> list){
//创建一个Map集合,用来统计学生对各个景区的投票数
Map<String,Integer> map=new HashMap<>();
//通过遍历list集合,获取到各个投票,进行统计
for (String vote : list) {
//判断map集合是否有vote对应的key,有就把原来的value+1,并把原来的替换掉(因为HashMap的键不能重复)
//没有就添加对应的key和投票数量1
if(map.containsKey(vote)){
int value=map.get(vote)+1;
map.put(vote,value);
}else {
map.put(vote,1);
}
}
return map;
}
}
2、HashMap 集合
特点:HashMap (由键决定特点) :无序、不重复、无索引; (用的最多 )
原理:HashMap跟HashSet的底层原理是一模一 样的,都是基于哈希表实现的。
实际上:原来学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。
jDK8之前,哈希表=数组+链表
jDK8开始,哈希表=数组+链表+红黑树
哈希表是一种增删改查数据,性能都较好的数据结构,所有HashMap也是。
注意:
HashMap的键依赖hashCode方法和equals方法保证键的唯一。
如果键存储的是自定义类型的对象,可以通过重写hashCode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的。
操作方法:在实体类中,右击》Generate》equals() and hashCode()》一直next
3、LinkedHashMap 集合
特点:LinkedHashMap ( 由键决定特点) :有序、不重复、无索引。
原理:底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表 的机制记录元素顺序(保证有序)。
实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap.
通过双链表机制的,首指针和尾指针来记录元素顺序。
public class LinkedHashMapDemo {
public static void main(String[] args) {
Map<String,String> map=new LinkedHashMap<>();
map.put("小明","篮球");
map.put("小天","足球");
map.put("小花","排球");
map.put("小刚","篮球");
System.out.println(map); //输出结果是有序的:{小明=篮球, 小天=足球, 小花=排球, 小刚=篮球}
}
}
4、TreeMap 集合
特点:TreeMap ( 由键决定特点) :按照大小默认升序排序、不重复、无索引。
原理:TreeMap跟TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。
TreeMap集合同样也支持两种方式来指定排序规则
方式一:让类实现Comparable接口,重写compareTo()方法比较规则。
方式二:TreeMap集合有 一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。
5、补充知识-集合的嵌套
定义:指的是集合中的元素又是一个集合。
5.1 Map集合案例-省和市
需求:要求在程序中记住如下省份和其对应的城市信息,记录成功后,要求可以查询出湖北省的城市信息。
分析:定义一个Map集合,键用表示省份名称,值表示城市名称,注意:城市会有多个。
public class Test {
public static void main(String[] args) {
//1、定义一个Map集合存储全部的省份信息,和其对应的城市信息。
Map<String, List<String>> map=new HashMap<>();
//2、创建一个List集合将城市信息放到集合中
List<String> cities1=new ArrayList<>();
//2.1、将城市信息存入到list集合中
Collections.addAll(cities1,"南京市", "扬州市", "苏州市","无锡市", "常州市");
//3、将城市信息存入对应的省份Map集合中
map.put("江苏省",cities1);
//2、创建一个List集合将城市信息放到集合中
List<String> cities2=new ArrayList<>();
//2.1、将城市信息存入到list集合中
Collections.addAll(cities2,"武汉市", "孝感市", "十堰市","宜昌市", "鄂州市");
//3、将城市信息存入对应的省份Map集合中
map.put("湖北省",cities2);
//2、创建一个List集合将城市信息放到集合中
List<String> cities3=new ArrayList<>();
//2.1、将城市信息存入到list集合中
Collections.addAll(cities3,"石家庄市","唐山市","邢台市","保定市","张家口市");
//3、将城市信息存入对应的省份Map集合中
map.put("河北省",cities3);
System.out.println(map);
//{江苏省=[南京市, 扬州市, 苏州市, 无锡市, 常州市], 湖北省=[武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市], 河北省=[石家庄市, 唐山市, 邢台市, 保定市, 张家口市]}
//查询湖北省的各个城市
List<String> hb=map.get("湖北省");
System.out.println(hb); //[武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市]
//遍历整个map
map.forEach((k,v)->{
System.out.println(k+"----"+v);
});
/*江苏省----[南京市, 扬州市, 苏州市, 无锡市, 常州市]
湖北省----[武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市]
河北省----[石家庄市, 唐山市, 邢台市, 保定市, 张家口市]*/
}
}