java基础-- 集合框架 之 Map集合
一、 Map 集合概述
(其实Set底层就是使用了Map集合。)
Map与Collection在集合框架中属于并列存在
Map存储的是键值对
Map存储元素使用put方法,Collection使用add方法
Map集合没有直接取出元素的方法,而是先转成Set集合,再通过迭代获取元素
Map集合中键要保证唯一性
二、Map子类集合特点
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同 步的,jdk1.0.版本,效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.版本,效率高。
|--TreeMap:底层是二叉树数据结构,线程不同步。可以用于给map集合中的键进行排序。和Set很像,其实Set底层就是使用了Map集合。
三、Map集合共性方法
特殊之处:
1、get(Object key) 可以用返回null来判断一个键是否存在,
2、put(K key, V value)
添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。
而且put方法会返回被覆盖的值。
3、remove()返回与key关联的旧值;如果没有任何映射关系,则返回null。(返回null还可能表示该映射之前将null与key相联
Map集合共性方法演示代码:
import java.util.*; class MapDemo { public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(); // 添加元素,添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。 // b并且put方法会返回被覆盖的值。而在HashSet中如果添加相同的元素,返回false System.out.println("put:" + map.put("01", "zhangsan1")); System.out.println("put:" + map.put("01", "wnagwu")); map.put("02", "zhangsan2"); map.put("03", "zhangsan3"); System.out.println("containsKey:" + map.containsKey("022")); // System.out.println("remove:"+map.remove("02")); System.out.println("get:" + map.get("023")); // 可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。 map.put("04", null); System.out.println("get:" + map.get("04")); // 获取map集合中所有的值。 Collection<String> coll = map.values(); System.out.println(coll); System.out.println(map); } }
四、Map集合两中取出方式
取出原理:将map集合转成set集合。在通过迭代器取出。
1、 取出方式一:Set<k> ,keySet()
将map中所有的键存入到Set集合。
因为set具备迭代器,所以可以通过迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。
2、 取出方式二:Set<Map.Entry<k,v>> ,entrySet()
将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。
Entry其实是Map中的一个static内部接口。
3、Entry为什么要定义在内部呢?
因为只有有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。
而且该事物在直接访问Map集合中的元素。
Map集合两种取出方式示例代码:
import java.util.*; class MapDemo2 { public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(); map.put("02", "zhangsan2"); map.put("03", "zhangsan3"); map.put("01", "zhangsan1"); map.put("04", "zhangsan4"); System.out.println("Map集合取出方式一:通过keySet()取键 "); // 先通过keySet()获取map集合的所有键的Set集合,; Set<String> keySet = map.keySet(); // 有了Set集合。就可以获取其迭代器。 Iterator<String> it2 = keySet.iterator(); while (it2.hasNext()) { String key = it2.next(); // 有了键可以通过map集合的get方法获取其对应的值。 String value = map.get(key); System.out.println("key:" + key + ",value:" + value); } System.out.println("Map集合取出方式二: 通过entrySet() 取键值的映射关系"); // 将Map集合中的映射关系取出,存入到Set集合中。 Set<Map.Entry<String, String>> entrySet = map.entrySet(); Iterator<Map.Entry<String, String>> it = entrySet.iterator(); while (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 { public static interface Entry { public abstract Object getKey(); public abstract Object getValue(); } } class HashMap implements Map { class Hahs implements Map.Entry { public Object getKey(){} public Object getValue(){} } } */
五、练习
Map集合练习:
要求:定义一个学生类,使用集合存储和获取学生对象
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。
思路:
1、描述学生。
2、定义map容器,将学生作为键,地址作为值存入。
3、获取map集合中的元素
说明:
如果对象较多,为了存储,而又不确定使用什么集合存储的时候,为了安全和提高可扩展性。需要做的操作:覆盖hashcode和equals方法,
实现Comparable,覆盖compareTo方法,使其具有自然顺序。
定义一个学生类,使用map集合存储和获取学生对象
import java.util.*; class Student implements Comparable<Student>{ private String name; private int age; Student(String name,int age){ this.name = name; this.age = age; } //为了以后可以使用二叉树存储,所以事先实现Comparable,让Student具有自然顺序 public int compareTo(Student s) { int num = new Integer(this.age).compareTo(new Integer(s.age)); if(num==0) return this.name.compareTo(s.name); return num; } //为了以后可以使用Hash集合存储,先复写hashCode和equals方法 public int hashCode() { return name.hashCode()+age*34; } public boolean equals(Object obj) { if(!(obj instanceof Student)) //Object没有泛型,需强转 throw new ClassCastException("类型不匹配"); Student s = (Student)obj; return this.name.equals(s.name) && this.age==s.age; } public String getName() { return name; } public int getAge() { return age; } public String toString() { return name+":"+age; } } class MapTest { public static void main(String[] args) { HashMap<Student,String> hm = new HashMap<Student,String>(); hm.put(new Student("lisi1",21),"beijing");//被覆盖 hm.put(new Student("lisi1",21),"tianjin"); hm.put(new Student("lisi2",22),"shanghai"); hm.put(new Student("lisi3",23),"nanjing"); hm.put(new Student("lisi4",24),"wuhan"); //第一种取出方式 keySet System.out.println("Map集合取出方式一:通过keySet()取键 "); Set<Student> keySet = hm.keySet(); Iterator<Student> it = keySet.iterator(); while(it.hasNext()) { Student stu = it.next(); String addr = hm.get(stu); System.out.println(stu+".."+addr); } //第二种取出方式 entrySet System.out.println("Map集合取出方式二: 通过entrySet() 取键值的映射关系"); Set<Map.Entry<Student,String>> entrySet = hm.entrySet(); Iterator<Map.Entry<Student,String>> iter = entrySet.iterator(); while(iter.hasNext()) { Map.Entry<Student,String> me = iter.next(); Student stu = me.getKey(); String addr = me.getValue(); System.out.println(stu+"........."+addr); } } }
TreeMap练习:对学生进行升序排序
因为数据是以键值对存在的,所以使用可以排序的Map集合:TreeMap
import java.util.*; class Student2 implements Comparable<Student2> { private String name; private int age; Student2(String name, int age) { this.name = name; this.age = age; } // 为了以后可以使用二叉树存储,所以事先实现Comparable,让Student具有自然顺序 public int compareTo(Student2 s) { int num = new Integer(this.age).compareTo(new Integer(s.age)); if (num == 0) return this.name.compareTo(s.name); return num; } // 为了以后可以使用Hash集合存储,先复写hashCode和equals方法 public int hashCode() { return name.hashCode() + age * 34; } public boolean equals(Object obj) { if (!(obj instanceof Student2)) // Object没有泛型,需强转 throw new ClassCastException("类型不匹配"); Student2 s = (Student2) obj; return this.name.equals(s.name) && this.age == s.age; } public String getName() { return name; } public int getAge() { return age; } // public String toString() { return name + ":" + age; } } class StuNameComparator implements Comparator<Student2> { public int compare(Student2 s1, Student2 s2) { int num = s1.getName().compareTo(s2.getName()); if (num == 0) return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); return num; } } class MapTest2 { public static void main(String[] args) { TreeMap<Student2, String> tm = new TreeMap<Student2, String>( new StuNameComparator()); tm.put(new Student2("blisi3", 23), "nanjing"); tm.put(new Student2("lisi1", 21), "beijing");// 被覆盖 tm.put(new Student2("alisi4", 24), "wuhan"); tm.put(new Student2("lisi1", 21), "tianjin"); tm.put(new Student2("lisi2", 22), "shanghai"); Set<Map.Entry<Student2, String>> entrySet = tm.entrySet(); Iterator<Map.Entry<Student2, String>> it = entrySet.iterator(); while (it.hasNext()) { Map.Entry<Student2, String> me = it.next(); Student2 stu = me.getKey(); String addr = me.getValue(); System.out.println(stu + ":::" + addr); } } }
Map集合练习二:
获取字符串中的字母出现的次数:"sdfgzxcvasdfxcvdf"
希望打印结果:a(1)c(2).....
说明:
通过结果发现,每一个字母都有对应的次数。
说明字母和次数之间都有映射关系,所以可以选择map集合,因为map集合中存放就是映射关系。
思路:
1、将字符串转换成字符数组。因为要对每一个字母进行操作。
2、定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合。
3、遍历字符数组。
将每一个字母作为键去查map集合。
如果返回null,将该字母和1存入到map集合中。
如果返回不是null,说明该字母在map集合已经存在并有对应次数。
那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到map集合中,覆盖调用原理键所对应的值。
4、将map集合中的数据变成指定的字符串形式返回。
获取字符串中的字母出现的次数代码演示:
import java.util.*; class MapTest3 { public static void main(String[] args) { String s = charCount("ak+abAf1c,dCkaAbc-defa"); System.out.println(s); } public static String charCount(String str) { char[] chs = str.toCharArray(); TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>(); // 定义一个计数器,记录字母出现的次数 int count = 0; for (int x = 0; x < chs.length; x++) { if (!(chs[x] >= 'a' && chs[x] <= 'z' || chs[x] >= 'A' && chs[x] <= 'Z')) continue; Integer value = tm.get(chs[x]); if (value != null) count = value; count++; tm.put(chs[x], count);// 直接往集合中存储字符和数字,为什么可以,因为自动装箱。 count = 0; //为了避免每次都使用同一个计数器,出现叠加,每次都要清零 /*if(value==null) { tm.put(chs[x],1); } else { value = value + 1; tm.put(chs[x],value); }*/ } // System.out.println(tm); //为获取指定格式,定义一个容器以指定格式存储原集合中的数据 StringBuilder sb = new StringBuilder(); Set<Map.Entry<Character, Integer>> entrySet = tm.entrySet(); Iterator<Map.Entry<Character, Integer>> it = entrySet.iterator(); while (it.hasNext()) { Map.Entry<Character, Integer> me = it.next(); Character ch = me.getKey(); Integer value = me.getValue(); sb.append(ch + "(" + value + ")"); } return sb.toString(); } }
六、Map扩展知识:嵌套映射(map集合被使用是因为具备映射关系)
获取学校学生信息示例代码:
要求:获取学校的学生信息:
一个学校有多个教室,每一个教室都有名称。
说明:
该示例使用了两种方式存储学生的信息。
方式一:将学生信息封装成对象存入List集合List<Student>
然后将教室名称作为键,教室集合作为值存入
方式二:将学生信息直接存入HashMap集合HashMap<String,String>
然后将教室名作为键,学生信息集合作为值存入
import java.util.*; class Student { private String id; private String name; Student(String id, String name) { this.id = id; this.name = name; } public String toString() { return id + ":::" + name; } } // 获取学生信息的工具类 class Tool { // 遍历指定教室直接获取学生信息 public static void getStudentInfo(HashMap<String, String> roomMap) { Iterator<String> it = roomMap.keySet().iterator(); while (it.hasNext()) { String id = it.next(); String name = roomMap.get(id); System.out.println(id + ":" + name); } } // 遍历指定教室来获取学生对象 public static void getInfos(List<Student> list) { Iterator<Student> it = list.iterator(); while (it.hasNext()) { Student s = it.next(); System.out.println(s); } } } class getStudentMethod { // 将学生信息封装成学生对象再存入教室集合 public static void Method() { // 创建学校 <教室名称,存储学生对象的教室> HashMap<String, List<Student>> czbk = new HashMap<String, List<Student>>(); // 创建存储学生对象的教室 List<Student> yure = new ArrayList<Student>(); List<Student> jiuye = new ArrayList<Student>(); // 将教室存入学校 czbk.put("yureban", yure); czbk.put("jiuyeban", jiuye); // 将学生对象存入教室 yure.add(new Student("01", "zhagnsa")); yure.add(new Student("04", "wangwu")); jiuye.add(new Student("01", "zhouqi")); jiuye.add(new Student("02", "zhaoli")); Iterator<String> it = czbk.keySet().iterator(); while (it.hasNext()) { String roomName = it.next(); List<Student> room = czbk.get(roomName); System.out.println(roomName); Tool.getInfos(room); } } // 直接将学生信息存入教室集合 public static void Method2() { // 创建学校<教室名称,存储学生信息的教室> HashMap<String, HashMap<String, String>> czbk = new HashMap<String, HashMap<String, String>>(); // 创建直接存储学生信息的教室 HashMap<String, String> yure = new HashMap<String, String>(); HashMap<String, String> jiuye = new HashMap<String, String>(); czbk.put("yureban", yure); czbk.put("jiuyeban", jiuye); yure.put("01", "zhagnsan"); yure.put("02", "lisi"); jiuye.put("01", "zhaoliu"); jiuye.put("02", "wangwu"); // 遍历czbk学校集合,获取所有的教室。 Iterator<String> it = czbk.keySet().iterator(); while (it.hasNext()) { String roomName = it.next(); HashMap<String, String> room = czbk.get(roomName); System.out.println(roomName); // 获取指定教室的所有学生信息 Tool.getStudentInfo(room); } } } class MapDemo3 { public static void main(String[] args) { System.out.println("demo"); getStudentMethod.Method(); System.out.println("--------------------"); System.out.println("demo2"); getStudentMethod.Method2(); } }