java学习(16)
来源:互联网 发布:linux steam服务器 编辑:程序博客网 时间:2024/05/22 03:15
from: http://android.yaohuiji.com/archives/3414
ava基础第十六讲:集合(二)
本讲内容:Map HashMap
前面课程中我们知道Map是个接口,它关心的是映射关系,它里面的元素是成对出现的,键和值都是对象且键必须保持唯一。这一点上看它和Collection是很不相同的。
一、Map接口
Map接口的常用方法如下表所示:
put(K key, V value)向集合中添加指定的键值对putAll(Map <? extends K,? extends V> t)把一个Map中的所有键值对添加到该集合containsKey(Object key)如果包含该键,则返回truecontainsValue(Object value)如果包含该值,则返回trueget(Object key)根据键,返回相应的值对象keySet()将该集合中的所有键以Set集合形式返回values()将该集合中所有的值以Collection形式返回remove(Object key)如果存在指定的键,则移除该键值对,返回键所对应的值,如果不存在则返回nullclear()移除Map中的所有键值对,或者说就是清空集合isEmpty()查看Map中是否存在键值对size()查看集合中包含键值对的个数,返回int类型
因为Map中的键必须是唯一的,所以虽然键可以是null,只能由一个键是null,而Map中的值可没有这种限制,值为null的情况经常出现,因此get(Object key)方法返回null,有两种情况一种是确实不存在该键值对,二是该键对应的值对象为null。为了确保某Map中确实有某个键,应该使用的方法是 containsKey(Object key) 。
二、HashMap
HashMap是最常用的Map集合,它的键值对在存储时要根据键的哈希码来确定值放在哪里。
1、HashMap的基本使用:
import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;public class Test {public static void main(String[] args) {Map<Integer,String> map = new HashMap<Integer,String>();map.put(1, "白菜");map.put(2, "萝卜");map.put(3, "茄子");map.put(4, null);map.put(null, null);map.put(null, null);System.out.println("map.size()="+map.size());System.out.println("map.containsKey(1)="+map.containsKey(2));System.out.println("map.containsKey(null)="+map.containsKey(null));System.out.println("map.get(null)="+map.get(null));System.out.println("map.get(2)="+map.get(2));map.put(null, "黄瓜");System.out.println("map.get(null)="+map.get(null));Set set = map.keySet();System.out.println("set="+set);Collection<String> c = map.values();System.out.println("Collection="+c);}}
编译并运行程序,查看结果:
map.size()=5map.containsKey(1)=truemap.containsKey(null)=truemap.get(null)=nullmap.get(2)=萝卜map.get(null)=黄瓜set=[null, 1, 2, 3, 4]Collection=[黄瓜, 白菜, 萝卜, 茄子, null]
2、HashMap 中作为键的对象必须重写Object的hashCode()方法和equals()方法
下面看一个我花了1个小时构思的例子,熟悉龙枪的朋友看起来会比较亲切,设定了龙和龙的巢穴,然后把它们用Map集合对应起来,我们可以根据龙查看它巢穴中的宝藏数量,例子只是为了说明hashCode这个知识点,所以未必有太强的故事性和合理性,凑合看吧:
import java.util.HashMap;import java.util.Map;public class Test {public static void main(String[] args) {// 龙和它的巢穴映射表Map<dragon , Nest> map = new HashMap<dragon , Nest>();// 在Map中放入四只克莱恩大陆上的龙map.put(new Dragon("锐刃", 98), new Nest(98));map.put(new Dragon("明镜", 95), new Nest(95));map.put(new Dragon("碧雷", 176), new Nest(176));map.put(new Dragon("玛烈", 255), new Nest(255));// 查看宝藏System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());}}// 龙class Dragon {Dragon(String name, int level) {this.level = level;this.name = name;}// 龙的名字private String name;// 龙的级别private int level;public int getLevel() {return level;}public void setLevel(int level) {this.level = level;}public String getName() {return name;}public void setName(String name) {this.name = name;}}// 巢穴class Nest {//我研究的龙之常数final int DRAGON_M = 4162;// 宝藏private int treasure;// 居住的龙的级别private int level;Nest(int level) {this.level = level;this.treasure = level * level * DRAGON_M;}int getTreasure() {return treasure;}public int getLevel() {return level;}public void setLevel(int level) {this.level = level;this.treasure = level * level * DRAGON_M;}}
编译并运行查看结果:
Exception in thread "main" java.lang.NullPointerException at Test.main(Test.java:18)
我们发现竟然报了错误,第18行出了空指针错误,也就是说get方法竟然没有拿到预期的巢穴对象。
在这里我们就要研究一下为什么取不到了。我们这里先解释一下HashMap的工作方式。
假设现在有个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(),我们把上面的例子加上这两个方法再试试看:
import java.util.HashMap;import java.util.Map;public class Test {public static void main(String[] args) {// 龙和它的巢穴映射表Map<dragon , Nest> map = new HashMap<dragon , Nest>();// 在Map中放入四只克莱恩大陆上的龙map.put(new Dragon("锐刃", 98), new Nest(98));map.put(new Dragon("明镜", 95), new Nest(95));map.put(new Dragon("碧雷", 176), new Nest(176));map.put(new Dragon("玛烈", 255), new Nest(255));// 查看宝藏System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());}}// 龙class Dragon {Dragon(String name, int level) {this.level = level;this.name = name;}// 龙的名字private String name;// 龙的级别private int level;public int getLevel() {return level;}public void setLevel(int level) {this.level = level;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int hashCode() {final int PRIME = 31;int result = 1;result = PRIME * result + level;result = PRIME * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;final Dragon other = (Dragon) obj;if (level != other.level)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}// 巢穴class Nest {//我研究的龙之常数final int DRAGON_M = 4162;// 宝藏private int treasure;// 居住的龙的级别private int level;Nest(int level) {this.level = level;this.treasure = level * level * DRAGON_M;}int getTreasure() {return treasure;}public int getLevel() {return level;}public void setLevel(int level) {this.level = level;this.treasure = level * level * DRAGON_M;}}
编译并运行查看结果:
碧雷巢穴中有多少宝藏:128922112
这一次正常输出了,真不容易^_^
好了本讲就到这里。
Java基础的东西先告一段落,从明天开始继续Android之旅。
- java学习(16)
- java学习(16)
- 【java】java学习(一)
- 【java】java学习(二)
- Java学习笔记18天---(16)
- 我的java学习日记(16)
- Java学习笔记16
- java学习笔记16
- Java学习笔记16
- Java学习-16天
- Java学习16 线程
- java学习总结(16.05.16) java的修饰符
- java并发编程实践学习(16)Java存储模型
- Java学习(途径!)
- 学习JAVA(一)
- 学习Java(一)
- java学习(1)
- java学习(2)
- 如何在VS中添加命令行参数
- csdn 提示页面 访问不了。6.14 12点
- java学习(15)
- 钉子的故事——你是否选择iBatis?
- vs中配置命令行参数&&VS中添加opencv2.2的静态链接库文件
- java学习(16)
- [分享] 数据库服务管理脚本,超好用! 支持oracle,mysql,sqlserver,tomcat(本人在源程序上修改的)
- java学习(17)
- java学习(17)
- HTML 滚动效果
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大系列集锦
- 软件项目管理师复习指南十一:项目成本管理
- java学习(18)
- MongoDB与CouchDB全方位对比