您的位置:首页 > 编程语言 > Java开发

java集合框架系列---遗留下来的集合框架

2016-09-13 00:09 681 查看
java第一版遗留下来的集合框架(容器类):

Vector

Stack

Hashtable

Dictionary

Properties

都是同步(用synchronized实现)



1、Vector

特点

1、Vector类实现了一个动态数组;

2、可以往其中随意插入不同类的对象,即不需顾及类型也不需预先选定向量的容量

4、Vector: 底层用数组实现List接口的另一个类

5、重量级,占据更多的系统开销 线程安全

源码分析

在这个类中有三个重要的变量定义,如下:

otected Object[] elementData; //它保存了添加到Vector中的元素,elementData是个动态数组,如果初始化Vector时,没指定动态数组的>大小,则使用默认大小10

protected int elementCount; // 动态数组中存储元素的个数

protected int capacityIncrement;

扩容:

(01) Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10。

(02) 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。

(03) Vector的克隆函数,即是将全部元素克隆到一个数组中。

Vector 实现了RandmoAccess接口,即提供了随机访问功能;RamdomAccess 接口是一个空接口,空接口的作用一般起到一个标识作用,比如:Serializable 接口;

功能

构造

提供了三种构造方法:

public vector()

public vector(int initialcapacity,int capacityIncrement)

public vector(int initialcapacity)

使用第一种方法系统会自动对向量进行管理;

若使用后两种方法,则系统将根据参数,initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时,系统会扩充向量对象存储容量,参数capacityincrement给定了每次扩充的扩充值;当capacityincrement为0的时候,则每次扩充一倍;

插入

(1)public final synchronized void adddElement(Object obj)

将obj插入向量的尾部。obj可以是任何类型的对象。对同一个向量对象,亦可以在其中插入不同类的对象。

(2)public final synchronized void setElementAt(Object obj,int index)

将index处的对象设置成obj,原来的对象将被覆盖。

(3)public final synchronized void insertElement(Object obj,int index)

在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。 需要移动数据;

查找

(1)public final int indexOf(Object obj)

从向量头开始搜索obj,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1.

(2)public final synchronized int indexOf(Object obj,int index)

从index所表示的下标处开始搜索obj.

(3)public final int lastindexOf(Object obj)

从向量尾部开始逆向搜索obj.

(4)public final synchornized int lastIndex(Object obj,int index)

从index所表示的下标处由尾至头逆向搜索obj.

(5)public final synchornized firstElement()

获取向量对象中的首个obj

(6)public final synchornized Object lastElement()

获取向量对象的最后一个obj

删除

(1)public final synchronized void removeElement(Object obj)

从向量中删除obj,若有多个存在,则从向量头开始试,删除找到的第一个与obj相同的向量成员。

(2)public final synchronized void removeAllElement();

删除向量所有的对象

(3)public fianl synchronized void removeElementAt(int index)

删除index所指的地方的对象

获取容量信息

public final int size();

此方法用于获取向量元素的个数。它们返回值是向量中实际存在的元素个数,而非向量容量。

capacity()来获取容量值。

遍历

1)for循环

2)增强的for循环

3)迭代器

和ArrayList对比

相同:

1)都是List

都继承于AbstractList,并且实现List接口

2)都实现了RandomAccess和Cloneable接口

实现RandomAccess接口,意味着它们都支持快速随机访问;

实现Cloneable接口,意味着它们能克隆自己。

3)通过数组实现的,本质上都是动态数组

4)默认数组容量是10

5)支持Iterator和listIterator遍历

不同:

1)线程安全性不同

Vector是同步访问的,即方法都用synchronized修饰;

ArrayList会比Vector快,因为没有同步,但是多线程下不安全;

2)扩容方式不同

ArrayList在内存不够时默认是扩展50% + 1个,Vector在capacityIncrement大于为时扩容capacityIncrement大小,否则为原始容量的2倍。

3)对序列化支持不同

ArrayList支持序列化,而Vector不支持;即ArrayList有实现java.io.Serializable接口,而Vector没有实现该接口。

4)对Enumeration的支持不同。

Vector支持通过Enumeration去遍历,而List不支持

Stack

介绍

Stack是栈。它的特性是:先进后出(FILO, First In Last Out)。Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现的,这就意味着,Stack也是通过数组实现的;通过对数组的操作来模仿栈的各种功能;

Vector的很多方法都是synchronized 的,也就是说是线程安全,所以说在多线程中是可以安全使用的,不过这样效率上肯定是会降低的。

源码分析

源码如下:

public class Stack<e> extends Vector<e> {
public Stack() {    }
public E push(E item) {       // 压栈
addElement(item);

return item;
}

public synchronized E pop() { // 弹栈
E   obj;
int  len = size();
obj = peek();
removeElementAt(len - 1);

return obj;
}

public synchronized E peek() { // 返回栈顶元素
int  len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}

public boolean empty() {      // 判断栈是否为空
return size() == 0;
}

public synchronized int search(Object o) {  // 查找元素
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}

}


Stack类发现含有的方法有pop(),peek(),push(Object),search(Object),empty()方法,其他值的方法是从Vector类继承而来;

Dictionary

介绍

Dictionary 类是
4000
一个抽象类,用来存储键/值对,作用和Map类相似。

Hashtable

介绍

Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。

Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。

Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。

Hashtable中的映射不是有序的。

Hashtable 的实例有两个参数影响其性能:初始容量加载因子

容量是哈希表中 桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。

加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。

初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。

通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable 操作中,包括 get 和 put 操作,都反映了这一点)。

构造函数

// 默认构造函数。
public Hashtable()

// 指定“容量大小”的构造函数
public Hashtable(int initialCapacity)

// 指定“容量大小”和“加载因子”的构造函数
public Hashtable(int initialCapacity, float loadFactor)

// 包含“子Map”的构造函数
public Hashtable(Map<? extends K, ? extends V> t)


Hashtable的API

synchronized void                clear()
synchronized Object              clone()
boolean             contains(Object value)
synchronized boolean             containsKey(Object key)
synchronized boolean             containsValue(Object value)
synchronized Enumeration<V>      elements()
synchronized Set<Entry<K, V>>    entrySet()
synchronized boolean             equals(Object object)
synchronized V                   get(Object key)
synchronized int                 hashCode()
synchronized boolean             isEmpty()
synchronized Set<K>              keySet()
synchronized Enumeration<K>      keys()
synchronized V                   put(K key, V value)
synchronized void                putAll(Map<? extends K, ? extends V> map)
synchronized V                   remove(Object key)
synchronized int                 size()
synchronized String              toString()
synchronized Collection<V>       values()


数据结构



(01) Hashtable继承于Dictionary类,实现了Map接口。Map是”key-value键值对”接口,Dictionary是声明了操作”键值对”函数接口的抽象类。

(02) Hashtable是通过”拉链法”实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount。

  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的”key-value键值对”都是存储在Entry数组中的。 Entry 实际上就是一个单向链表。这也是为什么我们说Hashtable是通过拉链法解决哈希冲突的;

  count是Hashtable的大小,它是Hashtable保存的键值对的数量。

  threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值=”容量*加载因子”。

  loadFactor就是加载因子。

  modCount是用来实现fail-fast机制的

源码分析

源码

package java.util;
import java.io.*;

public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {

// Hashtable保存key-value的数组。
// Hashtable是采用拉链法实现的,每一个Entry本质上是一个单向链表
private transient Entry[] table;

// Hashtable中元素的实际数量
private transient int count;

// 阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子)
private int threshold;

// 加载因子
private float loadFactor;

// Hashtable被改变的次数
private transient int modCount = 0;

// 序列版本号
private static final long serialVersionUID = 1421746759512286392L;

// 指定“容量大小”和“加载因子”的构造函数
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);
}

// 指定“容量大小”的构造函数
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}

// 默认构造函数。
public Hashtable() {
// 默认构造函数,指定的容量大小是11;加载因子是0.75
this(11, 0.75f);
}

// 包含“子Map”的构造函数
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
// 将“子Map”的全部元素都添加到Hashtable中
putAll(t);
}

public synchronized int size() {
return count;
}

public synchronized boolean isEmpty() {
return count == 0;
}

// 返回“所有key”的枚举对象
public synchronized Enumeration<K> keys() {
return this.<K>getEnumeration(KEYS);
}

// 返回“所有value”的枚举对象
public synchronized Enumeration<V> elements() {
return this.<V>getEnumeration(VALUES);
}

// 判断Hashtable是否包含“值(value)”
public synchronized boolean contains(Object value) {
// Hashtable中“键值对”的value不能是null,
// 若是null的话,抛出异常!
if (value == null) {
throw new NullPointerException();
}

// 从后向前遍历table数组中的元素(Entry)
// 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value
Entry tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}

public boolean containsValue(Object value) {
return contains(value);
}

// 判断Hashtable是否包含key
public synchronized boolean containsKey(Object key) {
Entry tab[] = table;
int hash = key.hashCode();
// 计算索引值,
// % tab.length 的目的是防止数据越界
int index = (hash & 0x7FFFFFFF) % tab.length;
// 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return true;
}
}
return false;
}

// 返回key对应的value,没有的话返回null
public synchronized V get(Object key) {
Entry tab[] = table;
int hash = key.hashCode();
// 计算索引值,
int index = (hash & 0x7FFFFFFF) % tab.length;
// 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
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;
}

// 调整Hashtable的长度,将长度变成原来的(2倍+1)
// (01) 将“旧的Entry数组”赋值给一个临时变量。
// (02) 创建一个“新的Entry数组”,并赋值给“旧的Entry数组”
// (03) 将“Hashtable”中的全部元素依次添加到“新的Entry数组”中
protected void rehash() {
int oldCapacity = table.length;
Entry[] oldMap = table;

int newCapacity = oldCapacity * 2 + 1;
Entry[] newMap = new Entry[newCapacity];

modCount++;
threshold = (int)(newCapacity * loadFactor);
table = newMap;

for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;

int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e
17fad
.next = newMap[index];
newMap[index] = e;
}
}
}

// 将“key-value”添加到Hashtable中
public synchronized V put(K key, V value) {
// Hashtable中不能插入value为null的元素!!!
if (value == null) {
throw new NullPointerException();
}

// 若“Hashtable中已存在键为key的键值对”,
// 则用“新的value”替换“旧的value”
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;
}
}

// 若“Hashtable中不存在键为key的键值对”,
// (01) 将“修改统计数”+1
modCount++;
// (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)
//  则调整Hashtable的大小
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();

tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}

// (03) 将“Hashtable中index”位置的Entry(链表)保存到e中
Entry<K,V> e = tab[index];
// (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。
tab[index] = new Entry<K,V>(hash, key, value, e);
// (05) 将“Hashtable的实际容量”+1
count++;
return null;
}

// 删除Hashtable中键为key的元素
public synchronized V remove(Object key) {
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
// 找到“key对应的Entry(链表)”
// 然后在链表中找出要删除的节点,并删除该节点。
for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
V oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}

// 将“Map(t)”的中全部元素逐一添加到Hashtable中
public synchronized void putAll(Map<? extends K, ? extends V> t) {
for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
put(e.getKey(), e.getValue());
}

// 清空Hashtable
// 将Hashtable的table数组的值全部设为null
public synchronized void clear() {
Entry tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
}

// 克隆一个Hashtable,并以Object的形式返回。
public synchronized Object clone() {
try {
Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
t.table = new Entry[table.length];
for (int i = table.length ; i-- > 0 ; ) {
t.table[i] = (table[i] != null)
? (Entry<K,V>) table[i].clone() : null;
}
t.keySet = null;
t.entrySet = null;
t.values = null;
t.modCount = 0;
return t;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}

public synchronized String toString() {
int max = size() - 1;
if (max == -1)
return "{}";

StringBuilder sb = new StringBuilder();
Iterator<Map.Entry<K,V>> it = entrySet().iterator();

sb.append('{');
for (int i = 0; ; i++) {
Map.Entry<K,V> e = it.next();
K key = e.getKey();
V value = e.getValue();
sb.append(key   == this ? "(this Map)" : key.toString());
sb.append('=');
sb.append(value == this ? "(this Map)" : value.toString());

if (i == max)
return sb.append('}').toString();
sb.append(", ");
}
}

// 获取Hashtable的枚举类对象
// 若Hashtable的实际大小为0,则返回“空枚举类”对象;
// 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
private <T> Enumeration<T> getEnumeration(int type) {
if (count == 0) {
return (Enumeration<T>)emptyEnumerator;
} else {
return new Enumerator<T>(type, false);
}
}

// 获取Hashtable的迭代器
// 若Hashtable的实际大小为0,则返回“空迭代器”对象;
// 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
private <T> Iterator<T> getIterator(int type) {
if (count == 0) {
return (Iterator<T>) emptyIterator;
} else {
return new Enumerator<T>(type, true);
}
}

// Hashtable的“key的集合”。它是一个Set,意味着没有重复元素
private transient volatile Set<K> keySet = null;
// Hashtable的“key-value的集合”。它是一个Set,意味着没有重复元素
private transient volatile Set<Map.Entry<K,V>> entrySet = null;
// Hashtable的“key-value的集合”。它是一个Collection,意味着可以有重复元素
private transient volatile Collection<V> values = null;

// 返回一个被synchronizedSet封装后的KeySet对象
// synchronizedSet封装的目的是对KeySet的所有方法都添加synchronized,实现多线程同步
public Set<K> keySet() {
if (keySet == null)
keySet = Collections.synchronizedSet(new KeySet(), this);
return keySet;
}

// Hashtable的Key的Set集合。
// KeySet继承于AbstractSet,所以,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();
}
}

// 返回一个被synchronizedSet封装后的EntrySet对象
// synchronizedSet封装的目的是对EntrySet的所有方法都添加synchronized,实现多线程同步
public Set<Map.Entry<K,V>> entrySet() {
if (entrySet==null)
entrySet = Collections.synchronizedSet(new EntrySet(), this);
return entrySet;
}

// Hashtable的Entry的Set集合。
// EntrySet继承于AbstractSet,所以,EntrySet中的元素没有重复的。
private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public Iterator<Map.Entry<K,V>> iterator() {
return getIterator(ENTRIES);
}

public boolean add(Map.Entry<K,V> o) {
return super.add(o);
}

// 查找EntrySet中是否包含Object(0)
// 首先,在table中找到o对应的Entry(Entry是一个单向链表)
// 然后,查找Entry链表中是否存在Object
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry entry = (Map.Entry)o;
Object key = entry.getKey();
Entry[] tab = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

for (Entry e = tab[index]; e != null; e = e.next)
if (e.hash==hash && e.equals(entry))
return true;
return false;
}

// 删除元素Object(0)
// 首先,在table中找到o对应的Entry(Entry是一个单向链表)
// 然后,删除链表中的元素Object
public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
K key = entry.getKey();
Entry[] tab = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

for (Entry<K,V> e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if (e.hash==hash && e.equals(entry)) {
modCount++;
if (prev != null)
prev.next = e.next;
else
tab[index] = e.next;

count--;
e.value = null;
return true;
}
}
return false;
}

public int size() {
return count;
}

public void clear() {
Hashtable.this.clear();
}
}

// 返回一个被synchronizedCollection封装后的ValueCollection对象
// synchronizedCollection封装的目的是对ValueCollection的所有方法都添加synchronized,实现多线程同步
public Collection<V> values() {
if (values==null)
values = Collections.synchronizedCollection(new ValueCollection(),
this);
return values;
}

// Hashtable的value的Collection集合。
// ValueCollection继承于AbstractCollection,所以,ValueCollection中的元素可以重复的。
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();
}
}

// 重新equals()函数
// 若两个Hashtable的所有key-value键值对都相等,则判断它们两个相等
public synchronized boolean equals(Object o) {
if (o == this)
return true;

if (!(o instanceof Map))
return false;
Map<K,V> t = (Map<K,V>) o;
if (t.size() != size())
return false;

try {
// 通过迭代器依次取出当前Hashtable的key-value键值对
// 并判断该键值对,存在于Hashtable(o)中。
// 若不存在,则立即返回false;否则,遍历完“当前Hashtable”并返回true。
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Map.Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(t.get(key)==null && t.containsKey(key)))
return false;
} else {
if (!value.equals(t.get(key)))
return false;
}
}
} catch (ClassCastException unused)   {
return false;
} catch (NullPointerException unused) {
return false;
}

return true;
}

// 计算Hashtable的哈希值
// 若 Hashtable的实际大小为0 或者 加载因子<0,则返回0。
// 否则,返回“Hashtable中的每个Entry的key和value的异或值 的总和”。
public synchronized int hashCode() {
int h = 0;
if (count == 0 || loadFactor < 0)
return h;  // Returns zero

loadFactor = -loadFactor;  // Mark hashCode computation in progress
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
for (Entry e = tab[i]; e != null; e = e.next)
h += e.key.hashCode() ^ e.value.hashCode();
loadFactor = -loadFactor;  // Mark hashCode computation complete

return h;
}

// java.io.Serializable的写入函数
// 将Hashtable的“总的容量,实际容量,所有的Entry”都写入到输出流中
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
// Write out the length, threshold, loadfactor
s.defaultWriteObject();

// Write out length, count of elements and then the key/value objects
s.writeInt(table.length);
s.writeInt(count);
for (int index = table.length-1; index >= 0; index--) {
Entry entry = table[index];

while (entry != null) {
s.writeObject(entry.key);
s.writeObject(entry.value);
entry = entry.next;
}
}
}

// java.io.Serializable的读取函数:根据写入方式读出
// 将Hashtable的“总的容量,实际容量,所有的Entry”依次读出
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the length, threshold, and loadfactor
s.defaultReadObject();

// Read the original length of the array and number of elements
int origlength = s.readInt();
int elements = s.readInt();

// Compute new size with a bit of room 5% to grow but
// no larger than the original size.  Make the length
// odd if it's large enough, this helps distribute the entries.
// Guard against the length ending up zero, that's not valid.
int length = (int)(elements * loadFactor) + (elements / 20) + 3;
if (length > elements && (length & 1) == 0)
length--;
if (origlength > 0 && length > origlength)
length = origlength;

Entry[] table = new Entry[length];
count = 0;

// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
K key = (K)s.readObject();
V value = (V)s.readObject();
// synch could be eliminated for performance
reconstitutionPut(table, key, value);
}
this.table = table;
}

private void reconstitutionPut(Entry[] tab, K key, V value)
throws StreamCorruptedException
{
if (value == null) {
throw new java.io.StreamCorruptedException();
}
// Makes sure the key is not already in the hashtable.
// This should not happen in deserialized version.
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)) {
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
Entry<K,V> e = tab[index];
tab[index] = new Entry<K,V>(hash, key, value, e);
count++;
}

// Hashtable的Entry节点,它本质上是一个单向链表。
// 也因此,我们才能推断出Hashtable是由拉链法实现的散列表
private static class Entry<K,V> implements Map.Entry<K,V> {
// 哈希值
int hash;
K key;
V value;
// 指向的下一个Entry,即链表的下一个节点
Entry<K,V> next;

// 构造函数
protected Entry(int hash, K key, V value, Entry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}

protected Object clone() {
return new Entry<K,V>(hash, key, value,
(next==null ? null : (Entry<K,V>) next.clone()));
}

public K getKey() {
return key;
}

public V getValue() {
return value;
}

// 设置value。若value是null,则抛出异常。
public V setValue(V value) {
if (value == null)
throw new NullPointerException();

V oldValue = this.value;
this.value = value;
return oldValue;
}

// 覆盖equals()方法,判断两个Entry是否相等。
// 若两个Entry的key和value都相等,则认为它们相等。
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());
}

public String toString() {
return key.toString()+"="+value.toString();
}
}

private static final int KEYS = 0;
private static final int VALUES = 1;
private static final int ENTRIES = 2;

// Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。因为,它同时实现了 “Enumerator接口”和“Iterator接口”。
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
// 指向Hashtable的table
Entry[] table = Hashtable.this.table;
// Hashtable的总的大小
int index = table.length;
Entry<K,V> entry = null;
Entry<K,V> lastReturned = null;
int type;

// Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
// iterator为true,表示它是迭代器;否则,是枚举类。
boolean iterator;

// 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
protected int expectedModCount = modCount;

Enumerator(int type, boolean iterator) {
this.type = type;
this.iterator = iterator;
}

// 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
public boolean hasMoreElements() {
Entry<K,V> e = entry;
int i = index;
Entry[] t = table;
/* Use locals for faster loop iteration */
while (e == null && i > 0) {
e = t[--i];
}
entry = e;
index = i;
return e != null;
}

// 获取下一个元素
// 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”
// 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
// 然后,依次向后遍历单向链表Entry。
public T nextElement() {
Entry<K,V> et = entry;
int i = index;
Entry[] t = table;
/* Use locals for faster loop iteration */
while (et == null && i > 0) {
et = t[--i];
}
entry = et;
index = i;
if (et != null) {
Entry<K,V> e = lastReturned = entry;
entry = e.next;
return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
}
throw new NoSuchElementException("Hashtable Enumerator");
}

// 迭代器Iterator的判断是否存在下一个元素
// 实际上,它是调用的hasMoreElements()
public boolean hasNext() {
return hasMoreElements();
}

// 迭代器获取下一个元素
// 实际上,它是调用的nextElement()
public T next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
return nextElement();
}

// 迭代器的remove()接口。
// 首先,它在table数组中找出要删除元素所在的Entry,
// 然后,删除单向链表Entry中的元素。
public void remove() {
if (!iterator)
throw new UnsupportedOperationException();
if (lastReturned == null)
throw new IllegalStateException("Hashtable Enumerator");
if (modCount != expectedModCount)
throw new ConcurrentModificationException();

synchronized(Hashtable.this) {
Entry[] tab = Hashtable.this.table;
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;

for (Entry<K,V> e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if (e == lastReturned) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
lastReturned = null;
return;
}
}
throw new ConcurrentModificationException();
}
}
}

private static Enumeration emptyEnumerator = new EmptyEnumerator();
private static Iterator emptyIterator = new EmptyIterator();

// 空枚举类
// 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
private static class EmptyEnumerator implements Enumeration<Object> {

EmptyEnumerator() {
}

// 空枚举类的hasMoreElements() 始终返回false
public boolean hasMoreElements() {
return false;
}

// 空枚举类的nextElement() 抛出异常
public Object nextElement() {
throw new NoSuchElementException("Hashtable Enumerator");
}
}

// 空迭代器
// 当Hashtable的实际大小为0;此时,又要通过迭代器遍历Hashtable时,返回的是“空迭代器”的对象。
private static class EmptyIterator implements Iterator<Object> {

EmptyIterator() {
}

public boolean hasNext() {
return false;
}

public Object next() {
throw new NoSuchElementException("Hashtable Iterator");
}

public void remove() {
throw new IllegalStateException("Hashtable Iterator");
}

}
}


put函数:

Hashtable中不能插入value为null的元素!

若“Hashtable中已存在键为key的键值对“, 则用“新的value”替换“旧的value”;

又因为要根据key进行hash,当key为空时,进行hash时出错,所以key也不能为空;

==》Hashtable的key和value均不能为空;

遍历

1、遍历Hashtable的键值对

第一步:根据entrySet()获取Hashtable的“键值对”的Set集合。

第二步:通过Iterator迭代器遍历“第一步”得到的集合。

效率高

Iterator iter = table.entrySet().iterator();
while(iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
// 获取key
key = (String)entry.getKey();
// 获取value
integ = (Integer)entry.getValue();
}


2、通过Iterator遍历Hashtable的键

第一步:根据keySet()获取Hashtable的“键”的Set集合。

第二步:通过Iterator迭代器遍历“第一步”得到的集合。

效率低

Iterator iter = table.keySet().iterator();
while (iter.hasNext()) {
// 获取key
key = (String)iter.next();
// 根据key,获取value
integ = (Integer)table.get(key);
}


3、通过Iterator遍历Hashtable的值

第一步:根据value()获取Hashtable的“值”的集合。

第二步:通过Iterator迭代器遍历“第一步”得到的集合。

Collection c = table.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
value = (Integer)iter.next();
}


参考

http://blog.csdn.net/zheng0518/article/details/42199477#t1

Properties

Properties 继承于 Hashtable,所以键和值不能为null;

每个键及其对应值都是一个字符串;

这个类也是synchronized的;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: