标签:
MapDemo1 Map接口的常用方法
/** * java.util * Map接口<K,V> 类型参数: K - 此映射所维护的键的类型 V - 映射值的类型 定义: Map是一个接口,又称作查找表 java提供了一组可以以键值对(key-value)的形式存储数据的数据结构, 这种数据结构成为Map。我们可以看成是一个多行两列的表格,一列是存放key,一列存放value. 而每一行就相当于一组 key-value对,表示一组数据. 注意: 1.Map对存入元素有一个要求,就是key不能重复,所谓key不能重复,就是不能有两个equals 结果为true的key. 2.Map对于key,value的类型没有严格要求,只要是引用类型均可。 常用实现类: Map接口根据内部结构不同有很多实现类,其中常用的有内部为hash表实现的HashMap 还有内部为排序二叉树实现的TreeMap 1.HashMap<K,V> (散列表,哈希表,散列算法实现) 2.TreeMap<K,V> 常用方法: 1. 存入数据 : V put(K key,V value) 同样也是替换数据的value的方法. Map要求key不允许重复: 即Map中不能出现两个key的equals判断为true。 若使用相同的key则是替换value操作,put方法会将被替换的value返回。 若给定的不是重复的key,返回值为null。 还有一种可能的现象,即一种key存在并关联的value值为null,存入相同key时, 也会返回null. 2. 获取数据: V get(Object key) 该方法的作用就是根据给定的key去查找Map中对应的value并返回, 若当前Map中不包含给定的key,那么返回值为null。 3. 检测是否包含给定的key: boolean containsKey (Object key) 该方法的作用是查找Map中是否包含有给定的key. 若当前Map中包含给定的key(这里检查是否包含是根据key的equals比较结果为依据的。) 4. 移除数据: V remove(Object key) 该方法的作用将给定的key 对应的(key-value)对删除.返回被删除的value值. */ public class MapDemo1 { public static void main(String[] args) { //1.创建一个Map接口的实现类HashMap Map<String,Integer> scoreMap = new HashMap<String,Integer>(); /* * 2.将给定的key-value存入到Map中。 * 注意: * 因为Map不允许包含重复的key存在,所以若有两个key的equals判断结果为true, * 那么put方法会替换并返回原来的value值. * 若没有相同的key存在时,put方法的返回值为null. */ Integer returnValue = scoreMap.put("语文", 99); /*此时因为Map中没有key.equals("语文"), 所以put方法返回值应该是null,*/ System.out.println("第一次实验性输出语句 put方法返回值是 :"+returnValue); /*在此处,输出语句,试验一下,输出put返回值,检验是否是null. 输出结果是null, 那么证明当存入Map的key值时,无相同的key时,返回值为null.*/ //加入一批key-value对到scoreMap中 scoreMap.put("英语",97); scoreMap.put("物理",92); scoreMap.put("政治",80); System.out.println("scoreMap表: "+scoreMap); /* * 思考?如果有一个名为"数学"这个key值原来就存在,并关联的value值是null, * 则put会返回什么结果? * */ scoreMap.put("数学",null); returnValue = scoreMap.put("数学", 98); System.out.println("第二次实验性输出语句 put方法返回值是 :"+returnValue); /*根据上面的思考,我们做个测试,先放入"数学"key关联value值为null * 输出结果同样是null.证明即还有一种可能的现象,当一种key存在并关联的value值为null, * 存入相同key时,也会返回null.*/ /* * 3.获取数据的方法 * V get (Object key) * 获取指定的key所对应的value,若指定的key在Map中不存在,则返回null */ returnValue = scoreMap.get("语文"); System.out.println("语文的成绩: "+returnValue); //语文的成绩: 99 /* 4.检查是否包含"体育"这个key*/ boolean containSport = scoreMap.containsKey("体育"); System.out.println("是否包含体育的结果: "+containSport); //是否包含体育的结果: false /* * 5.删除数据的方法 */ returnValue = scoreMap.remove("数学"); System.out.println("删除的数学value值为: "+returnValue); //删除的数学value值为: 98 } }
MapDemo2 Map的遍历
/** * Map的遍历 遍历Map有三种方式: 1:遍历所有的key: Set<K> keySet() 返回值: Set集合(因为Set集合是无序,不可重复的,而Map的key正好是无序的,不可重复的) 2:遍历所有的key-value对: Set<Map.Entry<K,V>> entrySet() 返回值: Set集合 上面的方法可以理解成: Set<Entry> entrySet() 注意: 1.这里的Entry(Map.Entry)是Map的内部类,每一个Entry实例都表示Map中的一组key-value对 2.Entry提供了获取key,value的方法: K getKey() , V getValue() 3.entrySet方法则是将每一组key-value对(即:若干Entry实例)存入一个Set集合后返回。 3:遍历所有的value(相对不常用) Collection<V> values() 返回值: Collection<V>集合 将Map中所有的value存入一个集合后返回。 注意: 因为value可以重复,所以不能是Set集来接收了. 总结: 1.三种遍历方式,相对复杂的是第2个.但三种实用性不高,单纯的取出value值意义不大,除非有特别的用处. 2.遍历key和遍历entry(key-value)对,注意用Set集接收,因为是不重复无序的集合. 3.遍历entry注意书写格式.还有entry代表的是一组数据. */ public class MapDemo2 { public static void main(String[] args) { //定义一个Map接口的实现类HashMap的对象. Map<String,Integer> scoreMap = new HashMap<String,Integer>(); //添加一批数据 scoreMap.put("语文", 90); scoreMap.put("数学", 82); scoreMap.put("化学", 66); scoreMap.put("政治", 67); scoreMap.put("历史", 80); /* * 1.遍历所有的key 方法 Set<K> keySet() * */ Set<String> scoreKeySet = scoreMap.keySet(); //注意返回值为Set<K> 集合. //遍历Set集合(新循环或者迭代器) for(String key: scoreKeySet){ System.out.println("遍历scoreMap表的key值 : "+key); /* 输出结果: 遍历scoreMap表的key值 : 政治 遍历scoreMap表的key值 : 历史 遍历scoreMap表的key值 : 数学 遍历scoreMap表的key值 : 化学 遍历scoreMap表的key值 : 语文 */ } /* * 2.遍历所有的key-value对方法 Set<Entry> entrySet() * 注意: Entry是个实例,每一个Entry实例, 代表的是Key和Value对一组数据. * 遍历时,也应当注意书写格式 .循环体内,用Entry自己的get方法,获取key和value的值. */ Set<Entry<String,Integer>> scoreEntrySet = scoreMap.entrySet(); for(Entry<String,Integer> entry : scoreEntrySet){ String subject = entry.getKey(); Integer score = entry.getValue(); System.out.println("科目 :" + subject + " 分数 :" + score); /* 输出结果: 科目 :政治 分数 :67 科目 :历史 分数 :80 科目 :数学 分数 :82 科目 :化学 分数 :66 科目 :语文 分数 :90 */ } /* * 3.遍历所有的Value值(不常用) Collection<V> values() * 注意: 因为value可以重复,所以不能是Set集来接收了. */ Collection<Integer> valueCollect = scoreMap.values(); for(Integer value:valueCollect){ System.out.println("分数:"+ value); /* 输出结果: 分数:67 分数:80 分数:82 分数:66 分数:90 */ } } }
HashMap原理
HashMap是Map的一个常用的子类实现。其实使用散列算法实现的。
HashMap内部维护着一个散列数组(就是一个存放元素的数组),我们称其为散列桶,而当我们向HashMap中存入一组键值对时,HashMap首先获取key这个对象的hashcode()方法的返回值,然后使用该值进行一个散列算法,得出一个数字,这个数字就是这组键值对要存入散列数组中的下标位置。
那么得知了下标位置后,HashMap还会查看散列数组当前位置是否包含该元素。(这里要注意的是,散列数组中每个元素并非是直接存储键值对的,而是存入了一个链表,这个链表中的每个节点才是真实保存这组键值对的。)检查是否包含该元素时根据当前要存入的key在当前散列数组对应位置中的链表里是否已经包含这个key,若不包含则将这组键值对存入链表,否则就替换value。
那么在获取元素时,HashMap同样先根据key的hashcode值进行散列算法,找到它在散列数组中的位置,然后遍历该位置的链表,找到该key所对应的value之后返回。
看到这里可能有个疑问,链表中应该只能存入一个元素,那么HashMap是如何将key-value存入链表的某个节点的呢?实际上,HashMap会将每组键值对封装为一个Entry的实例,然后将该实例存入链表。
在散列表中有一下名词需要了解:
那么当加载因子较小时候散列查找性能会提高, 同时也浪费了散列桶空间容量. 0.75是性能和空间相对平衡结果. 在创建散列表时候指定合理容量, 从而可以减少rehash提高性能。
/* * 当一个类作为HashMap中的key使用时,它的equals方法与hashcode方法的结果直接影响散列表的查询性能。 * 原因: 根据HashMap表的原理.详见图. * API手册中明确说明:当我们重写一个类的equals方法时就应当连同重写hashCode方法。 * 重写hashCode方法时应遵循: * 1:稳定性:当参与equals比较的属性的值没有发生过改变的前提下,多次调用hashCode方法返回的数字应当相同。 * 2:一致性: 当两个对象equals比较为true时,那么hashcode方法返回的数字必须相同 反过来如果hashcode相同,equals的结果虽然不强制,但也尽量保证一致。 因为若两个对象hashcode值相同,但是equal方法比较为false,在散列表中会产生链表,影响查询性能 */ public class KeyHashCode { private int x; private int y; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; KeyHashCode other = (KeyHashCode) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } }
MapDemo1+2 Map接口的常用方法及遍历 及HashMap原理
标签:
原文地址:http://www.cnblogs.com/zyjcxc/p/5448776.html