第三十五讲 集合框架——Map接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yerenyuan_pku/article/details/84193614

Map接口的概述

将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。其实Map集合是一个双列集合,存储的就是键值对,而且Map集合中必须保证键的唯一性。

Map接口的特点

  1. Map与Collection在集合框架中属并列存在,而且Map是双列的,Collection是单列的;
  2. Map的键唯一,Collection的子体系Set是唯一的;
  3. Map集合的数据结构只针对键有效,跟值无关;Collection集合的数据结构是针对元素有效。

Map接口中的常用方法

在这里插入图片描述
下面我们就来演示以上的一些方法。

package cn.liayun.map;

import java.util.HashMap;
import java.util.Map;

public class MapDemo {

	public static void main(String[] args) {
		
		/*
		 * 需求:在Map集合中存储学号,姓名。
		 */
		Map<Integer, String> map = new HashMap<Integer, String>();
		methodDemo(map);
	}
	
	public static void methodDemo(Map<Integer, String> map) {
		//1,存储键值对。如果键相同,会出现值覆盖。
		System.out.println(map.put(3, "xiaoqiang"));
		System.out.println(map.put(3, "erhu"));
		map.put(7, "wangcai");
		map.put(2, "daniu");
		
//		System.out.println(map.remove(7));
		
		System.out.println(map.get(7));
		
		System.out.println(map);
	}

}

Map接口的常见子类

在这里插入图片描述
Map和Set很像,其实Set底层就是使用了Map集合。

Map集合的三种取出所有元素的方式

Map集合的三种取出所有元素的方式:
在这里插入图片描述

Map集合的取出所有元素的第一种方式——keySet()方法

下面我们就来演示Map集合的第一种取出方式。

package cn.liayun.map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class MapDemo2 {

	public static void main(String[] args) {
		/*
		 * 取出Map中所有的元素。
		 * Map中存储姓名---归属地
		 */
		Map<String, String> map = new HashMap<String, String>();
		
		map.put("xiaoqiang", "beijing");
		map.put("wangcai", "funiushan");
		map.put("daniu", "heifengzhai");
		map.put("erhu", "wohudong");
		map.put("zhizunbao", "funiushan");
		
		//keySet(),取出所有的键,并存储到Set集合中。map集合没有迭代器,但是可以将map集合转成Set集合,再使用迭代器就哦了。
		Set<String> keySet = map.keySet();
		for (Iterator<String> it = keySet.iterator(); it.hasNext();) {
			String key = it.next();
			String value = map.get(key);
			System.out.println(key + ":" + value);
		}
	}
}

Map集合的取出所有元素的第二种方式——entrySet()方法

package cn.liayun.map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class MapDemo2 {

	public static void main(String[] args) {
		/*
		 * 取出Map中所有的元素。
		 * Map中存储姓名---归属地
		 */
		Map<String, String> map = new HashMap<String, String>();
		
		map.put("xiaoqiang", "beijing");
		map.put("wangcai", "funiushan");
		map.put("daniu", "heifengzhai");
		map.put("erhu", "wohudong");
		map.put("zhizunbao", "funiushan");
		
		//演示entrySet()。Map.Entry:其实就是一个Map接口中的内部接口。
		Set<Map.Entry<String, String>> entrySet = map.entrySet();
		for (Iterator<Map.Entry<String, String>> it = entrySet.iterator(); it.hasNext();) {
			Map.Entry<String, String> me = it.next();
			String key = me.getKey();
			String value = me.getValue();
			System.out.println(key + ":::" + value);
		}
	}
}

对于Map.Entry而言,其实Entry也是一个接口,它是Map接口中的一个内部接口。源码我们可以理解为:

interface Map {

	//entry就是Map接口中的内部接口
	public static interface Entry {
		public abstract Object getKey();
		public abstract Object getValue();
	}
	
}

class MyDemo implements Map.Entry {

	@Override
	public Object getKey() {
		return null;
	}

	@Override
	public Object getValue() {
		return null;
	}
	
}

Map集合的取出所有元素的第三种方式——values()方法

package cn.liayun.map;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class MapDemo2 {

	public static void main(String[] args) {
		/*
		 * 取出Map中所有的元素。
		 * Map中存储姓名---归属地
		 */
		Map<String, String> map = new HashMap<String, String>();
		
		map.put("xiaoqiang", "beijing");
		map.put("wangcai", "funiushan");
		map.put("daniu", "heifengzhai");
		map.put("erhu", "wohudong");
		map.put("zhizunbao", "funiushan");
		
		//演示values()方法,获取所有的值
		Collection<String> values = map.values();
		for (Iterator<String> it = values.iterator(); it.hasNext();) {
			String value = it.next();
			System.out.println(value);
		}
	}

}

练习

练习一

每一个雇员都有对应的归属地。雇员Employee,地址String。雇员属性:姓名,年龄。将雇员和归属地存储到HashMap集合中并取出,注意:姓名和年龄相同的视为同一个雇员,须保证雇员的唯一性。
首先描述雇员,由于要将雇员对象作为键存入HashMap集合中,所以为了保证键的唯一性,雇员类中应该覆盖掉hashCode()和equals()方法。

package cn.liayun.domain;

public class Employee {
    private String name;
    private int age;

    public Employee() {
        super();
    }

    public Employee(String name, int age) {
        super();
        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 String toString() {
        return "Employee [name=" + name + ", age=" + age + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

然后定义Map容器,将雇员作为键,地址作为值存入,在这里我们只使用keySet()方法进行获取Map集合中的元素。

package cn.liayun.map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import cn.liayun.domain.Employee;

public class HashMapTest {

	public static void main(String[] args) {
		Map<Employee, String> map = new HashMap<Employee, String>();//如果改成LinkedHashMap,可以实现有序。
		
		map.put(new Employee("xiaozhang", 24), "北京");
		map.put(new Employee("laoli", 34), "上海");
		map.put(new Employee("mingming", 26), "南京");
		map.put(new Employee("xili", 30), "广州");
		map.put(new Employee("laoli", 34), "铁岭");
		
		Set<Employee> keySet = map.keySet();
		for (Employee employee : keySet) {
			String value = map.get(employee);
			System.out.println(employee.getName() + ":" + employee.getAge() + "...." + value);
		}
		
	}

}

拓展一

现在我们又有了这样一个需求:按照雇员的年龄进行升序排序并取出。

分析:因为数据是以键值对的形式存在的,所以要使用可以排序的Map集合——TreeMap。

首先描述雇员,为了能按照雇员的年龄进行升序排序,我们可以让自定义的Employee类实现Comparable接口(强制让Employee类具备比较性),覆盖compareTo()方法。

package cn.liayun.domain;

public class Employee implements Comparable<Employee> {
	private String name;
	private int age;

	public Employee() {
		super();
	}

	public Employee(String name, int age) {
		super();
		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 String toString() {
		return "Employee [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public int compareTo(Employee o) {
		int temp = this.age - o.age;
		return temp == 0 ? this.name.compareTo(o.name) : temp;
	}
	
}

然后定义Map容器,将雇员作为键,地址作为值存入,在这里我们只使用entrySet()方法进行获取Map集合中的元素。

package cn.liayun.map;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import cn.liayun.domain.Employee;

public class TreeMapTest {

	public static void main(String[] args) {
		Map<Employee, String> map = new TreeMap<Employee, String>();
		
		map.put(new Employee("xiaozhang", 24), "北京");
		map.put(new Employee("laoli", 34), "上海");
		map.put(new Employee("mingming", 26), "南京");
		map.put(new Employee("xili", 30), "广州");
		map.put(new Employee("laoli", 34), "铁岭");
		
		//entrySet()
		Set<Map.Entry<Employee, String>> entrySet = map.entrySet();
		
		for (Map.Entry<Employee, String> me : entrySet) {
			Employee key = me.getKey();
			String value = me.getValue();
			System.out.println(key.getName() + "::" + key.getAge() + "....." + value);
		}
	}

}

拓展二

现在我们又有了这样一个需求:按照雇员的姓名进行升序排序并取出。

分析:因为数据是以键值对的形式存在的,所以要使用可以排序的Map集合——TreeMap

由于雇员类我们在上面已描述过,所以在此省略,然后定义一个按姓名排序的比较器,最后定义Map容器,将雇员作为键,地址作为值存入,在这里我们只使用entrySet()方法进行获取Map集合中的元素。

package cn.liayun.map;

import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import cn.liayun.domain.Employee;

public class TreeMapTest {

	public static void main(String[] args) {
		//自定义一个比较器
		Comparator<Employee> comparator = new Comparator<Employee>() {
			
			@Override
			public int compare(Employee o1, Employee o2) {
				int temp = o1.getName().compareTo(o2.getName());
				return temp == 0 ? o1.getAge() - o2.getAge() : temp;
			}
		};
		
		Map<Employee, String> map = new TreeMap<Employee, String>(comparator);
		
		map.put(new Employee("xiaozhang", 24), "北京");
		map.put(new Employee("laoli", 34), "上海");
		map.put(new Employee("mingming", 26), "南京");
		map.put(new Employee("xili", 30), "广州");
		map.put(new Employee("laoli", 34), "铁岭");
		
		//entrySet()
		Set<Map.Entry<Employee, String>> entrySet = map.entrySet();
		
		for (Map.Entry<Employee, String> me : entrySet) {
			Employee key = me.getKey();
			String value = me.getValue();
			System.out.println(key.getName() + "::" + key.getAge() + "....." + value);
		}
	}

}

练习二

获取字符串(比如”bwaerbctyxbacecrtdcvr”)中每一个字母出现的次数,要求结果格式为:a(2)b(1)d(3)…

分析:通过结果发现,每一个字母都有对应的次数,说明字母和次数之间具有映射关系。注意:当发现有映射关系时,可以选择Map集合,因为Map集合中存放的就是映射关系。本题思路如下:

  1. 将字符串转换为字符数组。因为要对每一个字母进行操作;
  2. 定义一个Map集合,因为打印结果的字母有顺序,所以使用TreeMap集合;
  3. 遍历字符数组,将每一个字母作为键去查Map集合。如果返回null,将该字母和1存入到Map集合中。如果返回不是null,说明该字母在Map集合中已经存在,并有对应次数。那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到Map集合中,覆盖掉原来键所对应的值;
  4. 将Map集合中的数据变成指定的字符串返回。
package cn.liayun.test;

import java.util.Map;
import java.util.TreeMap;

public class Test {

	public static void main(String[] args) {
		/*
		 * 作业:"bwaerbctyxbacecrtdcvr"
		 * 获取字符串中每一个字母出现的次数,要求结果格式:a(2)b(1)d(3)......
		 * 思路:
		 * 1,获取到字母。
		 * 2,如何获取到字母的次数?
		 * 	    发现字母和次数有对应关系,而且对应关系的一方具备唯一性。
		 *    就想到了Map集合。Map集合就是一张表。
		 * 3,使用查表法就可以了。
		 *    先查第一个字母在表中出现的次数,如果次数不存在,说明是第一次出现,将该字母和1存储到表中。
		 *    依此类推,当要查的次数存在了,将次数取出并自增后,再和对应的字母存储到表中,map表的特点是相同键,值覆盖,哦耶!
		 * 4,查完每一个字母后,表中存储的就是每一个字母出现的次数。
		 */
		String str = "b?wa+erbcty=xbace-crtdcvr";
		String char_count = getCharCount(str);
		System.out.println(char_count);
	}

	public static String getCharCount(String str) {
		//1,将字符串转成字符数组
		char[] chs = str.toCharArray();
		//2,定义map集合表
		Map<Character, Integer> map = new TreeMap<Character, Integer>();
		
		//3,遍历字符数组,获取每一个字母
		for (int i = 0; i < chs.length; i++) {
			//只对字母操作
			if (!(chs[i] >= 'a' && chs[i] <= 'z' || chs[i] >= 'A' && chs[i] <= 'Z')) {
				continue;
			}
			
			
			//将遍历到的字母作为键去查表,获取值。
			Integer value = map.get(chs[i]);
			int count = 0;//用于记录次数。
			//如果次数存在,就用count记录该次数;如果次数不存在,就不记录,只对count自增变成1。
			if (value != null) {
				count = value;
			}
			count++;
			map.put(chs[i], count);
			
			
			/*
			if (value == null) {
				map.put(chs[i], 1);
			} else {
				value++;
				map.put(chs[i], value);
			}
			*/
			
		}
//		System.out.println(map);
		return toString(map);
	}

	/*
	 * 将Map集合中的元素转成指定格式的字符串。a(2)b(1)d(3)......
	 */
	private static String toString(Map<Character, Integer> map) {
		//1,数据多,无论类型是什么,最终都要变成字符串,所以可以使用StringBuilder
		StringBuilder sb = new StringBuilder();
		//2,遍历集合Map
		for (Character ch : map.keySet()) {
			Integer value = map.get(ch);
//			sb.append(ch).append("(").append(value).append(")");
			sb.append(ch + "(" + value + ")");
		}
		return sb.toString();
	}

}

总结

什么时候使用Map集合呢? 当需求中出现映射关系时,应该最先想到Map集合。

猜你喜欢

转载自blog.csdn.net/yerenyuan_pku/article/details/84193614