- 浏览: 175673 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
surfingll:
思路不错,赞一个
站内信的实现:数据库的设计 -
shakajava:
哎,都是千篇一律的东西
站内信的实现:数据库的设计 -
java_xiaoyi:
不错...
java API -
tonysmith:
兄弟说的太对了。干活用了一年多,考官一问,只知其一。这是个“杯 ...
Java 中的访问权限控制 -
上官车月:
像牛一样的干了一年多,除了工作和加班 还真没有想过,基础的东西 ...
Java 中的访问权限控制
我想先问一个问题:为什么hashmap允许key可以为null(only one),value可以为null?二hashtable不可以呢?
Hashtable从JDK1.0就已经有了, 所以让我们先来看看它是怎么工作, 然后有浅入深, 来研究HashMap的原理, 以及两者的不同点.
Hashtable有几个主要的字段, 如下,
/**
* The hash table data.
*/
private transient Entry[] table;
/**
* The total number of entries in the hash table.
*/
private transient int count;
/**
* The table is rehashed when its size exceeds this
threshold. (The
* value of this field is (int)(capacity *
loadFactor).)
*
* @serial
*/
private int threshold;
其中最重要的就是那个table数组了. 它就是整个hashtable的基本数据结构! 在来看一下这个字段
private transient Entry[] table;
可以看到, hashtable的基本数据结构就是, 一个包涵Entry类的二维数组. 而这个Entry类是hashtable的内在类, 它其实是一个单向链, 让我们详细分析一下.
private
static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
K key;
V value;
Entry<K,V> next;
...
...
看到这里有没有想到学校里教的数据结构原理这门课呢? Entry类就是定义了一个很简单的单向链结构, 它里面包括key, value和下个Entry类的对象next.
在这里我在强调一下, hashtable的数据结构就是一个包涵单向链的二维数组.
接下来让我们来看看hashtable的构造器是长的什么样的.
最长用的
public Hashtable() {
this(11,
0.75f);
}
这个构造器调用了另外一个构造器
public Hashtable(int initialCapacity, float loadFactor) {
if
(initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity:
"+
initialCapacity);
if (loadFactor <= 0 ||
Float.isNaN(loadFactor))
throw new
IllegalArgumentException("Illegal Load: "+loadFactor);
if (initialCapacity==0)
initialCapacity
= 1;
this.loadFactor = loadFactor;
table = new
Entry[initialCapacity];
threshold = (int)(initialCapacity * loadFactor);
}
细读代码后, 我们发现这个构造器构造了table字段和threshold. Table前面已经详细讲了, 那么这个threshold又是什么东东呢?
其实这个threshold对hashtalbe的性能影响是很大的! 因为table是个数组, 如果在hashtable中保存的实体大于一定的数量后, 对数据的读写就会有很慢, 那是因为, 很多数据都保存在entry类的单向链中, 每次读写都要比对链中所有的数据, 链越长读写就越慢.
所以当数据容量大于threshold的时候, hashtable就会做rehash(), rehash把table的容量扩大一倍, 再把从前在table里的数据统统搬回新的table. 这样的一个过程, 开销是多么的大呀.
threshold = (int)(initialCapacity * loadFactor);
Hashtable类提供了构造涵数, 用户可以自定, intitialCapacity和loadFactor. 对于那些大概知道容量的hashtable, 用户应该自定intitialCapacity. 这样的话, 就可以省去一大笔rehash的开销.
现在让我们来看hashtable的put和get操作
public synchronized V get(Object key) {
Entry tab[]
= table;
int hash =
key.hashCode();
int index =
(hash & 0x7FFFFFFF) % tab.length;
for
(Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}
先来看get方法, get可谓是hashtable中的最基本方法了, 它是通过key来拿到hashtable中的value.
int hash = key.hashCode();
int index =
(hash & 0x7FFFFFFF) % tab.length;
从key拿到hashCode, 从hashCode再计算出在table中的index, 也就是在数组中的第几个列.
至于为什么要与 0x7FFFFFFF, 那是hashtable 提供的hash算法, hashMap提供了不同的算法, 用户如果要定义自己的算法也是可以的. 如果要知道不同的具体算法, 就google or 百度一下吧.
好了, 现在我们有了index, 就可以到table数组里的entry单向链去找value啦.
for (Entry<K,V> e
= tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
for语句就是简单的检索entry的单链, if语句检查key是否相同. 这里就遇到了java学习中的一个重大知识点. hasCode()和equal()的关系.
大家都学过如果hasCode()的值相同的话, equal不一定相同, 而如果equal相同的话, hasCode一定要相同. 但那是为什么呢? 其实答案就在上面的代码中!
Hashtable的数据结构是一个包涵单向链的二维数组. 从hasCode我们得到hash和index, 并得以确定这个key在table数组中的第几个列, 然而这显然是不够的, 因为, entry类是一个单向列, 它可以是一个, 也可能是很多个key组成, 那么要从一系列有着相同hasCode的entry中找到, 我们所要的key的话, 就要用equals了. 只有两个key是相等的, 那才是我们要找的. 找到key之后, 只要简单的把value返回就好了. 如果对entry类还有疑问的话, 请参考前面的解释.
public
synchronized V put(K key, V value) {
// Make sure
the value is not null
if (value ==
null) {
throw new NullPointerException();
}
// Makes
sure the key is not already in the hashtable.
Entry tab[]
= table;
int hash =
key.hashCode();
int index =
(hash & 0x7FFFFFFF) % tab.length;
for
(Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count
>= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index =
(hash & 0x7FFFFFFF) % tab.length;
}
// Creates
the new entry.
Entry<K,V> e = tab[index];
tab[index] =
new Entry<K,V>(hash, key, value, e);
count++;
return null;
}
接下来再来看看put方法, 理解了get, put就很容易弄明白了.
首先, 要放入hashtable的value不能是null, 否则就报错.
其次, 然后要确保key不能已经在hashtable里面, 有的话, 就返回value.
再次, 检查是否容量已经太大, 如果太大话就rehash, 这会是一个很浪费资源的方法, 请参考前文.
最后, 也是最重要的, 我们要把key-value保存到hashtable中去.
Entry<K,V> e = tab[index];
tab[index] =
new Entry<K,V>(hash, key, value, e);
1. 拿到当前在table数组中的entry对象.
2. 根据传入的key和value建一个新的entry并赋予给当前的table的index中
protected Entry(int hash, K key, V value, Entry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
这是entry类的构造函数. 简单的说, 就是在单链的最前端加了个新的entry对象. 从这里也可以看出, 对于那些后写入的object, 反而可以以比较快的速度读出, 那是因为后写入的object, 总是在链的前端.
看完了hashtable, 我们在来看看hashMap
hashMap可以算作是hashtable的升级版本, 最早从1.2开始有的.
整体上hashMap对hashtable类优化了代码. 比如说, 消除了hardcoding, 增加了code reuse等等.
但是, 两者之间最主要的不同有两点.
1. hashMap的读写是unsynchronized, 在多线程的环境中要注意使用
而hashtable是synchronized
这两者的不同是通过在读写方法上加synchronized关键字来实现的.
hashMap
public V put(K key, V value)
public V get(Object key)
hashtable
public synchronized V get(Object key)
public synchronized V put(K key, V value)
可能有人问, 能synchronized, 能线程安全好啊. 为什么不要呢?
这里其实还是一个效率的问题. 对于线程安全的方法, 系统要进行加锁, 减锁操作. 性能会有很大的影响. 由于很多程序是在单线程或者说是线程安全的情况下工作的, 所以用synchronized就显得多余了.
3. 第二个不同是hashMap可以放空值, 而hashtable就会报错.
hashMap
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
hashtable
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
发表评论
-
字符串比较之 “==”和 “equals”
2012-03-05 13:04 915字符串比较之 “==”和 “equals” 提示:引用 ... -
介绍一下抽象类和接口的异同
2012-03-02 16:27 1116我把基本的弄成了表格形式的。下载附件吧。本想吧table co ... -
Java 中的上转型对象 使用
2012-03-02 15:34 5556呵呵。最近交接工作比较闲,顺便温习一下基础的知识吧: 今天看 ... -
最好的学习地址:Java开源框架SSH 和 ANT的学习地址
2012-02-29 15:44 1060给大家推荐一个我经常去看的网站:这个网站适合初级程序员,学生, ... -
Java 中的访问权限控制
2012-02-29 15:39 2141要辞职了,突然觉得这 ... -
JDK和JRE的区别
2012-02-29 12:17 1178<!--end: blogStats -->< ... -
Java 接口学习笔记
2012-02-26 02:23 3java语言不支持一个类有多个直接的父类(多继承),但可以实现 ... -
浅谈HTTP中Get与Post的区别(转)
2012-02-15 12:24 1207浅谈HTTP中Get与Post的区别 Http ... -
JDK中的URLConnection参数详解(转)
2012-02-15 11:51 1349JDK中的URLConnection参数 ... -
Java利用HttpURLConnection发送post请求上传文件
2012-02-14 10:58 2178在页面里实现上传文件不是什么难事,写个form,加上encty ... -
Java 存储过程 Mysql
2011-12-20 12:16 1339一:Java如何实现对存储过程的调用: A:不带输出参数的 ... -
spring jdbcTemplate
2011-12-08 11:08 1016先看applicationContext.xml配置文件: ... -
MyEclipse 8.6 download 官方下载地址
2011-12-07 14:28 1454Downloads: MyEclipse 8.6 for Ec ... -
windows下架设svn服务器
2011-12-07 11:36 933* 传统的Subversion 服务器 ... -
tomcat7.0 manager app和host manager web管理(转)
2011-12-07 11:23 10858在捣腾Tomcat 7的时候遇到一个问题,很多人对tomc ... -
Tomcat7.0 Error:java.lang.NoClassDefFoundError
2011-12-07 10:34 1316前面一段时间看到Tomcat7.0发布了几个测试版,由于没有稳 ... -
tomcat5.5 Error:cannot find the declaration of element 'web-app'
2011-12-05 12:01 2105tomcat 启动:cannot find the decla ... -
设置 session 失效时间的方法(转)
2011-09-21 09:57 1236具体设置很简单,方法有三种: (1) 在主页面或者公共页 ... -
Java读取properties文件的思考
2011-07-19 10:24 1026Java读取properties文件的思考 Java读 ... -
使用J2SE读取Properties文件的六种方式(转)
2011-07-19 10:24 1030使用J2SE读取Properties文件的六种方式: 1.使用 ...
相关推荐
### HashMap与HashTable的区别详解 #### 引言 在Java编程中,`HashMap`与`HashTable`作为两种常用的数据结构,经常被用来存储键值对数据。尽管它们在功能上相似,但在实现细节、性能表现以及使用场景方面存在显著...
### HashMap与Hashtable的区别 在Java编程语言中,`HashMap`和`Hashtable`是两种非常重要的数据结构,它们都用于存储键值对。然而,在实际应用过程中,这两种数据结构有着本质的不同,下面将详细介绍这些差异。 ##...
### HashMap与HashTable的区别 在Java编程语言中,`HashMap`和`HashTable`是两种非常重要的数据结构,它们都实现了`Map`接口,并提供了键值对的存储方式。这两种数据结构虽然相似,但在实现细节和使用场景上存在...
### hashMap和hashTable的区别 #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在...
### HashMap与HashTable和HashSet的区别 #### 一、概述 在Java集合框架中,`HashMap`, `HashTable` 和 `HashSet` 是三个重要的数据结构,它们分别实现了`Map`接口和`Set`接口,提供了不同的功能来满足不同的编程...
HashMap和HashTable是Java中两个常用的数据结构,都是基于哈希表实现的,但它们之间存在着一些关键的区别。本文将深入探讨HashMap和HashTable的底层原理,并总结常见的面试题。 HashMap的底层原理 HashMap是Java中...
在Java编程语言中,`HashMap`和`HashTable`都是实现键值对存储的数据结构,但它们之间存在一些显著的区别,这些区别主要体现在线程安全性、性能、null值处理以及一些方法特性上。以下是对这两个类的详细分析: 1. ...
### Hashtable与HashMap的区别详解 #### 一、基本概念与历史背景 在Java编程语言中,`Hashtable` 和 `HashMap` 都是用来存储键值对的数据结构。这两种数据结构虽然相似,但是在实现细节上存在显著差异。 1. **...
Java集合专题总结:HashMap和HashTable源码...本文总结了HashMap和HashTable的源码学习和面试总结,涵盖了它们的存储结构、构造方法、get和put方法的源码分析、Hash表的特点和缺点、HashTable和HashMap的区别等内容。
hashmap和hashtable的区别
### Hashtable和HashMap的区别 在Java编程语言中,`Hashtable`和`HashMap`是两种非常重要的数据结构,它们都实现了`Map`接口,用于存储键值对。尽管它们有着相似的功能,但在实现细节和应用场景上存在显著差异。接...
HashMap与HashTable的主要区别在于线程安全性和对null值的支持。HashMap是非同步的,意味着在多线程环境中,如果不进行适当的同步控制,可能会导致数据不一致。而HashTable是同步的,因此它在多线程环境下的安全性更...
在Java编程语言中,集合框架是处理对象数组的重要工具,其中`List`、`ArrayList`、`Vector`、`HashTable`和`HashMap`是五个关键的接口和类,它们各有不同的特性和用途。以下是这些概念的详细解释: 1. **List接口**...
在Java编程语言中,`HashMap`和`HashTable`都是实现`Map`接口的数据结构,用于存储键值对。它们在很多方面有所不同,这些差异主要体现在线程安全性、迭代器类型、null值支持以及哈希码处理等方面。以下是关于两者...
hashMap和Hashtable的区别1
HashMap, HashTable, LinkedHashMap, TreeMap 的区别 在 Java 中,Map 是一个非常重要的集合类,用于存储键值对。其中,HashMap, HashTable, LinkedHashMap, TreeMap 是四种常用的 Map 实现类,每种类都有其特点和...
HashMap 和 Hashtable 是 Java 集合框架中两个重要的映射数据结构,它们都实现了 Map 接口,但具有显著的差异。以下将详细介绍这两个类的主要区别: 1. 线程安全性: - HashMap 不是线程安全的,这意味着在多线程...
### Hashtable与HashMap的区别 在Java编程语言中,`Hashtable`和`HashMap`是两种非常重要的数据结构,它们都属于`Map`接口的实现类,用于存储键值对数据。尽管两者在功能上相似,但在实际应用中却存在显著差异。 #...
了解这些区别后,开发者可以根据具体需求选择使用`HashMap`或`HashTable`。在大多数情况下,由于性能和灵活性的考虑,`HashMap`是首选。然而,如果在多线程环境中且无法通过其他手段确保同步,那么`HashTable`可能是...
- HashMap 和 Hashtable 都实现了 Map 接口,HashMap 更快但不是线程安全的,而 Hashtable 是线程安全但较慢。WeakHashMap 则使用弱引用作为键,有助于防止内存泄漏。 - 在选择使用哪种数据结构时,需要考虑性能需求...