HashMap快速的原因

使用自定义的类作为HashMap的键,必须重载hashCode()equals()方法,因为这两个方法都是继承自Object类,默认是基于对象地址计算hashCode()equals()方法。

hashCode()并不需要总是返回唯一的标识码。

HashMap或者HashSet快的原因:

其他查询慢的原因是对于键或者值查询上,因为键或者只没有按特定顺序保存,所以只能采用简单的线性查询,而线性查询是最慢的查询方式。

散列的价值在于速度。由于瓶颈位于键或值的查询速度,因此解决方案之一就是保持键或值的排序状态,然后使用Collections.binarySearch()进行查询。

散列则更进一步,它将键保存在某处,以便能够快速找到。存储一组元素最快的数据结构是数组,所以使用它来表示键的信息,但是数组是固定大小的,我们需要能够保存可变大小的数据。因此数组必须不保存键本身,而是通过键生成一个数字作为数组的下标,这个数字就是散列码,由定义在Object中的、或者是自定义的类覆盖的hashCode()方法生成。

为解决数组容量被固定的问题,不同的键可以生成相同的下标,也就可能产生冲突。因此数组多大就不重要了,任何键在数组中总能找到自己的位置。

于是查询一个值的过程首先就是计算散列码,然后使用散列码查询数组。如果能够保证数组下标没有冲突,那就有了一个完美的散列函数,但这种情况是特例。通常,冲突由外部链接处理:数组并不直接保存只,而是保存值的list,然后对list中的值使用equals()方法进行线性的查询,这也就是为什么HashSetHashMap存放自定义类需要重写hashCode()equals()方法的原因。这部分的查询自然会比较慢,但是,如果散列函数好的话,数组的每个位置就会有较少的值。这样就不是查询整个list,而是快速跳转到数组的某个位置,只对较少的元素进行比较。这便是HashMap如此快的原因。

下面实现一个简单的散列Map

import java.util.Map;

public class MapEntry<K,V> implements Map.Entry<K, V>
{
    private K key;
    private V value;
    public MapEntry(K key,V value)
    {
        this.key=key;
        this.value=value;
    }
    public K getKey(){
        return key;
    }
    public V getValue(){
        return value;
    }
    public V setValue(V v){
        V result=value;
        value=v;
        return result;
    }
    public int hashCode(){
        return (key==null?0:key.hashCode())^(value==null?0:value.hashCode());
    }
    public boolean equals(Object o){
        if (!(o instanceof MapEntry))
        {
            return false;
        }
        MapEntry map=(MapEntry)o;
        return (key==null?map.getKey()==null:key.equals(map.getKey()))
            &&(value==null?map.getValue()==null:value.equals(map.getValue()));
    }
    @Override
    public String toString()
    {
        return key+"="+value;
    }
    
}
import java.util.*;

public class SimpleHashMap<K,V> extends AbstractMap<K, V>
{
    static final int SIZE=997;
    LinkedList<MapEntry<K,V>>[] buckets=new LinkedList[SIZE];
    public V put(K key,V value){
        V oldValue=null;
        int index=Math.abs(key.hashCode())%SIZE;
        if (buckets[index]==null)
        {
            buckets[index]=new LinkedList<MapEntry<K, V>>();
        }
        LinkedList<MapEntry<K, V>> bucket=buckets[index];
        MapEntry<K, V> pair=new MapEntry<K, V>(key, value);
        boolean found=false;
        ListIterator<MapEntry<K, V>> it=bucket.listIterator();
        while (it.hasNext())
        {
            MapEntry<K, V> iPair=it.next();
            if (iPair.getKey().equals(key))
            {
                oldValue=iPair.getValue();
                it.set(pair);
                found=true;
                break;
            }
        }
        if(!found){
            buckets[index].add(pair);
        }
        return oldValue;
    }
    public Set<Map.Entry<K, V>> entrySet(){
        Set<Map.Entry<K, V>> set=new HashSet<Map.Entry<K,V>>();
        for (LinkedList<MapEntry<K, V>> bucket:buckets)
        {
            if(bucket==null) continue;
            for(MapEntry<K, V> mpair:bucket)
                set.add(mpair);
        }
        return set;
    }
    public static void main(String[] args)
    {
        SimpleHashMap<String, String> m=new SimpleHashMap<String,String>();
        m.put("吉林", "长春");
        m.put("山西", "太原");
        m.put("湖北", "武汉");
        m.put("江苏", "南京");
        m.put("浙江", "杭州");
        m.put("四川", "成都");
        System.out.println(m);
        System.out.println(m.get("浙江"));
        System.out.println(m.entrySet());
    }
}
执行结果如下:

{江苏=南京,山西=太原, 湖北=武汉, 吉林=长春, 四川=成都, 浙江=杭州}

杭州

[江苏=南京, 山西=太原, 湖北=武汉, 吉林=长春, 四川=成都, 浙江=杭州]

以上内容摘自《Think In Java Edition4

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的HashMap是一种常用的集合类,用于存储键值对。它继承自AbstractMap类,并且实现了Map接口。与HashTable相比,HashMap具有更好的性能和扩展性。[1] HashMap的底层原理是使用哈希表来实现的,它通过将键映射到存储桶中来存储和获取值。HashMap使用键的hashCode()方法来计算哈希码,然后根据哈希码将键值对存储在相应的存储桶中。在存储和获取值时,HashMap会根据键的哈希码进行快速查找,从而实现了O(1)的平均时间复杂度。 在HashMap中,键和值都允许为null,但是只能有一个为null的键。如果多个键映射到同一个存储桶,HashMap会使用链表或红黑树来解决冲突。当链表长度超过一定阈值时,链表会被转换为红黑树,以提高查找效率。 除了HashMap,还有其他一些相关的类可以用来实现线程安全的HashMap,例如Collections.synchronizedMap()方法可以将HashMap转换为同步的Map。这样可以在多线程环境中安全地使用HashMap。不过,由于性能的原因,这种方式不常用。 总结来说,JavaHashMap是一种常用的集合类,使用哈希表来存储键值对。它具有良好的性能和扩展性,允许键和值为null。在多线程环境中可以使用同步的Map来实现线程安全。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java集合 —— HashMap原理解析](https://blog.csdn.net/m0_56602092/article/details/130338081)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [【javaHashMap底层实现原理及面试题](https://blog.csdn.net/twotwo22222/article/details/128426417)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值