【JavaSE】day06_Map接口_HashMap_hashCode

20 篇文章 0 订阅

【JavaSE】day06_Map接口_HashMap_hashCode


1.Map接口

  1)java.util.Map

      Map看起来像是一个多行两列的表格。每条记录分为两部分:key,value。

其中在一个Map中key是不允许重复的(equals比较)

  2)常用实现类:java.util.HashMap(散列算法实现)

                            java.util.TreeMap(二叉树实现)

  3)V put(K k,V v)

     将给定的key与value存入到Map中。由于Map中key不允许重复,所以会出现两种情况:

     * 1:存入的key在Map中还不存在,那么直接将这对key-value存入Map,返回值为null。

     * 2:存入的key在Map中已经存在,那么会将对应的value替换原来这个key对应的value,并将被替换的value值返回。

  4)V get(K k)

       根据给定的key值获取对应的value。若当前Map中不含有给定的key,则返回值为null。

  5)V remove(K k)

       将给定的key对应的这一对内容从Map中删除并将对应的value返回。

  6)boolean containsKey(K k)

       查看当前Map是否包含给定的key。包含的判断依据是根据key的equals比较的结果

代码演示:

package day05;

import java.util.HashMap;
import java.util.Map;

/**
 * java.util.Map
 * Map看起来像是一个多行两列的表格
 * 每条记录分为两部分:key,value
 * 其中在一个Map中key是不允许重复的。(equals比较)
 *
 *常用实现类:java.util.HashMap(散列算法实现)
 *          java.util.TreeMap(二叉树实现)
 */
public class MapDemo1 {
	public static void main(String[] args) {
		/*
		 * 保存成绩单  语文-90
		 */
		Map<String,Integer>map = new HashMap<String,Integer>();
		
		/*
		 * V put(K k,V v)
		 * 将给定的key与value存入到Map中。
		 * 由于Map中key不允许重复,所以会出现两种情况:
		 * 1:存入的key在Map中还不存在,那么直接将这对
		 *    key-value存入Map,返回值为null
		 * 2:存入的key在Map中已经存在,那么会将对应的
		 *    value替换原来这个key对应的value,并将被
		 *    替换的value值返回。
		 *    
		 */
		map.put("语文",95);
		map.put("数学",99);
		map.put("英语",97);
		map.put("物理",96);
		map.put("化学",98);
		/*
		 * 存入顺序与内部顺序不一致
		 */
		System.out.println(map);
		
		Integer a =map.put("语文1",100);
		//int a =map.put("语文1",100); //空指针异常,写成Integer可以避免
		System.out.println(a);
		System.out.println(map);
		
		/*
		 * V get(K k)
		 * 根据给定的key值获取对应的value
		 * 若当前Map中不含有给定的key,则返回值为null
		 */
		Integer num = map.get("化学");
		System.out.println(num);
		
		/*
		 * V remove(K k)
		 * 将给定的key对应的这一对内容从Map中删除
		 * 并将对应的value返回。
		 */
		num = map.remove("化学");
		System.out.println(num);
		System.out.println(map);
		
		/*
		 * boolean containsKey(K k)
		 * 查看当前Map是否包含给定的key
		 * 包含的判断依据是根据key的equals比较的结果
		 */
		boolean contains = map.containsKey("语文");
		System.out.println(contains);
		
		
		
	}

}

  7)Map的三种遍历方法:

package day05;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * 遍历Map
 * 遍历Map有三种方式:
 * 1:遍历所有的key
 * 2:遍历每一组键值对
 * 3:遍历所有的value(相对不常用)
 *
 */
public class MapDemo2 {
	public static void main(String[] args) {
		/*
		 * LinkedHashMap
		 * 内部使用一个LinkedList维护顺序,可以做到遍历的时候
		 * 与put的顺序一致。若不许要顺序,通常不使用该类。
		 */
		Map<String,Integer> map = new LinkedHashMap<String,Integer>();
		map.put("语文",95);
		map.put("数学",98);
		map.put("英语",95);
		map.put("物理",93);
		map.put("化学",90);
		System.out.println(map);
		
		/*
		 * 遍历所有的key:
		 * Set<K> keySet()
		 * 该方法会将所有的key存入一个Set集合后返回,
		 * 所以遍历该集合就相当于遍历到所有的key了。
		 */
		Set<String> keySet = map.keySet();
		for(String key : keySet){
			System.out.println(key);
		}
		
		/*
		 * 遍历每一组键值对
		 * Set<Entry> entrySet()
		 * 将每一组键值对(Entry实例)存入一个Set集合后将其返回。
		 * 
		 * Entry是Map的内部类,每一个实例表示一组键值对
		 * 其中包含两个属性,key,value。
		 */
		Set<Entry<String,Integer>> entrySet = map.entrySet();
		for(Entry<String,Integer> e : entrySet){
			String key = e.getKey();
			Integer num = e.getValue();
			System.out.println(key+"--"+num);
		}
		
		/*
		 * Collection<V> values()
		 * 将当前Map中所有的value值存入一个集合后返回。
		 */
		Collection<Integer> values = map.values();
		for(Integer i : values){
			System.out.println(i);
		}
		
		
	}

}

2.HashMap

HashMap是Map的一个常用的子类实现。其实使用散列算法实现的。

HashMap内部维护着一个散列数组(就是一个存放元素的数组),我们称其为散列桶,而当我们向HashMap中存入一组键值对时,HashMap首先获取key这个对象的hashcode()方法的返回值,然后使用该值进行一个散列算法,得出一个数字,这个数字就是这组键值对要存入散列数组中的下标位置。

那么得知了下标位置后,HashMap还会查看散列数组当前位置是否包含该元素。(这里要注意的是,散列数组中每个元素并非是直接存储键值对的,而是存入了一个链表,这个链表中的每个节点才是真实保存这组键值对的。)检查是否包含该元素时根据当前要存入的key在当前散列数组对应位置中的链表里是否已经包含这个key,若不包含则将这组键值对存入链表,否则就替换value。

那么在获取元素时,HashMap同样先根据key的hashcode值进行散列算法,找到它在散列数组中的位置,然后遍历该位置的链表,找到该key所对应的value之后返回。

看到这里可能有个疑问,链表中应该只能存入一个元素,那么HashMap是如何将key-value存入链表的某个节点的呢?实际上,HashMap会将每组键值对封装为一个Entry的实例,然后将该实例存入链表。


3.hashCode

当我们使用自定义类型的实例作为HashMap中key的值时,这个类的equals与hashCode的结果直接影响着HashMap查询的效率。

 * 要避免一件事的产生:

 hashCode值相同,但是equals比较不为true!!这会严重影响 HashMap效率。

 * JAVA API文档中对于这两个方法的重写有这样的要求:

 当我们重写一个类的equals方法时,就应当连同重写hashCode方法。

 *还应同时满足:
当两个对象equals比较为true时,hashCode返回的值应当相等。反过来不强制,但最好也不同,否则影响HashMap性能。

hashCode方法返回值应当是一个稳定的值,意思就是:当确定equals方法比较结果的属性没有发生改变的前提下,多次调用hashCode方法返回值应当相同。

代码演示:

package day05;
/**
 * 该类用于练习重写equals与hashCode的注意事项:
 * 当我们使用自定义类型的实例作为HashMap中key的值时,
 * 这个类的equals与hashCode的结果直接影响着HashMap查询的效率。
 * 要避免一件事的产生:
 * hashCode值相同,但是equals比较不为true!!这会严重影响
 * HashMap效率。
 * JAVA API文档中对于这两个方法的重写有这样的要求:
 * 当我们重写一个类的equals方法时,就应当连同重写hashCode方法。
 *还应同时满足:
 *当两个对象equals比较为true时,hashCode返回的值应当相等。
 *反过来不强制,但最好也不同,否则影响HashMap性能。
 *hashCode方法返回值应当是一个稳定的值,意思就是:当确定equals
 *方法比较结果的属性没有发生改变的前提下,多次调用hashCode方法
 *返回值应当相同。
 *
 */
public class Cell {
	private int row;
	private int col;
	
	public Cell(int row, int col) {
		super();
		this.row = row;
		this.col = col;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + col;
		result = prime * result + row;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Cell other = (Cell) obj;
		if (col != other.col)
			return false;
		if (row != other.row)
			return false;
		return true;
	}
	
	
	
	
	
}

4.Map小案列

package day05;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * 现有字符串"good good study, day day up.",统计其中各个字符出现的次数。
 *
 */
public class MapDemo {
	public static void main(String[] args) {
		String str = "good good study, day day up.";
		summary(str);
	}
	public static Map<Character,Integer> summary(String str){
		// "good good study, day day up."
		Map<Character,Integer> map = new HashMap<Character,Integer>();
		//去除字符串中的空格和标点符号
		//regex = "[^a-zA-Z]+"
		str = str.replaceAll("[^a-zA-Z]+","");
		System.out.println(str);
		
		for(int i=0;i<str.length();i++){
			char c = str.charAt(i);
			if(map.containsKey(c)){
				map.put(c,map.get(c)+1);
			}else{
				map.put(c,1);
			}
		}
		//新循环遍历
		Set<Entry<Character,Integer>>entrySet = map.entrySet();
		for(Entry<Character,Integer> e : entrySet){
			System.out.println(e.getKey()+"--"+e.getValue());
		}
		
		//Iterator迭代器遍历 key-value
		Iterator<Entry<Character,Integer>> it2 = entrySet.iterator();
		while(it2.hasNext()){
			//it.next()每次循环的时候只能出现一次,否则可能抛异常
			Entry<Character,Integer> e = it2.next(); 
			char key = e.getKey();
			Integer value = e.getValue();
			System.out.println(key +"--" +value);
		}
		
		//迭代器遍历key
		Set<Character> keySet = map.keySet();
		Iterator<Character> it = keySet.iterator();
		while(it.hasNext()){
			System.out.print(it.next()+" ");
		}
		System.out.println();
		
		return null;
	}

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值