Map

Map

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是两者的结合,用一维数组存放散列地址,以便更快速的遍历;用链表存放地址值,以便更快的插入和删除

 Map 

如果两个对象相等(equal),它们的hashcode一定相同;

如果两个对象有相同的hashcode,它们不一定相等(equal);

Map

当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;
}

	
	
}