实现自己的HashMap
准备工作 ,实现自己的Map.entry。代码如下 :
import java.util.Map;
public class MapEntry<K,V> implements Map.Entry<K,V> {
private K key;
private V value; public MapEntry(K key, V value) {
this.key = key;
this.value = value;
} @Override
public K getKey() {
return key;
} @Override
public V getValue() {
return value;
} @Override
public V setValue(V v) {
V result = value;
value = v;
return result;
} public String toString() {
return key + " = " + value;
}
}
1.简单的用一对ArrayList来实现。(为什么不用LinkedList?因为无论是put()还是get()都有查询,还是ArrayList快一点)。
import java.util.*;
public class SimpleHashMap<K, V> extends AbstractMap<K, V> {
private List<K> keys = new ArrayList<>();
private List<V> values = new ArrayList<>();
public V put(K key, V value) {
V oldvalue = get(key);
if (!keys.contains(key)) {
keys.add(key);
values.add(value);
} else {
values.set(keys.indexOf(key), value);
}
return oldvalue;
}
public V get(Object key) {
if (!keys.contains(key)) {
return null;
}
return values.get(keys.indexOf(key));
}
@Override
public Set<Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> set = new HashSet<Entry<K, V>>();
Iterator<K> ki = keys.iterator();
Iterator<V> vi = values.iterator();
while (ki.hasNext())
set.add(new MapEntry<K, V>(ki.next(), vi.next()));
return set;
}
public static void main(String args[]) {
SimpleHashMap<String, String> map = new SimpleHashMap<String, String>();
map.put("hello1", "world");
map.put("hello2", "world2");
map.put("hello3", "world3");
System.out.println(map);
System.out.println(map.get("hello"));
System.out.println(map.entrySet());
}
}
这种实现能够满足现有测试工作。但是有2个问题需要考虑:
1.在put()和get()的时候都是用list.contains()来判断,如果是按地址查找,速度会不会快更快?
2.所有的put()和get()都是查找整个list,能不能给所有的object按照某一属性分类,这样在查找的时候是不是可以到对应的分类上去查找,这样就不用查整个list,速度会不会再提高一些?
于是就有了第二种实现自己的hashmap的方法,代码如下:
import java.util.*;
public class SecondHashMap<K, V> extends AbstractMap {
static final int SIZE = 997;
LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];
public V pub(K key, V value) {
V oldvalue = null;
int index = Math.abs(key.hashCode()) % SIZE;
if (buckets[index] == null)
buckets[index] = new LinkedList<MapEntry<K, V>>();
LinkedList<MapEntry<K, V>> bucket = buckets[index];
MapEntry<K, V> pair = new MapEntry<>(key, value);
boolean found = false;
ListIterator<MapEntry<K, V>> it = bucket.listIterator();
while (it.hasNext()) {
MapEntry<K, V> ipair = it.next();
if (ipair.getKey().equals(pair.getKey())) {
oldvalue = ipair.getValue();
it.set(pair);
found = true;
break;
}
}
if (!found)
buckets[index].add(pair);
return oldvalue;
}
public V get(Object key){
int index = Math.abs(key.hashCode())%SIZE;
if(buckets[index] == null) return null;
for(MapEntry<K,V> ipair : buckets[index]){
if(ipair.getKey().equals(key))
return ipair.getValue();
}
return null;
}
@Override
public Set<MapEntry<K,V>> entrySet() {
Set<MapEntry<K,V>> set = new HashSet<MapEntry<K,V>>();
for(LinkedList<MapEntry<K,V>> bucket : buckets){
if (bucket ==null) continue;
for (MapEntry<K,V> ipair : bucket){
set.add(ipair);
}
}
return set;
}
public static void main(String args[]) {
SimpleHashMap<String, String> map = new SimpleHashMap<String, String>();
map.put("hello1", "world");
map.put("hello2", "world2");
map.put("hello3", "world3");
System.out.println(map);
System.out.println(map.get("hello"));
System.out.println(map.entrySet());
}
}
这样一来,是解决了上面的两个问题。但是对于buckets数组下标的生成仅仅是对key的hashcode与容器的长度做了取模运算。这个buckets数组下标最好分布均匀点,如果都集中在在某一块,hashmap在某些区域负载过重,降低整体的性能。在Efffective Java Programming Language Guide这本书中有关于hashcode生成的指导,有兴趣的同学可以自己找找看看。
另外,补充一个hashmap的知识点:负载因子。负载因子代表当前的存储数/容量。空表是0,半满表示0.5,以此类推。当负载情况达到负载因子的水平时,容器就会自动扩容。实现方式是使容量大致加倍,并重新将现有的对象分布到新的表中,也被称为再散列。hashmap的负载因子默认是0.75,这个因子在时间和空间代价之间达到了平衡。更高的负载因子可以降低所需的空间,但是会增加查找代价,反之亦然。如果知道将要在hashmap中存储多少项,创建一个具有恰当大小的初始容量将可以避免自动再散列的开销。
实现自己的HashMap的更多相关文章
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- HashMap的工作原理
HashMap的工作原理 HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...
- 计算机程序的思维逻辑 (40) - 剖析HashMap
前面两节介绍了ArrayList和LinkedList,它们的一个共同特点是,查找元素的效率都比较低,都需要逐个进行比较,本节介绍HashMap,它的查找效率则要高的多,HashMap是什么?怎么用? ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- 学习Redis你必须了解的数据结构——HashMap实现
本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接博客园蜗牛 cnblogs.com\tdws . 首先提供一种获取hashCode的方法,是一种比较受欢迎的方式,该方法参照了一位园友的 ...
- HashMap与HashTable的区别
HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...
- JDK1.8 HashMap 源码分析
一.概述 以键值对的形式存储,是基于Map接口的实现,可以接收null的键值,不保证有序(比如插入顺序),存储着Entry(hash, key, value, next)对象. 二.示例 public ...
- HashMap 源码解析
HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...
- java面试题——HashMap和Hashtable 的区别
一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...
- 再谈HashMap
HashMap是一个高效通用的数据结构,它在每一个Java程序中都随处可见.先来介绍些基础知识.你可能也知 道,HashMap使用key的hashCode()和equals()方法来将值划分到不同的桶 ...
随机推荐
- 学习笔记TF063:TensorFlow Debugger
TensorFlow Debugger(tfdbg),TensorFlow专用调试器.用断点.计算机图形化展现实时数据流,可视化运行TensorFlow图形内部结构.状态.有助训练推理调试模型错误.h ...
- 详解:idea工具下的main函数只执行Thread.activeCount(),打印值为:2
写多线程的时候,想要等main中其他线程都执行完成后(其他线程功能为对一个数字inc+1),输出最终的inc值. 于是写了个循环: while (Thread.activeCount() > 1 ...
- Java高级特性 第11节 JUnit 3.x和JUnit 4.x测试框架
一.软件测试 1.软件测试的概念及分类 软件测试是使用人工或者自动手段来运行或测试某个系统的过程,其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别.它是帮助识别开发完成(中间或最终 ...
- Dart 语法
Dart 语法 说明 var 类似于JavaScript中的var:最大的不同是Dart中var变量一旦赋值,类型便会确定,则不能再改变其类型 Object Object 是dart所有对象的根基类, ...
- 4.认识Angular组件之2
11. 变化监测:Angular提供了数据绑定的功能.所谓的数据绑定就是将组件类的数据和页面的DOM元素关联起来.当数据发生变化时,Angular能够监测到这些变化,并对其所绑定的DOM元素 进行相应 ...
- 记录一次MyEclipse打开jsp文件出现Error的解决办法
今天正在忙着写项目,在打开一个项目内的jsp文件时发现我亲爱的代码消失了. 最后从网上找到了解决办法,希望可以帮到有需要的人,也作为个人记录 第一步:找到安装路径MyEclipse\configura ...
- 通用Mapper简单使用
通用Mapper 1.通用Mapper的使用 1.0.实体类 @Table(name = "tb_user") public class User { @Id @Generated ...
- 【Leecode】两数相加
学习了链表结构,链表中元素的访问,对象指针的初始化与赋值,链表的创建(多个节点链接起来),进位计算的表达. 100ms /** * Definition for singly-linked list. ...
- 使用 AWK 去掉文本文档中的空白行
在 Linux 操作系统中,可以使用 AWK 命令高效地处理文本文档.AWK 命令通过执行使用 AWK 语言编写的脚本程序,处理文本文档.AWK 脚本程序是由模式(patterns)与相关操作(cor ...
- redis4.0.13主从、哨兵、集群3种模式的 Server端搭建、启动、验证
本文使用的是redis-4.0.13.tar.gz版本. 两个centos7系统虚拟机:192.168.10.140.192.168.10.150 redis各版本下载地址:http://downlo ...