HashMap类使用详解

HashMap类使用详解

HashMap采用哈希算法实现,是Map接口最常用的实现类。 由于底层采用了哈希表存储数据,我们要求键不能重复,如果发生重复,新键值对会替换旧的键值对。 HashMap在查找、删除、修改方面都有非常高的效率。

HashMap 集合中的 key 不能重复(key可以为null),我们可以通过重写 hashCode() 与 equals()方法来保证键的唯一。

7.3.1、HashMap的使用

HashMap 中key为 JavaAPI 中提供的类型元素时,不需要重写元素的 hashCode 和 equals 方法,因为这两个方法,在 JavaAPI 的每个类中已经重写完毕,如 String 类、Integer 类等。

【示例】HashMap中key为 String类型

public class Demo {
    public static void main(String[] args) {
        // 初始化HashMap对象
        Map<String, Integer> map = new HashMap<String, Integer>();
        // 添加元素
        map.put("a", 111);
        map.put("c", 222); // 被覆盖
        map.put("e", 333);
        map.put("d", 444);
        map.put("b", 555);
        map.put("c", 222); // 与第二个添加的key相同,那么覆盖第二个的value值
        // 遍历元素
        Iterator<String> iterator = map.keySet().iterator();
        while(iterator.hasNext()) {
            String key = iterator.next();
            System.out.println("key:" + key + " value:" + map.get(key));
        }
    }
}

输出结果如下:

key:a value:111
key:b value:555
key:c value:222
key:d value:444
key:e value:333

注意:当在HashMap 中put的key在之前已经存过,则不会重复存储,会覆盖之前key对应的value。

7.3.2、存储自定义对象

当给 HashMap 中存放自定义对象时,如果自定义对象作为 key 存在,这时要保证对象唯一,必须重写对象的 hashCode 和 equals 方法,建立自己的比较方式,才能保证 HashMap 集合中的对象唯一。

例如,每位学生(姓名,年龄)都有自己的家庭住址。那么既然有对应关系,则将学生对象和家庭住址存储到HashMap 集合中。学生作为键(key),家庭住址作为值(value),当学生姓名相同并且年龄相同视为同一名学生。

【示例】创建自定义对象 Person

class Person {
	String name;
	int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	// 重写equals方法
	@Override
	public boolean equals(Object obj) {
		Person p = (Person) obj;
		return name.equals(p.name) && age == p.age;
	}
	// 重写hashCode方法,
	@Override
	public int hashCode() {
		return name.hashCode() + age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}

【示例】创建 HashMap 集合

public class Demo {
    public static void main(String[] args) {

        // 初始化HashMap对象
        Map<Person, String> map = new HashMap<Person, String>();
        // 添加元素
        map.put(new Person("小明", 18), "重庆");
        map.put(new Person("张三", 33), "成都");
        map.put(new Person("李四", 19), "武汉");
        map.put(new Person("王麻子", 28), "北京");
        map.put(new Person("王麻子", 28), "上海"); // 只能输出一个
        // 遍历元素
        Iterator<Person> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            Person p = iterator.next();
            System.out.println("key:" + p + " value:" + map.get(p));
        }
    }
}

输出结果如下

key:Person [name=张三, age=33] value:成都
key:Person [name=王麻子, age=28] value:上海
key:Person [name=小明, age=18] value:重庆
key:Person [name=李四, age=19] value:武汉

注意:当自定义对象作为HashMap的key时,一定得重写自定义类的 hashCode 和 equals 方法,,建立自己的比较方式,才能保证 HashMap 集合中的对象唯一。

7.3.3、HashMap:类底层实现

哈希表也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如:Redis)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出现在各类的面试题中,重要性可见一斑。

  在讨论哈希表之前,我们先回顾一下数组和链表来实现对数据的存储的优缺点:

jdk1.7:数组+链表

数组:占用空间连续。 寻址容易,查询速度快。但是,增加和删除效率非常低。

链表:占用空间不连续。 寻址困难,查询速度慢。但是,增加和删除效率非常高。

从上分析我们知道,数组优势是查询效率高,链表的优势是增删效率高。那么有没有一种数据结构能结合“数组+链表”的双方优点呢?答案就是“哈希表”。 

哈希表的本质就是“数组+链表”,这是一种非常重要的数据结构。在哈希表中进行添加、删除和查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成。

我们知道,数据结构的物理存储结构只有两种:顺序存储结构和链式存储结构。而在上面我们提到过,在数组中根据下标查找某个元素,一次定位就可以达到,哈希表利用了这种特性,哈希表的主干就是数组。

我们打开HashMap源码,发现有如下两个核心内容:

其中的,Node[] table 就是HashMap的核心数组结构,我们也称之为“位桶数组”。我们再继续看Node是什么,源码如下:

一个Node对象存储了:

key:键对象              

value:值对象

next:下一个节点

hash:键对象的hash值 

显然就是一个单向链表结构,我们使用图形表示一个Entry的典型示意:

然后我们画出Node[]数组的结构(这也是HashMap的结构) :

由图可知,哈希表就是数组链表,底层还是数组但是这个数组每一项就是一个链表。

接下来我们来基于JDK1.7来模拟HashMap的实现,本章节重点模拟HashMap的put()方法和get()方法,在进行模拟put()方法和get()方法的实现之前,我们先做好相关的准备工作。

首先创建一个Node节点类,Node节点类是HashMap的内部类,它有几个重要的属性:键对象(key) 、值对象(value)、键对象的hash值(hash)和下一个节点(next)。

代码实现如下:


class MyHashMap<K, V> {// Node节点,是一个单链表	static class Node<K, V> {		int hash; // 键对象的hash值		K key; // 键对象		V value; // 值对象		Node<K, V> next; // 下一个节点		// 构造方法		public Node(int hash, K key, V value, Node<K, V> next) {			this.hash = hash;			this.key = key;			this.value = value;			this.next = next;		}	}}
Nod

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值