Java中的hashmap

简介: 笔记

一、数据结构之哈希表

所谓哈希表,是一种数据的存储结构,我们可以通过数据的“关键码值”来直接访问表。通过散列的方法(可以理解为一种特殊的数学过程=_=),我们可以把关键码值映射到数组中的不同位置。
设计散列系统的目标是对于任一个关键码值Key,都能通过某散列函数的计算来得到一个数组中的存储下标,使得该位置存储值Value。这样一来就很可能出现不同的关键码值对应同一个数组下标的情况,因此设计冲突解决策略也是必须的。
一种很容易想到的解决冲突的策略是,每当要存储一个关键值为Key的数据时,首先判断计算出的存储下标处是否已经存储了一个数据,如果是则将下标值进行“+1”操作,继续判断,直到判断为否时存入数据。
根据以上原理我们可以设计一个简单的程序来模拟哈希表的实现(这里假设Key和Value的数据类型都是int)
public class HashDemo {
    static int size = 1000;
    static int[] hash = new int[size];
    int currsize = 0;
    int Key, Value;
    static {
        for (int i = 0; i < size; i++) {
            hash[i] = -1;
        }
    }
    // 构造方法
    public HashDemo(int Key, int Value) {
        this.Key = Key;
        this.Value = Value;
    }
    public HashDemo() {}
    // 计算hashcode
    public int hashcode(int Key) {
        int index = Key % size;
        if (currsize == size) {
            return -1;
        } else {
            while (index >= 0 && index < size && hash[index] != -1) {
                index++;
                if (index == size - 1) {
                    index++;
                }
            }
            return index;
        }
    }
    // 往HashDemo中插入测试数据
    public boolean put(int Key, int Value) {
        int index = hashcode(Key);
        if (index == -1 || index < 0 || index >= size)
            return false;
        else {
            hash[index] = Value;
            return true;
        }
    }
    public void Tester() {
        HashDemo hd = new HashDemo();
        long starttime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            hd.put(i * i, i * i);
        }
        long endtime = System.currentTimeMillis();
        System.out.println("100000次put所用时间:" + (endtime - starttime) + "ms");
            }
}

90.png


二、java中hashmap的具体实现

import java.util.HashMap;
public class HashTest {
    public void Tester(){
        HashMap<Integer,Integer> hm=new HashMap<Integer,Integer>();
        long starttime=System.currentTimeMillis();
        for(int i=0;i<1000000;i++){
            Integer n=new Integer(i);
            hm.put(n*n,n*n );
        }
        long endtime=System.currentTimeMillis();
        System.out.println("100000次put所用时间:"+(endtime-starttime)+"ms");
        starttime=System.currentTimeMillis();
        for(int i=0;i<1000000;i++){
            Integer n=new Integer(i);
            Integer m=hm.get(n*n);
        }
        endtime=System.currentTimeMillis();
        System.out.println("100000次get所用时间:"+(endtime-starttime)+"ms");
        starttime=System.currentTimeMillis();
        for(int i=0;i<1000000;i++){
            Integer n=new Integer(i);
            hm.remove(n*n);
        }
        endtime=System.currentTimeMillis();
        System.out.println("100000次remove所用时间:"+(endtime-starttime)+"ms");
    }

91.png


可以看到使用java中自带的hashmap类执行put操作时,和上述思路所花费的时间有较大的出入,并且可以发现多次put和get操作所花费的时间也有较大的差别。
通过查看源代码其实不难发现,java中的哈希表中每一个位置不会只存储一个元素,如果有多个Key值计算出来的hashcode结果是相同的,则这几个元素并不会移动存储的位置,也就是说,hashcode一旦被计算出来,就不会在改变。
那么多个数据是怎么存储在数组的一个位置上呢,其实很简单,我们可以联想数据结构中的“图”,其中有一种表示方法叫做临接表表示法,将存储在同一位置的数据用链表的形式连接起来来进行存储,其实HashMap有一个叫做Entry的内部类,它用来存储key-value对。
```

92.png

由于put时每一次都要实例化Entry内部类的对象,所以put方法要使用比get方法更久的时间。


三、hashcode的计算方法


由于java中有许多的数据类型,而且有时传入的Key是一个类的对象。所以hashcode的计算并不是那么容易。在设计一个类的时候,很可能要重写类的hashCode()方法,根据哈希表的特点,重写的hashCode()方法需要遵守以下准则:

           ①同一个对象调用hashCode()时,应返回相同的值

           ②若两个对象通过equals()方法比较返回true的时候,两个对象的hashCode()方法应返回相同的值

           ③对象调用equals()方法参与比较的值,都应该拿来计算hashCode()


对象中不同的值对应不同的计算方法:

93.png


将所有的数据计算出来的hashCode相加即为该对象的hashCode();为了避免重复,可以让各个数据乘以不同的权值后再相加。



相关文章
|
16天前
|
存储 Java
Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
28 1
|
18天前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
45 2
|
18天前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
49 2
|
18天前
|
存储 缓存 安全
HashMap VS TreeMap:谁才是Java Map界的王者?
HashMap VS TreeMap:谁才是Java Map界的王者?
56 2
|
1天前
|
Java
Java之HashMap详解
本文介绍了Java中HashMap的源码实现(基于JDK 1.8)。HashMap是基于哈希表的Map接口实现,允许空值和空键,不同步且线程不安全。文章详细解析了HashMap的数据结构、主要方法(如初始化、put、get、resize等)的实现,以及树化和反树化的机制。此外,还对比了JDK 7和JDK 8中HashMap的主要差异,并提供了使用HashMap时的一些注意事项。
Java之HashMap详解
|
15天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
38 5
|
1月前
|
Java
用java搞定时任务,将hashmap里面的值存到文件里面去
本文介绍了如何使用Java的`Timer`和`TimerTask`类创建一个定时任务,将HashMap中的键值对写入到文本文件中,并提供了完整的示例代码。
34 1
用java搞定时任务,将hashmap里面的值存到文件里面去
|
16天前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
35 3
|
16天前
|
存储 缓存 安全
在Java的Map家族中,HashMap和TreeMap各具特色
【10月更文挑战第19天】在Java的Map家族中,HashMap和TreeMap各具特色。HashMap基于哈希表实现,提供O(1)时间复杂度的高效操作,适合性能要求高的场景;TreeMap基于红黑树,提供O(log n)时间复杂度的有序操作,适合需要排序和范围查询的场景。两者在不同需求下各有优势,选择时需根据具体应用场景权衡。
22 2
|
16天前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
23 2