Map接口详解

本文深入讲解Java中Map集合的特点、常用方法及其实现原理,并通过具体实例演示如何使用Map集合来解决实际问题。
一、Map集合特点:存储的是键值对,键必须唯一

常用方法:

1、增
V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。
          当键相同时,用新值替换旧值,并返回原来的值
     void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。 
2、删
void clear() 
          从此映射中移除所有映射关系(可选操作)。 
     V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 
3、判断
boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 true。
     boolean equals(Object o) 
          比较指定的对象与此映射是否相等。
     boolean isEmpty() 
          如果此映射未包含键-值映射关系,则返回 true。   
4、获取
V get(Object key) 
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
     int size() 
          返回此映射中的键-值映射关系数。 
     Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。 
     重点:
     Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。 
     Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。 

二、体系结构

Map
|--Hashtable:底层是哈希表,必须实现 hashCode 方法和 equals 方法。jdk1.0 效率低
不能存储null值和键,线程同步
|--HashMap:底层是哈希表,允许使用 null 值和 null 键。不同步jdk1.2 效率高
|--TreeMap :底层是二叉树,线程不同步,键排序
和set很像,其他set底层就是使用了Map集合

三、元素存取

import java.util.*;
	
	/*
		Map实例
	*/
	class MapTest {
		public static void main(String[] args) {
			HashMap<String, String> h = new HashMap<String, String>();
	
			//添加数据
			h.put("01","lisi1");
			h.put("03","lisi3");
			h.put("04","lisi2");
	
			//获取
			out(h.get("03"));
		}
		
		//输出
		public static void out(Object obj) {
			System.out.println(obj);
		} 
	}

四、Map集合和取出方式

Map集合取出原理:将Map集合转成Set集合,通过迭代器。在调用put()
	
	1、keySet();将Map中所有的键存入Set集合,在根据get方法
	获取每一个键对应的值
	import java.util.*;
	
	/*
		Map实例
		用keySet()取出所有的键和值
	*/
	class MapTest1 {
		public static void main(String[] args) {
			HashMap<String, String> h = new HashMap<String, String>();
	
			//添加数据
			h.put("01","lisi1");
			h.put("03","lisi3");
			h.put("04","lisi2");
	
			//生产set集合
			Set<String> set = h.keySet();
	
			//迭代器
			Iterator<String> it = set.iterator();
	
			//遍历元素
			while(it.hasNext()) {
				String key = it.next();
				String value = h.get(key);
	
				out("key->" + key + " value->" + value);
			}
		}
		
		//输出
		public static void out(Object obj) {
			System.out.println(obj);
		} 
	}
	2、用entrySet()取元素
	import java.util.*;

	/*
		Map实例
		用entrySet()取出所有的键和值
	*/
	class MapTest2 {
		public static void main(String[] args) {
			HashMap<String, String> h = new HashMap<String, String>();
	
			//添加数据
			h.put("01","lisi1");
			h.put("03","lisi3");
			h.put("04","lisi2");
	
			//生产set集合
			Set<Map.Entry<String, String>> set = h.entrySet();
	
			//迭代器
			Iterator<Map.Entry<String, String>> it = set.iterator();
	
			//遍历元素
			while(it.hasNext()) {
				
				Map.Entry<String, String> m = it.next();
				String key = m.getKey();
				String value = m.getValue();
	
				out(key + ":" + value);
			}
		}
		
		//输出
		public static void out(Object obj) {
			System.out.println(obj);
		} 
	}
	
	Map.Entry:内部实现
	(1)在Map接口中定义了一个静态Entry接口
	interface Map {
		public static interface Entry {
			//一些方法
		}
	}
	(2)Map类实现细节
	class HashMap implements Map {
		class Ha implements Map.Entry {
			//复写方法
		}
	} 

五、综合实例

import java.util.*;
	
	/*
		综合练习:将学生对象存储到HashMap中的键,值为住址
		姓名和年龄相同视为同一人
	
		思路:
			1、描述学生
				实现Comparable接口,覆盖compareTo() //是对象具有自然顺序
				重写equals(),HashCode() //存储到hash结构的容器中
				和toSting()
			2、将学生存储到HashMap容器中
			3、分别用keySet()和entrySet()对元素遍历
		
	*/
	
	//学生
	class Student implements Comparable<Student> {
		private String name;
		private int age;
		
		//构造方法
		public Student(String name, int age) {
			this.name = name;
			this.age = age;
		}
	
		public String getName() {
			return name;
		}
	
		public int getAge() {
			return age;
		}
		
		//复写equlas
		public boolean equlas(Object obj) {
			if (obj instanceof Student)
				throw new ClassCastException("对象类型错误!");
	
			Student s = (Student)obj;
			return this.name.equals(s.name) && this.age == s.age; 
		}
	
		//复写hashCode
		public int hashCode() {
			return this.name.hashCode() + age * 7;
		}
	
		//复写compareTo
		public int compareTo(Student s) {
			int num = this.name.compareTo(s.name); //先按照姓名排序,升序
	
			if (num == 0) { //如果姓名相同,按年龄,升序
				return new Integer(this.age).compareTo(new Integer(s.age));
			}
			return num;
		}
	
		//复写toString
		public String toString() {
			return name + "..." + age;
		}
	}
	
	//main 
	class HashMapTest {
		public static void main(String[] args) {
			//创建容器
			HashMap<Student, String> hs = new HashMap<Student, String>();
	
			//添加数据
			hs.put(new Student("lisi1",14), "四川");
			hs.put(new Student("lisi4",19), "深圳");
			hs.put(new Student("lisi3",29), "北京");
			hs.put(new Student("lisi5",11), "上海");
	
			//第一种方法keySet()取数据
			Set<Student> set = hs.keySet();
	
			//迭代器
			Iterator<Student> it = set.iterator();
	
			//循环取出数据
			while(it.hasNext()) {
				Student key = it.next();
	
				String addr = hs.get(key);
	
				out("name:" + key.getName() + " age:" + key.getAge() + " 地址:" + addr);
			}
	
			out("");
	
			//第二种方法entrySet()
	
			//获取键值映射的Set集合
			Set<Map.Entry<Student, String>> s1 = hs.entrySet();
	
			//迭代器
			Iterator<Map.Entry<Student, String>> iter = s1.iterator();
	
			//循环取元素
			while(iter.hasNext()) {
				Map.Entry<Student, String> mp = iter.next();
	
				Student stu = mp.getKey();
				String addrs = mp.getValue();
	
				out("name:" + stu.getName() + " age:" + stu.getAge() + " addr:" + addrs);
			}
		}
	
		//输出
		public static void out(Object obj) {
			System.out.println(obj);
		}
	}

六、综合实例改进

import java.util.*;

	/*
		实现对学生对象的排序用TreeSet容器(默认是姓名排序)
		现在要求用年龄升序
	
		注意:	学生对象同上
	*/
	
	//main 
	class HashMapTest1 {
		public static void main(String[] args) {
			//创建容器
			TreeMap<Student, String> hs = new TreeMap<Student, String>(new StudentNameComparator());
	
			//添加数据
			hs.put(new Student("lisi1",14), "四川");
			hs.put(new Student("lisi4",19), "深圳");
			hs.put(new Student("lisi3",29), "北京");
			hs.put(new Student("lisi5",11), "上海");
	
			//获取键值映射的Set集合
			Set<Map.Entry<Student, String>> s1 = hs.entrySet();
	
			//迭代器
			Iterator<Map.Entry<Student, String>> iter = s1.iterator();
	
			//循环取元素
			while(iter.hasNext()) {
				Map.Entry<Student, String> mp = iter.next();
	
				Student stu = mp.getKey();
				String addrs = mp.getValue();
	
				out("name:" + stu.getName() + " age:" + stu.getAge() + " addr:" + addrs);
			}
		}
	
		//输出
		public static void out(Object obj) {
			System.out.println(obj);
		}
	}
	
	//学生比较器
	class StudentNameComparator implements Comparator<Student> {
		public int compare(Student s1, Student s2) {
			int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
	
			if (num == 0)
				return s1.getName().compareTo(s2.getName());
			return num;
		}
	}

七、实例2

什么时候使用map集合:当数据直接出现映射关系时
	import java.util.*;
	
	/*
		练习:统计字符串中字母出现的次数
		输出如;a(13)b(3)c(9)...
	
		思路:
			1、定义一个TreeMap,因为数据之间有映射关系,而且是自然排序
			2、将字符串转成数组toCharArray()
			3、遍历字符数组,取出一个字符,去TreeMap中查询get()
			如果返回值为null说明,该字符以前没有出现,就将该字母和1
			作为键值对存入。
			否则,将出来的值加1,该字母和该值存入
			4、定义字符串缓冲区,拼接字符串(StringBuilder)
	*/
	
	class TreeMapCount {
		public static void main(String[] args) {
			String str = "anglakjngdpang";
			out(countChar(str));
		}
	
		//输出方法
		public static void out(Object obj) {
			System.out.println(obj);
		}
	
		//统计字母出现次数方法
		public static String countChar(String str) {
			//将字符串转成数组
			char[] chs = str.toCharArray();
		
			TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
	
			//遍历字符串
			Integer count = 0;
			for (int i=0;i<chs.length;i++) {
				/*
				Character ch = chs[i];
	
				Integer value = tm.get(ch);
	
				if (value == null) {
					tm.put(ch, 1);
				} else {
					value++;
					tm.put(ch, value);
				}
				*/
	
				Character ch = chs[i];
				Integer value = tm.get(ch);
	
				if (value != null) 
					count = value;
				count++;
				tm.put(ch, count);
	
				count = 0;
	
			}
			
			//拼接字符串
			StringBuilder sb = new StringBuilder();
	
			//获取键值映射集合Set
			Set<Map.Entry<Character, Integer>> set = tm.entrySet();
			
			//迭代器
			Iterator<Map.Entry<Character, Integer>> it = set.iterator();
	
			//循环取值
			while(it.hasNext()) {
				Map.Entry<Character, Integer> me = it.next();
	
				Character c = me.getKey();
				Integer value = me.getValue();
	
				sb.append(c + "(" + value + ")");
			}
			return sb.toString();
		}
	}

八、Map扩展知识

import java.util.*;
	
	/*
		练习:
		需求:对如下数据进行存储
		
		有一个学校,一个学校有很多班级,一个班级有很多学生,
		每个学生信息,姓名,学号
	
		分析:
			1、多对多关系,一个学校有很多个班级,班级有名称
			2、一个班级有很多学生,每个学生属于一个班级
		步骤:
			1、描述学生
			2、定义一个学生HashMap
			3、定义多个班级,
			4、向每个班级中添加学生
	*/
	
	//学生类
	class Student {
		private String id;
		private String name;
	
		public Student(String id, String name) {
			this.id = id;
			this.name = name;
		}
	
		public String toString() {
			return id + "..." + name;
		}
	}
	
	//main
	class StorageTest {
		public static void main(String[] args) {
			method2();
		}
	
		//第一种方式,不将学校封装成对象,就要用HashMap,因为,
		//学号和姓名要一一对应
		public static void method1() {
			//创建学校
			HashMap<String, HashMap<String, String>> school = new HashMap<String, HashMap<String, String>>();
	
			//创建班级
			HashMap<String, String> ruanjianban = new HashMap<String, String>();
			HashMap<String, String> yishuban = new HashMap<String, String>();
			HashMap<String, String> dongmanban = new HashMap<String, String>();
	
			//将班级与学校关联
			school.put("软件班", ruanjianban);
			school.put("艺术班", yishuban);
			school.put("动漫班", dongmanban);
	
			//向每个班级添加学生
			ruanjianban.put("01", "zhangsan");
			ruanjianban.put("02", "lisi");
			ruanjianban.put("04", "wanger");
	
			yishuban.put("02", "zhangsan1");
			yishuban.put("01", "zhaoliu");
	
			dongmanban.put("05", "wangsan");
	
			//打印这个学校的学生信息
			outInfo(school);
		}
		
		//打印学生信息
		public static void outInfo(HashMap<String, HashMap<String, String>> s) { //传一个学校
			//先循环出班级的名称
			Iterator<String> it = s.keySet().iterator();
			
			while (it.hasNext()) {
				String room = it.next();
	
				out(room);
				//在由班级名称查找对于的学生
				
				HashMap<String, String> mm = s.get(room); //班级对象
	
				Iterator<String> it1 = mm.keySet().iterator();
	
				while(it1.hasNext()) {
					String key = it1.next();
					String value = mm.get(key);
	
					out(key + "..." + value);
				}
			}
			
		}
		
		
	
		//第二种方式,将学生封装成对象,那些第二个集合用Set就可以了
		public static void method2() {
			//创建学校
			HashMap<String, List<Student>> school = new HashMap<String, List<Student>>();
	
			//创建班级
			List<Student> ruanjianban = new ArrayList<Student>();
			List<Student> yishuban = new ArrayList<Student>();
			List<Student> dongmanban = new ArrayList<Student>();
			
	
			//将班级与学校关联
			school.put("软件班", ruanjianban);
			school.put("艺术班", yishuban);
			school.put("动漫班", dongmanban);
	
			//向每个班级添加学生
			ruanjianban.add(new Student("01", "zhangsan"));
			ruanjianban.add(new Student("02", "lisi"));
			ruanjianban.add(new Student("04", "wanger"));
	
			yishuban.add(new Student("02", "zhangsan1"));
			yishuban.add(new Student("01", "zhaoliu"));
	
			dongmanban.add(new Student("05", "wangsan"));
	
			//打印这个学校的学生信息
			outInfo1(school);
		}
	
		public static void outInfo1(HashMap<String, List<Student>> h) {
			//变量出班级名称
			Iterator<String> it = h.keySet().iterator();
	
			while(it.hasNext()) {
				String key = it.next();
	
				out(key);
	
				Iterator it2 = h.get(key).iterator();
		
				while(it2.hasNext()) {
					out(it2.next());
				}
			}
	
		}
		//输出
		public static void out(Object obj) {
			System.out.println(obj);
		}
	}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值