感慨现在的在校实习生并不好找实习工作了,就拿安卓而言,想找工作之前还需要一些非常有用的筹码。像自己处于普通本科,只能通过写博客来壮大自己,同时希望加深自己对一些编程的理解。如有什么错误的地方,麻烦你们矫正一下。谢谢~
Hashmap
HashMap面试中经常考的基础题了,HashMap我们都知道是基于哈希表的一种以键值对的方式存储数据。而且查询的时候特别方便,直接通过键的特征就能知道值。那既然这样,你们是否有兴趣去了解其中的奥秘呢 ? 来了,我要开始装逼了。。。。
HashMap是继承自AbstractMap这个父类的。
public class HashMap<K,V> extends AbstractMap<K,V>
先引用一张图哦,本人不会用手残不会作图,只能引用别人的了。
这张图发现很多博客都用,我就不标明出处了。如果有侵犯的话请告知。!
我们仔细看一下这张图,作为程序员的我们,是否很熟悉这是什么 ?没错啦,左边是数组,右边就是链表。
所以我们就可以总结出,这是一个散列表。HashMap的底层实现还是用数组实现的,然后数组的每一项,是类似于一条拉链这种形式的。
既然我们知道它的存储原理,接下来我们要知道它是如何实现存储和取值的。我们通常Hashmap的时候,都知道用put和get方式进行的对吧。
那这样我们就进去源码看看,它是怎么实现的,
存储值的时候
int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
int index = hash % Entry[].length;
Entry[index] = value;
取值的时候
int hash = key.hashCode();
int index = hash % Entry[].length;
return Entry[index];
在这两段代码中,发现每次都会int hash这个变量去取key的hashcode,这个意思是说,hashmap是通过hashcode去取值的,那么定位的方式就是,hash % Entry[].length通过这个来赋予index这个变量。举一个简答的例子,就拿上面的第一张图片来解释,在下标为12的位置,12%16=12,28%16=12,108%16=12,140%16=12。那么12,28,108,140都在12的位置。
既然知道这存和取的方式,在Hashmap的内部里面还有一个类,Entry
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
.......
}
这个类是用于存放key和value的,我们可以看到它定义了key value 还有next用于取下一个值,还有hash值。
完整源码
static class Entry<K,V> implements Map.Entry<K,V> {
2 final K key;
3 V value;
4 Entry<K,V> next;//对下一个节点的引用
5 final int hash;//哈希值
6
7 Entry(int h, K k, V v, Entry<K,V> n) {
8 value = v;
9 next = n;
10 key = k;
11 hash = h;
12 }
13
14 public final K getKey() {
15 return key;
16 }
17
18 public final V getValue() {
19 return value;
20 }
21
22 public final V setValue(V newValue) {
23 V oldValue = value;
24 value = newValue;
25 return oldValue;//返回的是之前的Value
26 }
27
28 public final boolean equals(Object o) {
29 if (!(o instanceof Map.Entry))//判断类型是否一致
30 return false;
31 Map.Entry e = (Map.Entry)o;
32 Object k1 = getKey();
33 Object k2 = e.getKey();
34 //如果Key相等和Value相等则两个Entry相等
35 if (k1 == k2 || (k1 != null && k1.equals(k2))) {
36 Object v1 = getValue();
37 Object v2 = e.getValue();
38 if (v1 == v2 || (v1 != null && v1.equals(v2)))
39 return true;
40 }
41 return false;
42 }
43 // hashCode是Key的hashCode和Value的hashCode的异或的结果
44 public final int hashCode() {
45 return (key==null ? 0 : key.hashCode()) ^
46 (value==null ? 0 : value.hashCode());
47 }
48 // 输出
49 public final String toString() {
50 return getKey() + "=" + getValue();
51 }
52
53
56 void recordAccess(HashMap<K,V> m) {
57 }
58
59
62 void recordRemoval(HashMap<K,V> m) {
63 }
64 }
put操作
public V put(K key, V value) {
2 if (key == null)
3 return putForNullKey(value);
4 int hash = hash(key.hashCode());
5 int i = indexFor(hash, table.length);
6 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
7 Object k;
8 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
9 V oldValue = e.value;
10 e.value = value;
11 e.recordAccess(this);
12 return oldValue;
13 }
14 }
15
16 modCount++;
17 addEntry(hash, key, value, i);
18 return null;
19 }
get操作
public V get(Object key) {
2 if (key == null)
3 return getForNullKey();
4 int hash = hash(key.hashCode());
5 for (Entry<K,V> e = table[indexFor(hash, table.length)];
6 e != null;
7 e = e.next) {
8 Object k;
9 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10 return e.value;
11 }
12 return null;
13 }