黑马程序员-JAVA基础-Java 集合之Map 接口

时间:2023-02-18 15:39:45

------- android培训java培训、期待与您交流! ----------

  Map 用于保存具有映射关系的数据,因此Map 集合里保存者两组值,一组值用于保存Map 里的Key ,另一组值用于保存Map 里的Value ,其中key 和 value 都是可以是任何引用类型的数据。

  注意:Map 的key 不允许重复,且通过指定的key,总能找到唯一的、确定的value。即key 和 value 之间存在单向一对一关系。

  Map 接口的经常用到的实现类:HashMap、Hashtable和TreeMap。

 

一.Map 集合中的共性方法

  1、添加:

  > V put(K key, V value) : 添加一个key-value 对,如果当前Map中已有一个与该key 相等的key-value 对,则新的key-value 对会覆盖原来的,并返回原来的value。

  > void putAll(Map<? extends K,? extends V> m)  从指定映射中将所有映射关系复制到此映射中。

  2、删除:

  > void clear() : 从此映射中移除所有映射关系 。

  > V remove(Object key)  如果存在一个键的映射关系,则将其从此映射中移除 , 并返回 value 。

  3、判断:

  > boolean containsKey(Object key) :如果Map 中包含指定key ,则返回 true

  > boolean containsValue(Object value) : 如果Map 中包含一个或多个value , 则返回true。

  > boolean isEmpty() : 如果Map 为空,则返回true 。

  4、获取:

  > V get(Object key) 返回key 对应的value , 如果没有则返回null 。

  > int size() 返回Map 中 key-value 对的个数。

  > Collection values() : 返回该Map 里所有value 组成的Collection 。 

 1 public class MapDemo {
 2     public static void main(String[] args)
 3     {
 4 //        定义个 HashMap 集合, key 和 value的类型都为String。
 5         Map<String, String> map = new HashMap<String, String>() ; 
 6 //        添加元素
 7         map.put("诛仙", "萧鼎") ;
 8         map.put("笑傲江湖", "金庸") ; 
 9         map.put("神雕侠侣", "金庸") ; 
10         map.put("陆小凤传奇", "古龙") ; 
11         System.out.println(map); 
12         System.out.println(map.put("笑傲江湖", "金——庸"));
13         System.out.println(map);
14 //        删除元素
15         System.out.println(map.remove("笑傲江湖") );
16         System.out.println(map);
17 //        获取元素
18         System.out.println(map.get("诛仙")); 
19 //        获取元素个数
20         System.out.println(map.size());
21 //        判断
22         System.out.println(map.containsKey("诛仙"));
23     }
24 }

   

 

二.HashMap 和 Hashtable 实现类:

  HashMap 和 Hashtable 它们之间的关系完全类似于 ArrayList 和 Vector 的关系。它们两个底层都是哈希表数据结构,两者的区别:

  1、Hashtable 不可以存入null 键和null 值;但是HashMap 可以存入null 键和null 值。

  2、hashtable 是线程安全Map 实现;但HashMap 是线程不安全的实现类。所以HashMap 性能比较高点。

 1 public class HashMapDemo {
 2     public static void main(String[] args)
 3     {
 4         Map<String,String> hash  = new HashMap<String, String>() ;
 5         
 6 //        给HashMap 集合存入null键或者null值
 7         hash.put("111", null) ; 
 8         hash.put(null, "1112") ;
 9 //        取出的结果为 1112
10         System.out.println(hash.get(null));
11         Map<String,String> table = new Hashtable<String, String>() ; 
12 //        下面的代码会出现运行异常:NullPointerException
13         table.put("111", null) ; 
14         table.put(null, "1112") ;
15         System.out.println(table.get(null));
16     }
17 }

 

  类似HashSet , HashMap 和 Hashtable 也不能保证其中的key-value 对的顺序。它们判断两个key的标准也是:

  1、先判断两个key 的hashCode 值是不是相等,

  2、如果相等则再调用equals方法的返回值来进行判断。返回true 表示两个key值一样;返回false 表示不一样。 

 1 class Writer
 2 {
 3     private String name ; 
 4     public Writer(String name)
 5     {
 6         this.name = name ; 
 7     }
 8 //    get方法
 9     public String getName()
10     {
11         return name ;
12     }
13 //    重写hashCode方法
14     public int hashCode()
15     {
16         System.out.println(this.name+"---------hashCode--------");
17         return this.name.hashCode() ; 
18     }
19 //    重写equals方法
20     public boolean equals(Object o)
21     {
22         if (!(o instanceof Writer))
23             throw new  RuntimeException() ;   
24         Writer w = (Writer) o ; 
25         System.out.println(name+"---------equals--------"+w.name);
26         return this.name.equals(w.getName()) ; 
27     }
28 }
29 public class MapDemo1 {
30     public static void main(String[] args)
31     {
32 //        定义个 HashMap 集合, key 的存储的数据类型为Writer, value的类型为String。
33         Map<Writer,String> writerMap = new HashMap<Writer,String>() ; 
34         
35 //        添加元素:
36         writerMap.put(new Writer("金庸"), "笑傲江湖") ;
37         writerMap.put(new Writer("萧鼎"), "诛仙") ;
38         writerMap.put(new Writer("金庸"), "笑傲江湖") ;
39         
40         System.out.println(writerMap);
41     }
42 }

 

  

    

三.TreeMap 实现类

  TreeMap 实现的的底层是二叉树的数据结构。线程是不同步的,其特点是:TreeMap 会对集合中所有 key 进行排序;也有两种排序方式:

  1、自然排序: TreeMap 的所有key 必须实现Comparable 接口,而且所有key 必须是同一类对象。

  2、制定排序: 编写比较器。在创建集合容器时将比较器传入至集合构造器。 

 1 //创建Books类并且 实现Comparable 接口
 2 //如果Books的名字和编号都相同则表示同一本书
 3 class Books implements Comparable<Books>
 4 {
 5     private String name ; 
 6     private String id ;
 7     public Books(String name , String id )
 8     {
 9         this.name = name ; 
10         this.id = id ; 
11     }
12 //    get方法
13     public String getName()
14     {
15         return name ;
16     }
17     public String getId()
18     {
19         return id ;
20     }
21     
22 //    覆盖compareTo 方法
23     public int compareTo(Books b)
24     { 
25         int num = this.id.compareTo(b.getId()) ;
26         if (num == 0)
27         {
28             return this.name.compareTo(b.getName()) ;
29         }
30         return num ;
31     }
32 //    重写hashCode 方法
33     public int hashCode()
34     {
35         return this.name.hashCode()+ this.id.hashCode() ;
36     }
37 //    重写equals 方法
38     public boolean equals(Object o)
39     {
40         if (!(o instanceof Books))
41             throw new RuntimeException() ;
42         Books b = (Books) o ;
43         return this.name.equals(b.getName())&& this.id.equals(b.getId()) ;
44     }
45 }
46 public class TreeMapDemo {
47     public static void main(String[] args)
48     {
49         Map<Books,String> bookMap = new TreeMap<Books, String> () ;
50         
51         bookMap.put(new Books("笑傲江湖","000001"), "金庸") ;
52         bookMap.put(new Books("笑傲江湖","000002"), "金庸") ;
53         bookMap.put(new Books("笑傲江湖","000004"), "金庸") ;
54         bookMap.put(new Books("笑傲江湖","000003"), "金庸") ;
55         bookMap.put(new Books("神雕侠侣","000001"), "金庸") ;
56         
57 //        取出方式:entry()  
58         Set<Entry<Books, String>> bookEntry = bookMap.entrySet() ;
59         Iterator<Map.Entry<Books, String>> itEntry = bookEntry.iterator() ;
60         while(itEntry.hasNext())
61         {
62             Map.Entry<Books, String> entry = itEntry.next() ; 
63             System.out.println("name:" + entry.getKey().getName() +
64                     "  id:" + entry.getKey().getId() +
65                     "  作者: " + entry.getValue());
66         } 
67     }
68 }

 

  

 

 

四.Map 集合的两种取出方式:

  因为 Map集合中没有Iterator 迭代器,所以如果想将Map 集合中的元素遍历以便就要能用到下面两个方法:

  1、Set<Map.Entry<K,V>> entrySet() :返回此映射中包含的映射关系的 Set 视图。映射关系为 Map.Entry<K,V>类型 ;

  2、Set<K> keySet():将Map 中所有的键存入到Set集合中 ;

  原理是:将Map 集合中的元素取出保存到Set 集合中,再根据Set 集合中的Iterator 迭代器取出。

  

 

  4.1 、 entrySet() 

  Map.Entry<K,V> 为一个接口(Map 接口中的内部类),其用法和 Iterator 接口类似。该接口包含如下方法

  > boolean equals(Object o) : 比较指定对象与此项的相等性。 

  > K getKey() :  返回与此项对应的键。 

  > V getValue() : 返回与此项对应的值。  

  > int hashCode() : 返回此映射项的哈希码值。

  > V setValue(V value) : 用指定的值替换与此项对应的值 。 

 

  步骤如下: 

  1、先获取Map 集合中的key-value 对的关系Set<Map.Entry<K,V>> 集合。 

  2、获取 Set  集合的迭代器。 

  3、遍历取出。 

 1 class Writer
 2 {
 3     private String name ; 
 4     public Writer(String name)
 5     {
 6         this.name = name ; 
 7     }
 8 //    get方法
 9     public String getName()
10     {
11         return name ;
12     }
13 //    重写hashCode方法
14     public int hashCode()
15     { 
16         return this.name.hashCode() ; 
17     }
18 //    重写equals方法
19     public boolean equals(Object o)
20     {
21         if (!(o instanceof Writer))
22             throw new  RuntimeException() ;   
23         Writer w = (Writer) o ;  
24         return this.name.equals(w.getName()) ; 
25     }
26 }
27 public class MapDemo1 {
28     public static void main(String[] args)
29     {
30 //        定义个 HashMap 集合, key 的存储的数据类型为Writer, value的类型为String。
31         Map<Writer,String> writerMap = new HashMap<Writer,String>() ; 
32         
33 //        添加元素:
34         writerMap.put(new Writer("金庸"), "笑傲江湖") ;
35         writerMap.put(new Writer("萧鼎"), "诛仙") ;
36         writerMap.put(new Writer("古龙"), "流星蝴蝶剑") ;
37         
38 //        System.out.println(writerMap);
39 //        将Map 元素取出存入Set 集合,指定该Set集合只能存入MapEntry<>数据类型。
40         Set<Map.Entry<Writer, String>> setMap = writerMap.entrySet() ;
41 //        建立迭代器
42         Iterator<Map.Entry<Writer,String>> it = setMap.iterator() ;
43         while(it.hasNext())
44         {
45 //            取出key-value 对 
46             Map.Entry<Writer, String> entry = it.next() ; 
47             System.out.println("key:"+ entry.getKey().getName()+
48                     "value:"+ entry.getValue()); 
49         }
50     }
51 }

 

 

  4.2 keySet() :  

  步骤:

  1、先获取Map集合的所有键的Set集合。

  2、获取Set集合的迭代器。

  3、遍历。通过Mao集合get方法获取其对应的值。

 1 class Writer
 2 {
 3     private String name ; 
 4     public Writer(String name)
 5     {
 6         this.name = name ; 
 7     }
 8 //    get方法
 9     public String getName()
10     {
11         return name ;
12     }
13 //    重写hashCode方法
14     public int hashCode()
15     { 
16         return this.name.hashCode() ; 
17     }
18 //    重写equals方法
19     public boolean equals(Object o)
20     {
21         if (!(o instanceof Writer))
22             throw new  RuntimeException() ;   
23         Writer w = (Writer) o ;  
24         return this.name.equals(w.getName()) ; 
25     }
26 }
27 public class MapDemo1 {
28     public static void main(String[] args)
29     {
30 //        定义个 HashMap 集合, key 的存储的数据类型为Writer, value的类型为String。
31         Map<Writer,String> writerMap = new HashMap<Writer,String>() ; 
32         
33 //        添加元素:
34         writerMap.put(new Writer("金庸"), "笑傲江湖") ;
35         writerMap.put(new Writer("萧鼎"), "诛仙") ;
36         writerMap.put(new Writer("古龙"), "流星蝴蝶剑") ;
37 //        取出key ,存入Set 集合
38         Set<Writer> setMap = writerMap.keySet() ; 
39 //        获取Set集合迭代器
40         Iterator<Writer> it = setMap.iterator() ; 
41         while(it.hasNext())
42         {
43             Writer w = it.next() ;
44             System.out.println("key:"+w.getName() +
45                     "value:" + writerMap.get(w));
46         }
47 
48     }
49 }

 

 

五.Map 集合练习:

  1、要求: 

  每个学生都有一个归属地。

  学生Student , 地址 String

  学生的属性:姓名、年龄 

  注意:姓名和年龄相同的视为同一个学生。  

 1 class Student  
 2 {
 3     private String name ; 
 4     private int age ; 
 5     public Student(String name , int age)
 6     {
 7         this.name = name ; 
 8         this.age = age ; 
 9     }
10 //    get方法:
11     public String getName()
12     {
13         return name ;
14     }
15     public int getAge()
16     {
17         return age ;
18     }
19 //    instanceof 判断函数:
20     private Student myIstanceof(Object o)
21     {
22         if (!(o instanceof Student))
23             throw new RuntimeException() ;
24         return (Student) o ; 
25     }
26 //    重写equals 方法
27     public boolean equals(Object o)
28     { 
29         Student stu =  myIstanceof(o);
30         return this.name.equals(stu.getName()) && this.age == stu.getAge() ;
31     }
32 //    重写hashCode方法
33     public int hashCode()
34     {
35          return name.hashCode()+age*39 ;
36     } 
37 }
38 public class Demo {
39     public static void main(String[] args)
40     {
41 //        创建Map 类:
42         Map<Student,String> stuMap = new HashMap<Student, String>() ; 
43         
44         stuMap.put(new Student("lisi002" , 11), "北京" ) ;
45         stuMap.put(new Student("lisi001" , 14), "上海" ) ;
46         stuMap.put(new Student("lisi005" , 10), "天津" ) ;
47         stuMap.put(new Student("lisi005" , 19), "天津" ) ;
48         stuMap.put(new Student("lisi001" , 19), "长沙" ) ;
49 
50         stuMap.put(new Student("lisi001" , 14), "北京" ) ; 
51         
52 //        第一种取出方式:keySet() 
53         Set<Student> stuSet = stuMap.keySet() ; 
54         Iterator<Student> it = stuSet.iterator() ;  
55         while(it.hasNext())
56         {
57             Student stu = it.next() ;
58             System.out.println("name:"+stu.getName()
59                     +"  age:"+stu.getAge() + "  地址:" + stuMap.get(stu));
60         } 
61         System.out.println("------我是分割线------");
62 //        第二种取出方式:entry()  
63         Set<Map.Entry<Student, String>> stuEntry = stuMap.entrySet() ;
64         Iterator<Map.Entry<Student, String>> itEntry = stuEntry.iterator() ;
65         while(itEntry.hasNext())
66         {
67             Map.Entry<Student, String> entry = itEntry.next() ; 
68             System.out.println("name:" + entry.getKey().getName() +
69                     "  age:" + entry.getKey().getAge() +
70                     "  地址: " + entry.getValue());
71         }
72     }  
73 }

  

   2、字母出现的次数: 

  输入一段字符串,获取该字符串中的字母出现的次数。

  希望打印结果:

  字母1(次数)字母2(次数)....

  通过结果发现,每一个字母都有对应的次数,说明字母和次数间有对应关系。

 1 public class TreeMapTest {
 2     public static void main(String[] args)
 3     {
 4         Scanner scan = new Scanner(System.in) ;
 5         String str = scan.nextLine() ;
 6         Map<Character,Integer> CNTree  = new TreeMap<Character, Integer>() ;
 7 //        存入Map集合。
 8         char[] chs = str.toCharArray() ;
 9         for (int i = 0 ; i < chs.length ; i ++)
10         {
11             Integer values = CNTree.get(chs[i])  ;
12             
13             if (values == null )
14                 CNTree.put(chs[i], 1) ; 
15             else 
16                 CNTree.put(chs[i], values+1) ; 
17         }
18         
19 //        遍历Map集合
20         Set<Character> charSet = CNTree.keySet() ; 
21         Iterator<Character> it = charSet.iterator() ; 
22         while(it.hasNext())
23         {
24             Character character = it.next() ;
25             System.out.println(character.charValue() +"   "+ CNTree.get(character));
26         }
27     } 
28 } 

 

  思路:

  1、将字符串转换成字符数组(因为要对每一个字母进行操作)。

  2、定义一个map集合,使用TreeMap 集合。

  3、遍历字符数组:

    a、将每一个字母作为键去查Map集合。

    b、如果返回null,将该字母和1存入Map集合中。

    c、如果返回不是null,则自增后,存入Map集合中。

  4、将Map集合中的数据打印。