Map:java.util.Map接口
*Map称为查找表,该数据结构体现的样子是一个“多行两列”的表格,左列
*称为key,右列称为value
*Map总是根据key查找对应的value
*存储元素也要求key-value成对存入
*常用的实现类:java.util.HashMap 散列表
* HashMap是基于散列算法实现的Map,是当今世界上最快的查询结构、
若只获取value值,则用get()
删除的remove()方法是成对删除,且返回值是被删除的value值
package map; import java.util.HashMap; import java.util.Map; /** * java.util.Map接口 *Map成为查找表,该数据结构体现的样子是一个“多行两列”的表格,左列 *称为key,右列称为value *Map总是根据key查找对应的value *存储元素也要求key-value成对存入 *常用的实现类:java.util.HashMap 散列表 * HashMap是基于散列算法实现的Map,是当今世界上最快的查询结构 * @author TEDU * */ public class MapDemo1 { public static void main(String[] args) { Map<String,Integer> map=new HashMap<String,Integer>(); map.put("数学", 100); map.put("物理", 97); map.put("化学", 99); map.put("英语", 20); map.put("语文", 98); Integer a=map.put("生物", 97); System.out.println(a); System.out.println(map); //{物理=97, 生物=97, 数学=100, 化学=99, 语文=98, 英语=20} //map的输出顺序与存入顺序不一样, /* * 如果向map中存入的键值对的key值已经存在map中,则不会再继续加入 * 而是替代之前的value值。如果向map中加入的键值对已经存在,用value * 接收返回值,则返回值为替代的value值,如果之前没有这个元素,则返回null。 * * 对于value是包装类的情况,不能直接用基本类型接收返回值,因为会触发 * 自动拆箱特性: * int n=map.put("语文",99); * 下面的代码编译后会改为: * int n=map.put("语文",99).inValue(); * * 若key在Map中不存在,则返回值为null,若拆箱则会引发空指针异常 */ //多少行 int size=map.size(); System.out.println(size); //查看数学的成绩 Integer math=map.get("数学"); System.out.println("数学"+math); /* * 删除元素 * 删除当前map中给定key值对应的这组键值对 * 返回值为该key所对应的value。若给定的key在key中不存在 * 则返回null */ Integer an=map.remove("数学"); System.out.println(an); //containsKey()与containsValue()判断是否含有指定的key和value boolean key=map.containsKey("化学"); System.out.println("是否含有key:"+key); boolean value=map.containsValue(98); System.out.println("是否含有value:"+value);} }
Map的遍历:
3种方法,分别是:
1.遍历所有的键值对
2.遍历所有的key值
3.遍历所有的value值
package map; /** * Map的三种遍历 * 1:遍历所有的key * 2:遍历所有的key-value对 * 3:遍历所有的value(相对不常用) * */ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class MapDemo03 { public static void main(String[] args) { Map<String,Integer> map=new HashMap<String,Integer>(); map.put("数学", 100); map.put("物理", 97); map.put("化学", 99); map.put("英语", 20); map.put("语文", 98); System.out.println(map); /* * 遍历所有的key值 * Set keySet() * 将当前Map中所有的key存入一个集合后返回 * 遍历这个set集合等于遍历多有的key */ Set<String>keySet=map.keySet(); for(String key:keySet){ System.out.println("key:"+key); } /* * 遍历每一组键值对 * 在Map接口中定义可一个内部接口 * java.util.Map.Entry * Entry的没一个实例表示当前map中的 * 一组键值对,提供了两个常用的方法: * K getKey() :获取key值 * V getValue():获取value值 * 不同的Map实现类都实现了Entry,并用实现类的 * 每一个实例表示一个具体的键值对。 * * Set<Entry> entrySet() * 刚方法会将Map中所有的键值对存入一个集合后返回 */ Set<Entry<String,Integer>>entrySet=map.entrySet(); for(Entry <String,Integer>e:entrySet){ Integer value=e.getValue(); String key=e.getKey(); System.out.println(key+":"+value); } /* * 遍历所有的value * Collection values() * 将当前Map中所有的value以一个集合的形式返回 * 因为set集合中不能有重复元素,故不叫valueSet */ Collection <Integer>values=map.values(); for(Integer e:values){ System.out.println(e); } } }
Map特点的缘由:
1,为什么用了一维数组:数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难
2,为什么用了链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易
而HashMap是两者的结合,用一维数组存放散列地址,以便更快速的遍历;用链表存放地址值,以便更快的插入和删除!
如果两个对象相等(equal),它们的hashcode一定相同;
如果两个对象有相同的hashcode,它们不一定相等(equal);
当Map存入的数据存入超过3/4时,Map会进行重新散列rehash,因为散列算法计算元素下标与key值和数组的长度有关,
这样可以有效的避免数组扩容后元素丢失。
package map; /** * HashMap内部由数组保存键值对,存储元素时根据key的hashcode值 * 计算数组下标,并将键值对存入,获取时也根据该值计算数组下标,并将键值对存入, * 获取时也根据该值找到该元素。所以HashMap根据这个方式避免了查找 * 元素时对数组的遍历操作,所以其不受元素的多少而影响查询性能。 * * 由于key的hashcode决定这键值对HasMap中数组 下标位置,而equals * 方法决定着key是否重复。所以这两个方法要妥善重写, * 当遇到两个key的shascode值一样。但是equals比 * 较不为true的情况时,会出现链表。链表会降低查询性能。应尽量避免 * * hashcode与equals方法时定义在Object中的,所有类都具有 * ,java提供的类需要重写equals或hashcode是 * 必须遵循一下原则: * 1:成对重写,当我们需要重写一个类的equals方法时 * 就应当连同重写hashcode方法。 * 2:一致性,当两个对象equals比较为true时,hashcode值应该相等 * ,反之虽然不是必须的,但是应当保证当两个对象hashcode方法返回值相等 * 时,equals方法比较为true。否则会在HashMap中出现链表 * 3:稳定性,当参与equals比较的属性没有发生变化的情况下,多 * 次调用hashcode方法返回的数字不应当有变化 * @author TEDU * */ public class Key { 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; Key other = (Key) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } }