Map集合概述
概念
- Map存储在软件包java.util包下,使用需要导包
- interface Map<K,V>——集合的泛型,K表示Map集合中存储键的类型;V表示Map集合中存储值的类型
- Map集合是将键映射到值的对象;不能有重复的键;每个键最多可以映射一个值
- 有序与无序性指的是:元素存储是否按照元素的添加顺序。Map是无序的,存储结构是哈希表键值对,插入元素是根据key计算出来的哈希值来存储元素的,因此不是按照元素的添加顺序来存储对象的。
创建Map集合对象
- 采用多态的形式 接口 对象名 = new 实现类名();
- 具体实现类有 HashMap、LinkedHashMap、HashTable、TreeMap。
案例:验证添加相同的key,value会被覆盖
注意
当多次添加的内容具有相同的键时,会将键的内容覆盖。
// 218-
public class MapDemo {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String, String>();
map.put("001", "汪苏泷");
map.put("002", "周杰伦");
map.put("003","林俊杰");
// 由于不允许有重复的键,所以当再添加重复键的时候,会将前者值覆盖
map.put("001", "许嵩");
System.out.println(map);
// 输出:{001=汪苏泷, 002=周杰伦, 003=林俊杰}
// 添加 许嵩后,输出:{001=许嵩, 002=周杰伦, 003=林俊杰}
}
}
Map集合的基本功能
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
案例:测试Map集合基本方法put、remove、isEmpty、containsKey、containsValue、size、clear
// 218-
public class MapDemo1 {
public static void main(String[] args){
// 创建Map集合对象
Map<String,String> map = new HashMap<String,String>();
//添加元素 V put(K key,V value)
map.put("杨过", "小龙女");
map.put("郭靖","黄蓉");
map.put("张无忌", "赵敏");
//删除元素 V remove (Object key)
// System.out.println(map.remove("张无忌"));
// System.out.println(map.remove("郭襄"));
// 返回删除key对应的value,若要删除的key不存在,则返回值是null
// 清空集合元素
// map.clear();
// 输出结果是{}
// 判断集合中键是否存在 containsKey
// System.out.println(map.containsKey("杨过"));//true
// System.out.println(map.containsKey("郭襄"));//false
// 判断集合中值是否存在 containsValue
// System.out.println(map.containsValue("小龙女"));//true
// System.out.println(map.containsValue("小飞象"));//false
// 判断集合中是否为空 isEmpty
// System.out.println(map.isEmpty());//false
// 获得集合长度
System.out.println(map.size());// 3
System.out.println(map);
}
}
Map集合的获取功能
方法名 | 说明 |
---|---|
V get(Object key) | 根据键获取值 |
default V getOrDefault(object jet,V defaultValue) | 返回指定键映射到的值,如果映射不包含该键的映射,则返回defaultValue |
Set < K > keySet() | 获取所有键的集合 Map中键是唯一的,所以返回是Set集合 |
Collection < V> values() | 获取所有值的集合 |
Set< Map.Entry<K,V>> entrySet() | 获取所有键值对 对象的集合 |
理解xhj:
使用 HashMap对象.get(key)
如果key不存在于HashMap集合的时候,此表达式的返回值value为null
案例:测试get、getKeys、values、entrySet
// 218
public class MapDemo2 {
public static void main(String[] args){
Map<String,String> map = new HashMap<String,String>();
map.put("夏", "夏启");
map.put("商", "商汤");
map.put("周","周文王姬昌");
// 获取集合元素 get(key)
System.out.println(map.get("夏"));
System.out.println(map.get("秦"));
// key键在集合中没有时,返回null
// keySet方法 获取所有键的集合
Set<String> set = map.keySet();
for(String st : set){
System.out.println(st);
}
// 输出 商 周 夏 不是按照存储的顺序输出
// Value 方法 获取所有值的集合
Collection<String> val = map.values();
for(String st:val){
System.out.println(st);
}
// 输出内容是: 商汤、周文王姬昌、夏启
// System.out.println(map);
}
}
Map.entry接口
概述
- public static interface Map.Entry<K,V> Map的键值对。
- 通过Map.entrySet方法返回的。
常用方法
方法 | 介绍 |
---|---|
K getKey() | 返回此条目对应的键 |
V getValue() | 返回此条目对应的值 |
HashMap
概述
底层实现:数组+链表;
可以存储null键和null值;
线程不安全;
put方法内存图
LinkedHashMap
概述
- LinkedHashMap是通过 哈希表 和 链表 实现的。
- 它是基于HashMap实现的,不同之处是定义了一个Entry header(头指针) 和 Entry tail(尾指针),不在table中,独立于table。
- 继承了HashMap的Entry,并添加了两个属性 before 和 after,before、after、Entry header组成一个链表,实现按插入顺序或访问顺序排序。此时Entry元素保存的有:当前对象的引用、上一个元素before引用、下一个元素after的引用。
当前对象的引用指的是 Value?
常用方法
方法名 | 说明 |
---|---|
containsKey(key) | 查看map集合中是否有该键 |
set<Map.entry< K,V> entrySet() | 返回此map集合中包含的映射的Map |
Map集合的遍历
方式1:KeySet获取键集合,for循环遍历键集合,get(key)得到值
思路
1 获取所有键的集合
用KeySet()方法实现
2 遍历所有Key组成的集合,获取每一个Key
使用增强for循环
语法for(元素数据类型 变量名:集合名)
3 根据键找对应的值
get(Object key)方法
案例
// 218
public class MapDemo3 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("夏", "夏启");
map.put("商", "商汤");
map.put("周","周文王姬昌");
// 遍历Map集合
Set<String> set = map.keySet();
for(String st:set){
String sValue = map.get(st);
System.out.println(st+", " + sValue);
}
}
}
方式2:entrySet获得键值对 对象的集合,for循环遍历,getKey、getValue分别得到键、值
思路
1 获取所有键值对对象的集合
Set< Map.Entry<K,V> > entrySet() 获取所有键值对对象的集合
2 遍历键值对对象的集合,得到每一个键值对对象
用增强for实现,得到每一个Map.Entry< K,V>
3 根据键值对对象获取键和值
用getKey()得到键
用getValue()得到值
案例
// 218
public class MapDemo4 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("夏", "夏启");
map.put("商", "商汤");
map.put("周","周文王姬昌");
Set<Map.Entry<String, String>> entries = map.entrySet();
for(Map.Entry<String,String> me:entries){
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
}
}
}
方式3:keySet、迭代器对象方式,iterator,hasNext、next
import java.util.Scanner;
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("夏", "夏启");
map.put("商", "商汤");
map.put("周","周文王姬昌");
// 遍历Map集合
Set<String> strSet = map.keySet();
Iterator<String> iterator = strSet.iterator();
while(iterator.hasNext()){
String skey = iterator.next();
System.out.println(skey + ","+map.get(skey));
}
}
}
代码输出有问题
案例
案例1:HashMap集合存储学生对象并遍历(键-学号;值-对象)
需求:
创建一个HashMap集合,键时学号(String),值是学生对象(Student)。存储三个键值对元素,并遍历
代码:
// 218-test2
public class HashMapDemo {
public static void main(String[] args) {
Map<String,Student> map = new HashMap<String, Student>();
Student s1 = new Student("汪苏泷",33);
Student s2 = new Student("许嵩",35);
Student s3 = new Student("徐良",38);
map.put("001", s1);
map.put("002", s2);
map.put("003", s3);
// 遍历学生集合 方式1
Set<String> keyS = map.keySet();
for(String s:keyS){
Student stu = map.get(s);
System.out.println(s + ", "+stu.getName() + ", " + stu.getAge());
}
System.out.println("----------------");
// 遍历学生集合 方法2
Set<Map.Entry<String, Student>> entries = map.entrySet();
for(Map.Entry<String,Student> me :entries){
String key = me.getKey();
Student stu = me.getValue();
System.out.println(key + ", " + stu.getName() + ", " + stu.getAge());
}
}
}
案例2:HashMap集合存储学生对象并遍历(键-学生,值-居住地)
需求:
创建一个HashMap集合,键是学生对象(Student),值是居住地(String)。存储多个键值对元素,并遍历。
要求:
保证键的唯一性,如果学生对象的成员变量相同,认为是同一个对象
关键:
- 需要在学生类中重写HashCode方法和equals方法。直接快捷键生成即可 num lock–》alt + insert
- 重复添加键相同值不同的元素,HashMap集合认为是修改键值对元素。前提是必须重写HashCode和equals方法。
代码:
// 218-test3
public class HashMapDemo {
public static void main(String[] args) {
Map<Student,String> map = new HashMap<Student, String>();
Student s1 = new Student("汪苏泷",33);
Student s2 = new Student("许嵩",33);
Student s3 = new Student("徐良",38);
Student s4 = new Student("徐良",38);
map.put(s1, "西安");
map.put(s2, "太原");
map.put(s3, "阳泉");
map.put(s4, "北京");
// 由于s3和s4的学生索引相同,则认为是同一个人,重复添加不同的地址,应该被认为是修改地址。
Set<Student> stu = map.keySet();
for(Student st : stu){
System.out.println(st.getName() + ", " + st.getAge() + ", " + map.get(st));
}
//没有重写HashCode和equals方法时,会输出四组数据。
// 重写之后 输出三组数据
}
}
Student类:
public class Student {
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
案例3:ArrayList集合存储HashMap元素并遍历
需求:
创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并遍历
// 221-test1
public class ArrayHashMapDemo {
public static void main(String[] args) {
ArrayList<HashMap<String,String>> array = new ArrayList<HashMap<String, String>>();
HashMap<String,String> hm1 = new HashMap<String, String>();
hm1.put("冯绍峰", "赵丽颖");
hm1.put("刘恺威", "杨幂");
array.add(hm1);
HashMap<String,String> hm2 = new HashMap<String, String>();
hm2.put("郭靖", "黄蓉");
hm2.put("杨过", "小龙女");
array.add(hm2);
HashMap<String,String> hm3 = new HashMap<String, String>();
hm3.put("杨绛", "我们仨");
hm3.put("张嘉佳", "从你的全世界路过");
array.add(hm3);
//遍历 迭代器、简单for循环、增强for循环 采用增强for循环
//遍历 ArrayList集合
for(HashMap<String,String> hm:array){//元素类型 变量名:遍历集合名
Set<String> keySet = hm.keySet();
// 获取HashMap集合中key键组成的集合
for(String key : keySet){
// 增强for循环遍历key键集合
String sValue = hm.get(key);
// HashMap对象通过get(key)方法获取值value
System.out.println(key + ", " + sValue);
}
}
}
}
案例4:HashMap集合存储ArrayList元素并遍历
需求:
创建一个HashMap集合,存储三个键值对元素,每一个键值对元素的键是String,值是ArrayList,每一个ArrayList的元素是String,并遍历
// 221-test1
public class HashMapArrayDemo {
/*需求:创建一个HashMap集合,存储三个键值对元素,每一个键值对元素的键是String,值是ArrayList,每一个ArrayList的元素是String,并遍历*/
public static void main(String[] args) {
// 创建HashMap集合
HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();
// 创建ArrayList对象
ArrayList<String> arr1 = new ArrayList<String>();
arr1.add("唐僧");
arr1.add("猪八戒");
ArrayList<String> arr2 = new ArrayList<String>();
arr2.add("宋江");
arr2.add("鲁智深");
ArrayList<String> arr3 = new ArrayList<String>();
arr3.add("刘备");
arr3.add("曹操");
// 将ArrayList对象添加到HashMap集合中
hm.put("西游记",arr1);
hm.put("水浒传", arr2);
hm.put("三国演义", arr3);
// 遍历HashMap集合
Set<String> keyset = hm.keySet();
for(String st : keyset){
ArrayList<String> arrOne = hm.get(st);
System.out.print(st + ", ");
for(int i = 0 ; i < arrOne.size() ; i++){
if(i == arrOne.size() - 1){
System.out.print(arrOne.get(i));
}else{
System.out.print(arrOne.get(i) + ", ");
}
}
System.out.println();
}
}
}
案例5:统计字符串中每个字符出现的次数
需求:
键盘录入一个字符串,要求统计字符串中每个字符串出现的次数
举例:
键盘录入“aababcabcdabcde” 在控制台输出:“a(5)b(4)c(3)d(2)e(1)”
分析:
1 可以把结果看成几个部分的组成:a(5),b(4),c(3),d(2),e(1)
2 那么每一部分又可以看成是键值对对象,键是字母,值是字母出现的次数
3 键值对对象可以使用HashMap存储,键是字符,类型不能是char类型,而应该是其对一个的基本类型封装类Character;值是数字,也不能是int等基本数据类型,应该是其对应的封装类Integer。
// 221-test1
public class ChartSumDemo {
public static void main(String[] args) {
/*键盘录入一个字符串,要求统计字符串中每个字符串出现的次数*/
// 创建Scanner对象,用于获取键盘录入字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String sLine = sc.nextLine();
// 创建HashMap集合
// HashMap<Character,Integer> hm = new HashMap<Character, Integer>();
// HashMap不具有排序给功能,随便输入非字母顺序的文字时,不会按照顺序输出,需要按照键排序的时候,采用TreeMap即可
TreeMap<Character,Integer> hm = new TreeMap<Character,Integer>();
// 遍历字符串,采用字符串.charAt
for(int i = 0 ; i<sLine.length(); i++){
char key = sLine.charAt(i);
Integer value = hm.get(key);
if(value == null){
// 如果返回值是null,说明该键在HashMap中不存在,就把该键作为键,1作为值存储
hm.put(key, 1);
// 这里有一个自动装箱的操作,将char类型的key变成character类
}else{
// 返回值不为null 说明key存在于HashMap集合中,那么执行value++;
value++;
hm.put(key, value);
}
}
// 遍历HashMap集合
Set<Character> chKey = hm.keySet();
for(Character key:chKey){
Integer iValue = hm.get(key);
System.out.print(key + "("+ iValue + ")" );
// 采用输入sout 和 加号 进行拼接
}
System.out.println();
System.out.println("-------------");
// 采用StringBuilder进行拼接
StringBuilder sb = new StringBuilder();
Set<Character> chkey2 = hm.keySet();
for(Character ckey : chkey2){
Integer iValue = hm.get(ckey);
sb.append(ckey).append("(").append(iValue).append(")");
}
String result = sb.toString();
System.out.println(result);
}
}