五、集合——6-Map集合
6-Map集合
1.概述
(1)Map集合用于保存具有映射关系的数据,所以,Map集合中保存有两组值,一组值用于保存Map里的key,另一组值用于保存Map中的value。key和value可以是任何引用类型的数据,但Map中的key不允许重复。
(2)Map中的key和value具有单向的一对一关系,通过指定的key总能找到与其对应的value。
(3)Map中的key组成的集合可以当做是一个Set集合,并且具有Set集合的特性,即无序并且不可重复。而value所组成的集合类似于一个List集合,可以通过索引来访问到value,但这个List的索引不是int类型,而是key的引用类型。
(4)Map的元素是Entry,Entry是Map的一个内部类,使用Entry来封装key-value对;
(5)Map接口中的常用方法:
import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapTest { public static void main(String[] args) { //创建一个Map集合 Map map = new HashMap(); //向Map集合中添加元素 map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.put(4, "D"); map.put(5, "A"); System.out.println(map); //查询Map中是否包含指定的key System.out.println("是否包含key为1的key:"+map.containsKey(1)); //查询Map中是否包含指定的value System.out.println("是否包含value为A的value"+map.containsValue("A")); //返回指定key对应的value System.out.println(map.get(1)); //查询Map是否为空 System.out.println("该Map是否为空:"+map.isEmpty()); //获取该Map的key所组成的Set集合 Set keySet = map.keySet(); System.out.println(keySet); //添加一个新的key-value对,如果该key存在,则新的key-value对会覆盖原key-value对 map.put(1, "a"); System.out.println(map); //将指定的Map中的key-value对复制到该Map中来 Map newMap = new HashMap(); newMap.putAll(map); System.out.println(newMap); //删除指定key对应的key-value对 map.remove(1); System.out.println(map); //获取该Map中key-value对的个数 System.out.println(map.size()); //获取Map中value组成的Collection Collection c = map.values(); System.out.println(c); } }
(6)Map接口的内部类Entry,的相关方法:
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class MapEntryTest { public static void main(String[] args) { Map map = new HashMap(); map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.put(4, "D"); map.put(5, "A"); System.out.println(map); //获取Map中的Entry对象组成的Set Set set = map.entrySet(); System.out.println(set); //遍历该集合 Iterator it = set.iterator(); while(it.hasNext()){ Entry e = (Entry) it.next(); //返回该Entry中包含的key System.out.println(e.getKey()); //返回该Entry中包含的value System.out.println(e.getValue()); System.out.println("=============="); } } }
2.HashMap和Hashtable实现类
(1)HashMap和Hashtable实现类的关系类似于ArrayList和Vector的关系;
(2)HashMap和Hashtable的区别:
1)Hashtable是一个线程安全的Map实现,但是HashMap不是线程安全的;(虽然如此,但是当多个线程访问同一个Map集合时还是应该选用HashMap然后用Collections工具类把HashMap变成一个线程安全的集合,这样的方式比较好);
2)Hashtable不允许使用null作为key或者value,但是HashMap则可以使用null作为key或者value;
(3)HashMap使用null作为key和value的例子:
import java.util.HashMap; public class HashMapTest { public static void main(String[] args) { HashMap hm = new HashMap(); hm.put(null, null); hm.put(1, null); System.out.println(hm); } }
(4)与HashSet集合类似,HashMap和Hashtable也不能保证key-value对的顺序是按照输入顺序排列;
(5)HashMap和Hashtable中判断key相等的规则是:通过equals()方法判断两个key时返回值为treu,同时两个key的hashCode()方法返回值相等;判断两个value相等的方式是两个value通过equals()方法返回true;
(6)类似于HashSet,尽量不要在HashMap或者Hashtable中使用可变对象作为key,或者当可变对象作为key时不要修改该可变对象。
3.LinkedHashMap实现类
(1)LinkedHashMap是HashMap的子类,通过链表维护该集合的顺序,使其顺序与添加元素顺序相同;
(2)LinkedHashMap由于使用链表维护元素插入循序,性能要略低于HashMap,但是在迭代遍历中具有较好的性能;
(3)比较:
import java.util.HashMap; import java.util.LinkedHashMap; public class LinkedHashMapTest { public static void main(String[] args) { //创建一个HashMap集合 HashMap hm = new HashMap(); //添加元素 hm.put("diyige", "A"); hm.put("dierge", "B"); hm.put("disange", "C"); hm.put("disige", "D"); hm.put("diwuge", "E"); hm.put("diliuge", "F"); //遍历元素 for(Object obj : hm.keySet()){ String i = (String)obj; System.out.println(hm.get(i)); } System.out.println("==================="); //LinkedHashMap LinkedHashMap lhm = new LinkedHashMap(); lhm.put("diyige", "A"); lhm.put("dierge", "B"); lhm.put("disange", "C"); lhm.put("disige", "D"); lhm.put("diwuge", "E"); lhm.put("diliuge", "F"); for(Object obj:lhm.keySet()){ String i = (String)obj; System.out.println(lhm.get(i)); } } }
4.Properties
(1)Properties类是Hashtable的子类,它主要用于处理属性配置文件;
(2)因为属性配置文件中的“key=value”是字符串类型,所以Properties集合的key和value的类型都是String类型的;
(3)Properties的使用:
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; public class PropertiesTest { public static void main(String[] args) throws Exception{ Properties props = new Properties(); //向Properties中添加属性 props.setProperty("name", "abc"); props.setProperty("age", "18"); props.setProperty("sex", "男"); //保存到配置文件中 props.store(new FileOutputStream("test.ini"),"test"); //并生成配置文件 //创建新的Properties Properties props2 = new Properties(); //加载配置文件 props2.load(new FileInputStream("test.ini")); System.out.println(props2); //根据指定的key获取属性value System.out.println(props2.getProperty("name")); System.out.println(props2.getProperty("age")); System.out.println(props2.getProperty("sex")); } }
5.SortedMap接口和TreeMap实现类
(1)SortedMap接口和TreeMap实现类也同样类似于SortedSet接口和TreeSet实现类;
(2)TreeMap也可以使得所有在此集合中的key-value对保持有序的状态;
(3)同TreeSet一样,TreeMap也同样有两种排序方式:
1)自然排序:key元素对应的类必须实现Comparable接口;
2)定制排序:创建TreeMap时,为其关联实现一个Comparator接口;
(4)TreeMap的自然排序:
Teacher:
//使用自然排序,必须实现Comparable接口 public class Teacher implements Comparable{ private String name; private int age; public Teacher(){ } public Teacher(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 int compareTo(Object o) { // TODO Auto-generated method stub Teacher t = (Teacher)o; return this.age-t.age; } //应该实现equals()方法,其结果应该与compareTo()方法一致 }
TreeMapComparableTest:
import java.util.TreeMap; public class TreeMapComparableTest { public static void main(String[] args) { Teacher t1 = new Teacher("A",18); Teacher t2 = new Teacher("B",25); Teacher t3 = new Teacher("C",24); //创建TreeMap集合 TreeMap map = new TreeMap(); map.put(t1, "t1"); map.put(t2, "t2"); map.put(t3, "t3"); //遍历map集合 for(Object obj:map.keySet()){ Teacher t = (Teacher)obj; System.out.println(map.get(t)); } //结果按照年龄升序排列 } }
(5)TreeMap的定制排序:
import java.util.Comparator; import java.util.TreeMap; class Student{ String name; int age; public Student(){ } public Student(String name,int age){ this.name = name; this.age = age; } } public class TreeMapComparatorTest { public static void main(String[] args) { Student s1 = new Student("s1",18); Student s2 = new Student("s2",17); Student s3 = new Student("s3",19); Student s4 = new Student("s4",16); //创建一个TreeMap并且与其关联一个Comparator对象 TreeMap t = new TreeMap(new Comparator(){ @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub Student s1 = (Student)o1; Student s2 = (Student)o2; return s1.age-s2.age; }}); //添加元素 t.put(s1, "s1"); t.put(s2, "s2"); t.put(s3, "s3"); t.put(s4, "s4"); //遍历 for(Object obj:t.keySet()){ Student s = (Student)obj; System.out.println(t.get(s)); } System.out.println("=============="); //也可以使用Lambda表达式 TreeMap t2 = new TreeMap((o1,o2)->(((Student)o1).age-((Student)o2).age)); //添加元素 t2.put(s1, "s1"); t2.put(s2, "s2"); t2.put(s3, "s3"); t2.put(s4, "s4"); //遍历集合 for(Object obj:t2.keySet()){ Student s = (Student)obj; System.out.println(t2.get(obj)); } } }
6.WeakHashMap实现类
(1)WeakHashMap的用法类似于HashMap,区别在于HashMap的key保留了对实际对象的强引用,只要该HashMap对象不被销毁,则该HashMap中key所引用的对象就不会被垃圾回收,HashMap也不会自动删除这些key-value对;但WeakHashMap的key只保留了对实际对象的弱引用,如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,这些key所引用的对象可能被垃圾回收,WeakHashMap也能自动删除这些key所对应的key-value对;
(2)WeakHashMap的使用:
import java.util.WeakHashMap; public class WeakHashMapTest { public static void main(String[] args) { WeakHashMap wmap = new WeakHashMap(); //添加元素 wmap.put(new String("a"), "a"); wmap.put(new String("b"), "b"); wmap.put(new String("c"), "c"); wmap.put(new String("d"), "d"); wmap.put("e", "e"); wmap.put("f", "f"); wmap.put("g", "g"); System.out.println(wmap); //通知系统进行垃圾回收 System.gc(); System.out.println(wmap); //输出{e=e, g=g, f=f} } }
7.IdentityHashMap实现类
(1)IdentityHashMap实现类与HashMap实现类相似,不同的是IdentityHashMap在比较两个key相等时不同,在IdentityHashMap中,当两个key严格相等(key1==key2)时,才认为两个key相等;而在HashMap中,两个key通过equals返回true,并且两个key的hashcode值相同,则两个key相同;
(2)IdentityHashMap和HashMap一样允许使用null作为key和value,并且也不能保证顺序。
8.EnumMap
(1)EnumMap是一个与枚举类一起使用的Map,EnumMap中的key必须是单个枚举类中的枚举值。创建EnumMap时,必须显式指定或隐式指定它对应的枚举类;
(2)EnumMap特性:
1)在内部以数组形式保存,这种实现形式非常高效和紧凑;
2)根据key的自然顺序(枚举中的定义顺序)排列来维护key-value对的排列顺序;
3)不许使用null作为key,但可以使用null作为value;
(3)EnumMap的使用:
import java.util.EnumMap; enum Season{ SPRING,SUMMER,FALL,WINTER } public class EnumMapTest { public static void main(String[] args) { //以Season枚举类创建一个EnumMap EnumMap em = new EnumMap(Season.class); em.put(Season.FALL, "fall"); em.put(Season.WINTER, "winter"); em.put(Season.SPRING, "spring"); em.put(Season.SUMMER, "summer"); System.out.println(em); } }