返回Java 集合......登陆

Java 集合系列11之 Hashtable详细介绍

阿神2016-11-08 13:57:35454

概要

前一章,我们学习了HashMap。这一章,我们对Hashtable进行学习。

我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable。

第1部分 Hashtable介绍

第2部分 Hashtable数据结构

第3部分 Hashtable源码解析(基于JDK1.6.0_45)

第4部分 Hashtable遍历方式

第5部分 Hashtable示例

第1部分 Hashtable介绍

Hashtable 简介

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

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

Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

Hashtable 的实例有两个参数影响其性能:初始容量 和 加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。

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

Hashtable的构造函数

1

2

3

4

5

6

7

8

// 默认构造函数。

public Hashtable() 

// 指定“容量大小”的构造函数

public Hashtable(int initialCapacity) 

// 指定“容量大小”和“加载因子”的构造函数

public Hashtable(int initialCapacity, float loadFactor) 

// 包含“子Map”的构造函数

public Hashtable(Map<? extends K, ? extends V> t)

Hashtable的API

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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()

第2部分 Hashtable数据结构

Hashtable的继承关系

1

2

3

4

5

java.lang.Object

      java.util.Dictionary<K, V>

              java.util.Hashtable<K, V>

public class Hashtable<K,V> extends Dictionary<K,V>

    implements Map<K,V>, Cloneable, java.io.Serializable { }

 Hashtable与Map关系如下图:

10.jpg

从图中可以看出: 

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

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

  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。 

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

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

  loadFactor就是加载因子。 

  modCount是用来实现fail-fast机制

第3部分 Hashtable源码解析(基于JDK1.6.0_45)

为了更了解Hashtable的原理,下面对Hashtable源码代码作出分析。

在阅读源码时,建议参考后面的说明来建立对Hashtable的整体认识,这样更容易理解Hashtable。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

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.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;

      &am<div class="tags bg-white layui-clear pt-20"></div>

最新手记推荐

• 用composer安装thinkphp框架的步骤• 省市区接口说明• 用thinkphp,后台新增栏目• 管理员添加编辑删除• 管理员添加编辑删除

全部回复(0)我要回复

暂无评论~
  • 取消回复发送