集合-HashMap
该文章的实践内容来自how2java网站,集合的学习篇章
1.概念:
HashMap是以哈希表作为底层数据结构,以一组键值对作为存储单元的Map接口的实现类。
其主要特点是,容器内的元素不以添加顺序排序,不可以用NULL作为键,但是可以用NULL作为值,非线程安全。
2.原理:
当向HashMap中添加元素时,首先需要添加一个键(key),然后添加一个值(value)。键作为值的索引,在之后查找value时提供位置。而键在添加时,会用hashCode方法获取键的hash码,根据这个hash码按照一定规则添加到相应位置中(可以参考HashSet的存放)。但是尽管是不同的对象,在经过hashCode获得的hash值也有可能是相同的,或者在HashMap中存放散列单元相同。这时就会在确定hash值之后,调用键的equals方法来判断是否为同一对象。如果是,就替换该键对应的值。如果不是,则在该位置添加一个链表,把有相同hash值的不同对象的键存放在其中。
注:键的存储与HashSet类似
3.简单的实现
(1)用LinkedList数组作为底层数据结构,实现Entry作为键值对保存单元
private LinkedList<Entry>[] lArray = new LinkedList[2000];
public class Entry {
public Entry(Object key,Object value){
super();
this.key = key;
this.value = value;
}
private Object key;
private Object value;
public Object getValue(){
return this.value;
}
public Object getKey(){
return this.key;
}
public void setKey(Object key){
this.key = key;
}
public void setValue(Object value){
this.value = value;
}
@Override
public String toString(){
return "[key="+key+",value="+value+"]";
}
}
(2)首先需要实现一个简单的hashCode方法,来获取字符串的hash值
public static int hashcode(String str){
int hcode = 0;
for (int i = 0; i < str.length(); i++) {
hcode = hcode + str.charAt(i)*(str.length()-1);
}
return hcode = hcode%2000;
}
注:这里在最后返回的值是模2000是为了让不同的字符串的哈希值都在2000以内,这样就会有大量重复的哈希值。在实现HashMap时,遇到相同hash值,就建立一个链表将其值存入其中
(3)实现put方法
public void put(String key,Object value){
//获取键的哈希值
int hcode = hashcode(key);
//判断该哈希值对应的存储位置是否有存储
LinkedList<Entry> ll = lArray[hcode];
if(null == ll){
//新建一个链表存储在该位置,并将键值对保存在链表中
ll = new LinkedList<>();
lArray[hcode] = ll;
}
//判断该key是否已经有对应的键值对
boolean found = false;
for(Entry entry:ll){
if(key.equals(entry.getKey())){
entry.setValue(value);
found = true;
break;
}
}
if(!found){
Entry entry = new Entry(key,value);
ll.add(entry);
}
}
(4)实现get方法
public Object get(String key){
//获取key的哈希值
int hcode = hashcode(key);
LinkedList<Entry> ll = lArray[hcode];
if(null == ll){
return null;
}else{
for (Entry e:ll){
if(key.equals(e.getKey()))
return e.getValue();
}
return null;
}
}
(5)最后用ArrayList和MyHashMap存储了100000个对象来测试两者查询所用时间差
ArrayList<Hero> hl = new ArrayList<>();
ArrayList<Hero> al = new ArrayList<>();
MyHashMap mhm = new MyHashMap();
for (int i = 0; i < 100000; i++) {
Random rand = new Random( System.currentTimeMillis()+i);
StringBuffer sb = new StringBuffer();
sb.append("hero-");
sb.append(rand.nextInt(9));
sb.append(rand.nextInt(9));
sb.append(rand.nextInt(9));
sb.append(rand.nextInt(9));
Hero hero = new Hero(sb.toString(),i);
al.add(hero);
//mhm.put(sb.toString(),hero);
}
for(Hero h:al){
List<Hero> list = (List<Hero>)mhm.get(h.getName());
if(null == list){
list = new ArrayList<Hero>();
mhm.put(h.getName(),list);
}
list.add(h);
}
long start = System.currentTimeMillis();
for (int i = 0; i < al.size(); i++) {
Hero h = al.get(i);
String name = h.getName();
if(name.equals("hero-5555")){
hl.add(h);
}
}
long end = System.currentTimeMillis();
long elapsed = end -start;
System.out.println("ArrayList列表中共有"+al.size()+"个对象");
System.out.println("用for循环查找到了"+hl.size()+"个名字叫hero-5555的对象");
System.out.println("耗时:"+elapsed);
start = System.currentTimeMillis();
List<Hero> hlist = (List<Hero>) mhm.get("hero-5555");
end = System.currentTimeMillis();
elapsed = end - start;
System.out.println("用MyHashMap查找到了"+hlist.size()+"个名字叫hero-5555的对象");
System.out.println("耗时:"+elapsed);
最后的运行结果是:
ArrayList列表中共有100000个对象
用for循环查找到了15个名字叫hero-5555的对象
耗时:7
用MyHashMap查找到了15个名字叫hero-5555的对象
耗时:0
可以看出,用MyHashMap查询时间比用一般查询ArrayList的方法要快,这里可以添加更多的对象来测试时间差
ArrayList列表中共有1000000个对象
用for循环查找到了139个名字叫hero-5555的对象
耗时:21
用MyHashMap查找到了139个名字叫hero-5555的对象
耗时:0
集合-HashMap的更多相关文章
- JAVA双列集合HashMap
HashMap 双列集合HashMap是属于java集合框架3大类接口的Map类, Map接口储存一组成对的键-值对象,提供key(键)到value(值)的映射.Map中的key不要求有序,不允许 ...
- Java 集合 HashMap & HashSet 拾遗
Java 集合 HashMap & HashSet 拾遗 @author ixenos 摘要:HashMap内部结构分析 Java HashMap采用的是冲突链表方式 从上图容易看出,如果选择 ...
- Java从入门到放弃18---Map集合/HashMap/LinkedHashMap/TreeMap/集合嵌套/Collections工具类常用方法
Java从入门到放弃18—Map集合/HashMap/LinkedHashMap/TreeMap/集合嵌套/Collections工具类常用方法01 Map集合Map集合处理键值映射关系的数据为了方便 ...
- [集合]HashMap和Hashtable区别
底层 哈希算法,双列集合 HashMap 线程不安全,效率高,JDK1.2版本 Hashtable 线程安全,效率低,JDK1.0版本 HashMap 可以存储 null 键和 null 值 ...
- 0014 Java学习笔记-集合-HashMap集合
主要的方法 + 构造方法: * HashMap(); - 默认大小16,负载因子0.75 * HashMap(int initialCapacity); * HashMap(int initialCa ...
- Java集合---HashMap源码剖析
一.HashMap概述二.HashMap的数据结构三.HashMap源码分析 1.关键属性 2.构造方法 3.存储数据 4.调整大小 5.数据读取 ...
- [转载] Java集合---HashMap源码剖析
转载自http://www.cnblogs.com/ITtangtang/p/3948406.html 一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射 ...
- java集合HashMap、HashTable、HashSet详解
一.Set和Map关系 Set代表集合元素无序,集合元素不可重复的集合,Map代表一种由多个key-value组成的集合,map集合是set集合的扩展只是名称不同,对应如下 二.HashMap的工作原 ...
- java集合-HashMap源码解析
HashMap 键值对集合 实现原理: HashMap 是基于数组 + 链表实现的. 通过hash值计算 数组索引,将键值对存到该数组中. 如果多个元素hash值相同,通过链表关联,再头部插入新添加的 ...
随机推荐
- zookeeper脑裂
出现: 在搭建hadoop的HA集群环境后,由于两个namenode的状态不一,当active的namenode由于网络等原因出现假死状态,standby接收不到active的心跳,因此判断activ ...
- python自动化开发-[第十七天]-django的ORM与其他
今日概要: 1.name别名 2.模版的深度查询 3.模版语言之filter 4.自定义过滤器,filter和simpletag的区别 5.orm进阶 扫盲:url的组成 URL:协议+域名+端口+路 ...
- 【SQL】数据库中的五种约束
#五大约束 1.主键约束(Primay Key Coustraint) 唯一性,非空性 2.唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个 3.检查约束 (Check ...
- SQL Server日志过大,清理日志
直接执行下面的代码 USE [master] GO ALTER DATABASE 数据库 SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE 数据库 ...
- git status -s命令解析
git status -s 以精简的方式显示文件状态. git status 输出的命令很详细,但有些繁琐. 如果用 git status -s 或 git status --short 命令,会得到 ...
- css3 rotate(1turn)的用法
1turn:一圈,一个圆共一圈. 90deg = 0.25turn.
- C#设计模式(2)——工厂模式
1.工厂模式介绍 上一篇我们知道了简单工厂的缺点是:当我们添加一个新的产品时需要修改工厂类,这样就违背了开闭原则.工厂模式就是为了解决这一缺陷而出现的,解决的方法是把创建具体实例的任务放在了工厂的子类 ...
- excel vlookup简易样例【原】
vlookup功能 vlookup主要用来做映射,就像java的map一样. 比如我要找id为2的学生对应的名字,那么在F7单元格录入=VLOOKUP(E7,$A$2:$B$4,2,FALSE) 实际 ...
- cdqz2017-test1-数论 (BSGS + 二次剩余 + CRT)
若m=0, 就是求n^2n ≡ x mod p (x--) 因为一定优解,所以x一定是p的二次剩余 令g为p的1个原根,且g^k ≡ x mod p 则k是偶数,证明k是偶数: 假设 g1^k1 ≡ ...
- MVC实用架构设计(三)——EF-Code First(1):Repository,UnitOfWork,DbContext
前言 终于到EF了,实在不好意思,最近有点忙,本篇离上一篇发布已经一个多星期了,工作中的小迭代告一段落,终于有点时间来继续我们的架构设计了,在这里先对大家表示歉意. 其实这段时间我并不是把这个系列给忘 ...