一、介绍
Hashtable 是早期实现的一个哈希存储方式的类,也就是键值对(key-value)的存放方式。实际上市键值对 和 链表的组合,相对同步安全的。
特点:
1.是key-value 方式存放的,并且是无序存放的
2.线程安全的,性能较低
3.key 不允许重复,否者会覆盖数据
4.key 不能为null,否者会空指针异常,
二、源码解析
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable
1.继承了Dictionary,实现 Map接口,和 Cloneable,这里简单说一下。
Dictionary:JDK 1.6阐明是一个过时的,用于存键值对的抽象父类,定义了一些基本属性,有兴趣自己看API。后来建议去实现Map 接口,而不是扩展此类,估计是面向接口编程,怕太臃肿了。只有hashtable继承,不是到有啥用,早就该去掉了。
Map :作为代替Dictionary 的出现,也是定义了键值对的一些方法,好处是便于各种键值对的类自己去实现,让代码更轻了。
Cloneable: 是克隆需要,Vactor 已经说了,就不多讲了。
2.主要构造方法:
// 我们获得的hashtable对象,无论有参数,无参数的 最终都调用的这个构造。 // 参数说明: // initialCapacity : 初始容量,好比新建数组,最开始的长度多少,默认11 // loadFactor:增长因子,默认是0.75f,好比是 你的内容超过了 总长度了75%,就会自动扩容 public Hashtable(int initialCapacity, float loadFactor) { // 初始长度小于0 必然异常 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 实际上是 private transient Entry[] table; // Entry 是一个内部键值对的内部类,下面说 // 可以看到,hashTabale 实际上就是一个 Entry[]的数组 table = new Entry[initialCapacity]; // 这里就是扩容的位置了,也就是会说你的数组容量超过了 下面这个数,默认就会扩容了 threshold = (int)(initialCapacity * loadFactor); }
3.内部类Entry 解析:
private static class Entry<K,V> implements Map.Entry<K,V> { int hash; K key; V value; // 链表的动作,Map 实际有键值对和链表组成,具体的将hash算法再讨论 Entry<K,V> next;
这里可以看到,这里是实现了Map.Entry 接口,定义了一些泛型属性,我们先看这个接口:
// Map 里面的内部接口 interface Entry<K,V> { K getKey(); V getValue(); V setValue(V value); boolean equals(Object o); int hashCode(); } }
// HashTable 内部类的主要方法。 public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); } public int hashCode() { return hash ^ (value==null ? 0 : value.hashCode()); } }
这里可能有些疑惑,既然实现了Map 接口,里面的getKey,getValue 等方法,为什么要用内部类去实现Map 的Entry接口,从而进行实现呢?不是很麻烦吗?
这里我的理解是:提供了一个包含键值对的映射集,这东西更加方便我们进行迭代(遍历),提供一种统一的迭代方式(Iterator),我们获得这个映射之后,可以同时获得 单个的键和值,并且迭代期间任何非自身的操作,都会报错,保证这个映射的唯一性,当然只能通过内部setValue(),进行设置值。
同时这个键值对在其他地方 有很灵活的使用,让你获得键 值 等个各种方式,更加灵活,后面会有
其实HashTbale 自身提供了 获得key 和value 的方式,请看源码:
// 获得values private transient volatile Collection<V> values = null;
// 这是获得所有值的方式 public Collection<V> values() { if (values==null) // 这里是通过一个内部,和 当前hashMap 对象,通过collection 方法获得值的集合 // 这里使用的是线程安全的方法 values = Collections.synchronizedCollection(new ValueCollection(), this); return values; } private class ValueCollection extends AbstractCollection<V> { public Iterator<V> iterator() { return getIterator(VALUES); } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { Hashtable.this.clear(); } }
顺便看看Collections.synchronizedCollection 源码:
static <T> Collection<T> synchronizedCollection(Collection<T> c, Object mutex) {
return new SynchronizedCollection<T>(c, mutex);
}
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
// 这里就只有一个赋值操作
SynchronizedCollection(Collection<E> c, Object mutex) {
this.c = c;
this.mutex = mutex;
}
从代码上看,相当于是把 ValueCollection 这个内部类 和hashtable 传入进去赋值给对象了。
1.ValueCollection 里面有iterator(),size() 等方法。这里相当于colleaction 方法里面有几乎所有
集合的基本方法接口,然后实现在各个集合里面。但是集合里面定义内部类 同样调用实现那些实现方 法的作用是为了将内部类 传回给colleaction ,让集合具有一种通用的访问这些元素的方法。
比如:Collection 定义集合可以看电影。hashtable 实现 用电脑看电影。 然后定义内部类,里面把用电脑看电影这种方式也放进去,然后可以送给Collection 集合,那么它就可以知道是用电脑看电影了。 也就是说,看电影这种举动很多集合都有,Collection 作为一种工具,只要任何其他集合传入一个方式过来,就可以调用各自的看电影的方式了。
2.参数this,实际上是一把对锁,实现线程安全的。这里看Collection 里面对这个内部类的操作就知道
// 这是获得,key 的集合 private transient volatile Set<K> keySet = null; // 上面的key,values private transient volatile Set<Map.Entry<K,V>> entrySet = null;
public Set<K> keySet() { if (keySet == null) keySet = Collections.synchronizedSet(new KeySet(), this); return keySet; } private class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return getIterator(KEYS); } public int size() { return count; } public boolean contains(Object o) { return containsKey(o); } // 多一个方法 public boolean remove(Object o) { return Hashtable.this.remove(o) != null; } public void clear() { Hashtable.this.clear(); } }
这里你会发现,获得keys 和values方法几乎一样,只是这里多提供了一个remove 方法,
那么这两个相同的方法 是如何 分别获得key 和value 的呢?请看:
// 这是主要不同点:
public Iterator<K> iterator() { return getIterator(KEYS); } public Iterator<K> iterator() { return getIterator(VALUES); } // 这几个参数 对应了 ,返回的类型,表示 枚举 private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2;
// 方法,发现这里其实是返回的是一个内部类, count = 0 的也是内部类,这里不介绍了 ,里面就判// 定空值的,主要看Enumerator
private <T> Iterator<T> getIterator(int type) {
if (count == 0) {
return (Iterator<T>) emptyIterator;
} else {
return new Enumerator<T>(type, true);
}
相关推荐
1.1 深入JAVA API 1.1.1 Lang包 1.1.2 集合类 1.1.2.1.1 日期类Date 1.1.2.1.2 日历类Calendar 1.1.2.1.3 随机数类Random 1.1.2.1.4 向量类Vector 1.1.2.1.5 栈类Stack 1.1.2.1.6 哈希表类Hashtable 1.1.2.1.7 ...
·基于JDK 11,将Java8、Java9、Java10、Java11新特性一网打尽 ·课程中,Eclipse和IDEA这两种企业一线开发环境都使用到了 3.技术讲解更深入、更全面: ·课程共30天,715个知识视频小节,涉及主流Java使用的...
java软件技术文档
Java集合详解4:HashMap和HashTable Java集合详解5:深入理解LinkedHashMap和LRU缓存 Java集合详解6:TreeMap和红黑树 Java集合详解7:HashSet,TreeSet与LinkedHashSet Java集合详解8:Java集合类细节精讲 JavaWeb
需要程序员经常刷题吗simple-java-zh-CN Simple Java 是 Java 常见问题的集合。中文翻译 ##1。 字符串和数组字符串...深入理解Arrays.sort(T[], Comparator < ? super T > c) 常见排序,Collections、Arrays、Tre
【Java工程师面试复习指南】本仓库架构大部分Java工程师所需要掌握的核心知识,整合了互联网上的很多优质Java技术文章,力求打造为最完整最实用的...Java集合详解:HashMap和HashTable Java集合详解:深入理解LinkedHas
高级java笔试题 interview 2017届春招秋招公司的面试题目 #阿里内推(Android开发) ##笔试 ####选择题: 快速排序 二叉树遍历 UML类图 ...7.java集合类,哪些线程安全,哪些线程不安全 8.线程安全
│ Java面试题11.HashMap和HashTable的区别.mp4 │ Java面试题12.实现一个拷贝文件的类使用字节流还是字符串.mp4 │ Java面试题13.线程的实现方式 怎么启动线程怎么区分线程.mp4 │ Java面试题14.线程并发库和线程池...
1.1 深入JAVA API 2 1.1.1 Lang包 2 1.1.2 集合类 8 1.1.2.1.1 日期类Date 9 1.1.2.1.2 日历类Calendar 10 1.1.2.1.3 随机数类Random 11 1.1.2.1.4 向量类Vector 12 1.1.2.1.5 栈类Stack 13 1.1.2.1.6 哈希表类...
JAVA_Thinking in Java(中文版 由yyc,spirit整理).chm ------------------------------------------------- 本教程由yyc,spirit整理 ------------------------------------------------- “Thinking in Java...
第三题 对比HashTable HashMap TreeMap有什么不同.pdf 第二题 Exception Error区别.pdf 第五题 如何保证集合是线程安全的.pdf 第八题 Java并发类库提供的线程池有哪几种 分别有什么特点.pdf 第六题 synchronized和...
8.4.4 Hashtable 8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 ...
在以后的章节中,用通俗易懂的手法,紧密联系实际应用的方式,深入浅出地讲解了多线程,常用Java类,Java中的I/O(输入输出)编程,GUI与Applet,网络编程等方面的知识。 本书许多内容都来源于程序员圈子里的非正式...
8.4.4 Hashtable 8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 ...
8.4.4 Hashtable 8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 ...
7.1 Java集合概述 241 7.2 Collection和Iterator接口 243 7.2.1 使用Iterator接口遍历集合元素 244 7.2.2 使用foreach循环遍历集合元素 246 7.3 Set接口 247 7.3.1 HashSet类 247 学生提问:hashCode方法对于...
8.4.4 Hashtable 8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 ...
8.4.4 Hashtable 8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 ...