`
tangyanbo
  • 浏览: 268724 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

跟我一起阅读Java源代码之HashMap(三)

 
阅读更多

上一节我们讲到了如何用散列和链表实现HashMap,其中有一个疑问今天已经有些答案了,为什么要用链表而不是数组

链表的作用有如下两点好处

1. remove操作时效率高,只维护指针的变化即可,无需进行移位操作

2. 重新散列时,原来散落在同一个槽中的元素可能会被散落在不同的地方,对于数组需要进行移位操作,而链表只需维护指针

 

今天研究下数组长度不够时的处理办法

table为散列数组

1. 首先定义一个不可修改的静态变量存储table的初始大小 DEFAULT_INITIAL_CAPACITY

2. 定义一个全局变量存储table的实际元素长度,size

3. 定义一个全局变量存储临界点,即元素的size>=threshold这个临界点时,扩大table的容量

4. 因为index是根据hash和table的长度计算得到的,所以还需要重新对所有元素进行散列

 

实现如下:

package sourcecoderead.collection.map;


public class EntryHashMap<K, V> {

	/** 初始容量 */
	static final int DEFAULT_INITIAL_CAPACITY = 16;

	static final float DEFAULT_LOAD_FACTOR = 0.75f;

	/** 下次扩容的临界值 */
	int threshold;

	transient int size;

	final float loadFactor;

	transient Entry[] table;

	public EntryHashMap() {
		this.loadFactor = DEFAULT_LOAD_FACTOR;
		threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
		table = new Entry[DEFAULT_INITIAL_CAPACITY];
	}

	public V put(K key, V value) {
		// 计算出新的hash
		int hash = hash(key.hashCode());
		// 计算出数组小标i
		int i = indexFor(hash, table.length);
		// 遍历table[i],如果table[i]没有与新加入的key相等的,则新加入
		// 一个value到table[i]中的entry,否则将新的value覆盖旧的value并返回旧的value
		for (Entry<K, V> e = table[i]; e != null; e = e.next) {
			Object k;
			if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
				V oldValue = e.value;
				e.value = value;
				return oldValue;
			}
		}
		addEntry(hash, key, value, i);
		return null;
	}

	public V get(K key) {
		// 计算出新的hash
		int hash = hash(key.hashCode());
		// 计算出数组小标i
		int i = indexFor(hash, table.length);
		for (Entry<K, V> e = table[i]; e != null; e = e.next) {
			Object k;
			if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
				return e.value;
			}
		}
		return null;
	}

	private void addEntry(int hash, K key, V value, int bucketIndex) {
		Entry<K, V> e = table[bucketIndex];
		// 将新的元素插入链表前端
		table[bucketIndex] = new Entry<>(hash, key, value, e);
		if (size++ >= threshold)
			resize(2 * table.length);
	}

	void resize(int newCapacity) {
		Entry[] oldTable = table;
		int oldCapacity = oldTable.length;
		Entry[] newTable = new Entry[newCapacity];
		transfer(newTable);
		table = newTable;
		threshold = (int) (newCapacity * loadFactor);
	}

	void transfer(Entry[] newTable) {
		Entry[] src = table;
		int newCapacity = newTable.length;
		for (int j = 0; j < src.length; j++) {
			Entry<K, V> e = src[j];
			if (e != null) {
				src[j] = null;
				do {
					Entry<K, V> next = e.next;
					int i = indexFor(e.hash, newCapacity);
					e.next = newTable[i];
					newTable[i] = e;
					e = next;
				} while (e != null);
			}
		}
	}

	/**
	 * 通过hash code 和table的length得到对应的数组下标
	 * 
	 * @param h
	 * @param length
	 * @return
	 */
	static int indexFor(int h, int length) {
		return h & (length - 1);
	}

	/**
	 * 通过一定算法计算出新的hash值
	 * 
	 * @param h
	 * @return
	 */
	static int hash(int h) {
		h ^= (h >>> 20) ^ (h >>> 12);
		return h ^ (h >>> 7) ^ (h >>> 4);
	}

	public static void main(String[] args) {
		EntryHashMap<String, String> hashMap = new EntryHashMap<String, String>();
		hashMap.put("key", "value");
		System.out.println(hashMap.get("key"));
	}
}
 
分享到:
评论

相关推荐

    java源代码,java源代码

    Java源代码是编程世界的基石,它是Java程序员用Java语言编写的程序文本,包含了类、方法、变量等元素,是理解程序逻辑和功能的核心。在Java编程中,源代码通常以`.java`为扩展名,经过Java编译器的处理,会被转化为...

    java代码-使用java解决手写hashMap的源代码

    java代码-使用java解决手写hashMap的源代码 ——学习参考资料:仅用于个人学习使用!

    164个完整的Java程序源代码

    4. **集合框架**:Java集合框架包括ArrayList、LinkedList、HashSet、HashMap等,它们在源代码中会被广泛应用,用于数据的存储和操作。 5. **输入/输出流**:Java的I/O流系统广泛用于文件读写、网络通信等场景,源...

    Java源码:比较经典的一些Java源代码,适合于初学者

    这个压缩包包含了140个经典的Java源代码程序,涵盖了各种基础到进阶的编程概念。下面,我们将详细讨论这些知识点。 1. **基础语法**:作为初学者,首先需要掌握Java的基础语法,包括变量声明、数据类型(如int、...

    java简单实例程序源代码

    "java简单实例程序源代码"这个压缩包包含了一系列章节相关的Java实例源代码,适合初学者和有经验的开发者用来加深对Java语言的理解。以下是这些章节可能涉及的重要知识点的详细解释: 1. **CH11**: 这个章节可能...

    250个java源代码

    "250个Java源代码"这个压缩包很显然是为了帮助初学者和希望提升Java技能的开发者提供实践素材。这些源代码实例涵盖了Java的基础概念到进阶特性,是学习和理解Java语法、编程技巧以及解决问题的有效工具。 首先,...

    Java全部源代码

    Java源代码包含了JDK(Java Development Kit)的所有组件,包括核心类库如java.lang、java.util、java.io等,这些类库构成了Java平台的基础。通过阅读源代码,我们可以了解到Java的API是如何实现的,比如对象的创建...

    java8源代码内容

    通过阅读源代码,开发者可以深入了解内部的工作原理,提升编程技能,并能够更好地利用Java 8的功能来解决实际问题。与Eclipse等IDE配合使用,可以方便地查看和调试源代码,进一步提高开发效率。

    JAVA 经典源代码

    在IT领域,尤其是Java编程语言的学习与开发过程中,掌握经典源代码是提升技能的重要途径。"JAVA 经典源代码"这个主题包含了丰富的知识内容,它涵盖了基础语法、设计模式、数据结构、算法等多个方面。这里我们将深入...

    java实用代码源代码

    在描述中提到的".java"文件是Java源代码文件,它是编写Java程序的基本单元。每个.java文件通常包含一个或多个类定义,编译后会生成对应的字节码文件(.class),由Java虚拟机执行。".java"文件的实用性质意味着它们...

    Java程序设计语言源代码

    Java源代码涉及到的基础知识包括变量、数据类型、运算符、流程控制(如if语句、for循环、while循环)、方法定义和调用。在applet相关的源代码中,可以学习到如何在Web环境中运行Java小程序,包括Applet类、初始化和...

    java api源代码

    Java API源代码是Java开发中的核心组成部分,它包含了Java标准库中的所有类和接口,这些类和接口构成了Java平台的基础。Sun Microsystems(后被Oracle收购)是Java的原始开发者,他们发布的源代码对于深入理解Java的...

    Java核心源代码

    Java核心源代码是Java编程语言的核心组成部分,它包括了大量的类库和API,这些构成了Java开发的基础框架。在Java中,"以java开头的包"通常指的是Java标准库,这是一个庞大的集合,涵盖了各种功能,从基本的数据类型...

    Java面向对象程序设计课本例题源代码

    这份压缩包包含了书中各个章节的例题源代码,是学习和理解Java面向对象编程概念的宝贵资源。下面我们将详细探讨这些源代码所涵盖的知识点,并结合Java的核心特性进行解析。 1. **类与对象**:在Java中,一切皆为...

    java源代码原理视频.txt

    java源代码原理,深入理解HashMap原理、高可用redis集群架构、zookeeper分布式、海量数据缓存、springAOP底层源码分析等

    Java自学程序源代码

    3. **异常处理**:Java的异常处理机制是其强大之处,源代码中可能会包含try-catch-finally块,学习者可以从中学习如何处理运行时可能出现的错误。 4. **集合框架**:Java集合框架包括ArrayList, LinkedList, ...

    Java HashMap类详解

    HashMap 的存储实现可以通过查看其 put(K key, V value) 方法的源代码来了解。该方法首先判断 key 是否为 null,然后根据 key 的 hashCode 值计算 Hash 值,接着搜索指定 hash 值在对应 table 中的索引,如果 i 索引...

    57个java源代码(自学java)

    这份“57个java源代码(自学java)”的资源对于初学者来说是一份宝贵的材料,它可以帮助你逐步理解并掌握Java编程的基础知识。下面将详细解释这份资料中可能涉及的关键知识点: 1. **基础语法**:在学习Java时,首先...

    三级联动java源代码

    在这个“三级联动java源代码”中,我们可以期待看到如何通过Java代码实现上述的各种技术。文件名“三级联动.txt”可能包含了源代码的注释或实现思路,对于理解代码的工作原理非常有帮助。通过阅读和分析这份源代码,...

    java大全书上源代码2

    通过阅读和实践这些源代码,你可以深入学习Java的各种特性,包括但不限于: 1. 类和对象:Java是面向对象的语言,源代码会展示如何定义类,创建对象,以及如何利用继承、封装和多态等面向对象原则来设计软件。 2. ...

Global site tag (gtag.js) - Google Analytics