道招

Java基础第十六讲:集合(二)

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

Java基础第十六讲:集合(二)

本讲内容:Map HashMap 前面课程中我们知道Map是个接口,它关心的是映射关系,它里面的元素是成对出现的,键和值都是对象且键必须保持唯一。这一点上看它和Collection是很不相同的。 一、Map接口 Map接口的常用方法如下表所示:
put(K key, V value) 向集合中添加指定的键值对
putAll(Map <? extends K,? extends V> t) 把一个Map中的所有键值对添加到该集合
containsKey(Object key) 如果包含该键,则返回true
containsValue(Object value) 如果包含该值,则返回true
get(Object key) 根据键,返回相应的值对象
keySet() 将该集合中的所有键以Set集合形式返回
values() 将该集合中所有的值以Collection形式返回
remove(Object key) 如果存在指定的键,则移除该键值对,返回键所对应的值,如果不存在则返回null
clear() 移除Map中的所有键值对,或者说就是清空集合
isEmpty() 查看Map中是否存在键值对
size() 查看集合中包含键值对的个数,返回int类型
  因为Map中的键必须是唯一的,所以虽然键可以是null,只能由一个键是null,而Map中的值可没有这种限制,值为null的情况经 常出现,因此get(Object key)方法返回null,有两种情况一种是确实不存在该键值对,二是该键对应的值对象为null。为了确保某Map中确实有某个键,应该使用的方法是 containsKey(Object key) 。 二、HashMap HashMap是最常用的Map集合,它的键值对在存储时要根据键的哈希码来确定值放在哪里。 1、HashMap的基本使用:  
01 import java.util.Collection;
02 import java.util.HashMap;
03 import java.util.Map;
04 import java.util.Set;
05
06 public class Test {
07
08     public static void main(String[] args) {
09
10         Map<Integer,String> map = new HashMap<Integer,String>();
11
12         map.put(1, "白菜");
13         map.put(2, "萝卜");
14         map.put(3, "茄子");
15         map.put(4, null);
16         map.put(null, null);
17         map.put(null, null);
18
19         System.out.println("map.size()="+map.size());
20         System.out.println("map.containsKey(1)="+map.containsKey(2));
21         System.out.println("map.containsKey(null)="+map.containsKey(null));
22         System.out.println("map.get(null)="+map.get(null));
23
24         System.out.println("map.get(2)="+map.get(2));
25         map.put(null, "黄瓜");
26         System.out.println("map.get(null)="+map.get(null));
27
28         Set set = map.keySet();
29         System.out.println("set="+set);
30
31         Collection<String> c = map.values();
32
33         System.out.println("Collection="+c);
34
35     }
36
37 }
编译并运行程序,查看结果:
1 map.size()=5
2 map.containsKey(1)=true
3 map.containsKey(null)=true
4 map.get(null)=null
5 map.get(2)=萝卜
6 map.get(null)=黄瓜
7 set=[null, 1, 2, 3, 4]
8 Collection=[黄瓜, 白菜, 萝卜, 茄子, null]
2、HashMap 中作为键的对象必须重写Object的hashCode()方法和equals()方法 下面看一个我花了1个小时构思的例子,熟悉龙枪的朋友看起来会比较亲切,设定了龙和龙的巢穴,然后把它们用Map集合对应起来,我们可以根据龙查看它巢穴中的宝藏数量,例子只是为了说明hashCode这个知识点,所以未必有太强的故事性和合理性,凑合看吧:
01 import java.util.HashMap;
02 import java.util.Map;
03
04 public class Test {
05
06     public static void main(String[] args) {
07
08         // 龙和它的巢穴映射表
09         Map<dragon , Nest> map = new HashMap<dragon , Nest>();
10
11         // 在Map中放入四只克莱恩大陆上的龙
12         map.put(new Dragon("锐刃", 98), new Nest(98));
13         map.put(new Dragon("明镜", 95), new Nest(95));
14         map.put(new Dragon("碧雷", 176), new Nest(176));
15         map.put(new Dragon("玛烈", 255), new Nest(255));
16
17         // 查看宝藏
18         System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
19     }
20
21 }
22
23 // 龙
24 class Dragon {
25
26     Dragon(String name, int level) {
27         this.level = level;
28         this.name = name;
29     }
30
31     // 龙的名字
32     private String name;
33
34     // 龙的级别
35     private int level;
36
37     public int getLevel() {
38         return level;
39     }
40
41     public void setLevel(int level) {
42         this.level = level;
43     }
44
45     public String getName() {
46         return name;
47     }
48
49     public void setName(String name) {
50         this.name = name;
51     }
52
53 }
54
55 // 巢穴
56 class Nest {
57
58     //我研究的龙之常数
59     final int DRAGON_M = 4162;
60
61     // 宝藏
62     private int treasure;
63
64     // 居住的龙的级别
65     private int level;
66
67     Nest(int level) {
68         this.level = level;
69         this.treasure = level * level * DRAGON_M;
70     }
71
72     int getTreasure() {
73         return treasure;
74     }
75
76     public int getLevel() {
77         return level;
78     }
79
80     public void setLevel(int level) {
81         this.level = level;
82         this.treasure = level * level * DRAGON_M;
83     }
84
85 }
编译并运行查看结果:
1 Exception in thread "main" java.lang.NullPointerException
2     at Test.main(Test.java:18)
我们发现竟然报了错误,第18行出了空指针错误,也就是说get方法竟然没有拿到预期的巢穴对象。 在这里我们就要研究一下为什么取不到了。我们这里先解释一下HashMap的工作方式。 image 假设现在有个6张中奖彩票的存根,放在5个桶里(彩票首位只有1-5,首位是1的就放在一号桶,是2的就放在2号桶,依次类推),现在你拿了3张彩 票来兑奖,一个号码是113,一个号码是213,一个号码是313。那么现在先兑第一张,取出一号桶里的存根发现存根号码和你的号码不符,所以你第一张没 中奖。继续兑第二张,二号桶里就没存根所以就直接放弃了,把三号桶里的所有彩票存根都拿出来对应一番,最后发现有一个存根恰好是313,那么恭喜你中奖 了。 HashMap在确定一个键对象和另一个键对象是否是相同时用了同样的方法,每个桶就是一个键对象的散列码值,桶里放的就是散列码相同的彩票存根, 如果散列码不同,那么肯定没有相关元素存在,如果散列码相同,那么还要用键的equals()方法去比较是否相同,如果相同才认为是相同的键。简单的说就 是 hashCode()相同 && equals()==true 时才算两者相同。 到了这里我们应该明白了,在没有重写一个对象的hashcode()和equals()方法之前,它们执行的是Object中对应的方法。而 Object的hashcode()是用对象在内存中存放的位置计算出来的,每个对象实例都不相同。Object的equals()的实现更简单就是看两 个对象是否==,也就是两个对象除非是同一个对象,否则根本不会相同。因此上面的例子虽然都是名字叫碧雷的龙,但是HashMap中却无法认可它们是相同 的。 因此我们只有重写Key对象的hashCode()和equals()方法,才能避免这种情形出现,好在Eclipse可以帮我们自动生成一个类的hashCode()和equals(),我们把上面的例子加上这两个方法再试试看:
001 import java.util.HashMap;
002 import java.util.Map;
003
004 public class Test {
005
006     public static void main(String[] args) {
007
008         // 龙和它的巢穴映射表
009         Map<dragon , Nest> map = new HashMap<dragon , Nest>();
010
011         // 在Map中放入四只克莱恩大陆上的龙
012         map.put(new Dragon("锐刃", 98), new Nest(98));
013         map.put(new Dragon("明镜", 95), new Nest(95));
014         map.put(new Dragon("碧雷", 176), new Nest(176));
015         map.put(new Dragon("玛烈", 255), new Nest(255));
016
017         // 查看宝藏
018         System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
019     }
020
021 }
022
023 // 龙
024 class Dragon {
025
026     Dragon(String name, int level) {
027         this.level = level;
028         this.name = name;
029     }
030
031     // 龙的名字
032     private String name;
033
034     // 龙的级别
035     private int level;
036
037     public int getLevel() {
038         return level;
039     }
040
041     public void setLevel(int level) {
042         this.level = level;
043     }
044
045     public String getName() {
046         return name;
047     }
048
049     public void setName(String name) {
050         this.name = name;
051     }
052
053     @Override
054     public int hashCode() {
055         final int PRIME = 31;
056         int result = 1;
057         result = PRIME * result + level;
058         result = PRIME * result + ((name == null) ? 0 : name.hashCode());
059         return result;
060     }
061
062     @Override
063     public boolean equals(Object obj) {
064         if (this == obj)
065             return true;
066         if (obj == null)
067             return false;
068         if (getClass() != obj.getClass())
069             return false;
070         final Dragon other = (Dragon) obj;
071         if (level != other.level)
072             return false;
073         if (name == null) {
074             if (other.name != null)
075                 return false;
076         } else if (!name.equals(other.name))
077             return false;
078         return true;
079     }
080
081 }
082
083 // 巢穴
084 class Nest {
085
086     //我研究的龙之常数
087     final int DRAGON_M = 4162;
088
089     // 宝藏
090     private int treasure;
091
092     // 居住的龙的级别
093     private int level;
094
095     Nest(int level) {
096         this.level = level;
097         this.treasure = level * level * DRAGON_M;
098     }
099
100     int getTreasure() {
101         return treasure;
102     }
103
104     public int getLevel() {
105         return level;
106     }
107
108     public void setLevel(int level) {
109         this.level = level;
110         this.treasure = level * level * DRAGON_M;
111     }
112
113 }
编译并运行查看结果:
1 碧雷巢穴中有多少宝藏:128922112
这一次正常输出了,真不容易^_^ 好了本讲就到这里。 分享至上:分享源头
更新时间:
上一篇:Java基础第十五讲:集合(一)下一篇:Java基础第十七讲:异常处理(一)

相关文章

Java基础第十五讲:集合(一)

本讲内容:集合 collection 讲集合collection之前,我们先分清三个概念: collection 集合,用来表示任何一种数据结构 Collection 集合接 阅读更多…

关注道招网公众帐号
道招开发者二群