背景
说到Map,估计作为一个java从业者,大家应该都不陌生。其实早在两年前就有面试官问我HashMap的实现及原理了。当时作为一个从业不到两年的我,很流利的回答了原理是数组加链表。但是何为数组何为链表,HashMap初始化究竟做了那些事情等等,其实我根本讲不清楚讲不明白。这件事其实也一直耿耿于怀我心中。每当有点时间的时候,我都会尝试性的去看看hashmap的源码,但是鉴于实力水平及个人资质以及花在上面的时间,直到今天,我也只能是浅谈一下Map。接下来的几篇文章我将从以下几个方面来剖析HashMap
- 什么是数组及链表
- 实现一个类似HashMap的容器类
- 什么是红黑树
- Map抽象接口的定义
- HashMap初始化做了那些事情
- HashMap的put方法详解
- HashMap的get方法详解
- HashMap的继承及实现关系
- CurrentHashMap线程安全的实现机制
这一片我们单纯介绍数组及链表即可。
什么是数组
定义
数组指的是一组相关类型的变量的集合,是一种容器,可以同时存放多个数据值
特点
- 查找速度快,随机访问性强
- 数组中多个数据,类型必须统一
- 数组的长度在程序运行期间不可改变
- 插入和删除效率低
- 可能浪费内存,即数组长度使用不完
- 内存空间要求高,必须有足够的连续内存空间
从特点我们可知数组访问速度快,但是插入慢。为什么这么说呢。当插入元素时我们需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中,因此慢。删除同理。又由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素,所以快。
什么是链表
定义
链表是把每个数据分为一个类,然后通过next指针域连接起来的表。这么说我自己也一脸懵逼。还是举个例子吧(人懒就直接用HashMap里面的Node节点了,别踩)
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
嗯嗯,很好。就是这样子。简单剖析下这个类吧,含有hash,key,value,next4个属性。setValue(),getKey(),getValue(),hashCode(),toString()几个方法。
当创建node节点时,需要指定他的key,value,next这几个值。而next又是一个node,依次链接就得到了一个小火车。这就是单链表。
链表的特点
-
每一个数据都保存了下一个数据的内存地址,通过这个地址找到下一个数据。 第一个人知道第二个人的座位号,第二个人知道第三个人的座位号……
-
增加数据和删除数据很容易。 再来个人可以随便坐,比如来了个人要做到第三个位置,那他只需要把自己的位置告诉第二个人,然后问第二个人拿到原来第三个人的位置就行了。其他人都不用动。
-
查找数据时效率低,因为不具有随机访问性,所以访问某个位置的数据都要从第一个数据开始访问,然后根据第一个数据保存的下一个数据的地址找到第二个数据,以此类推。 要找到第三个人,必须从第一个人开始问起
-
不指定大小,扩展方便。链表大小不用定义,数据随意增删
不难发现链表插入删除等操作容易,遍历就麻烦。一旦长了就只有一个一个走。
好的,链表与数组暂时介绍到这里。下一篇我们将会使用数组和链表实现一个类似HashMap的容器类