HashMap快速的缘由

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

hashCode()并不须要老是返回惟一的标识码。数组

HashMap或者HashSet快的缘由:数据结构

其余查询慢的缘由是对于键或者值查询上,由于键或者只没有按特定顺序保存,因此只能采用简单的线性查询,而线性查询是最慢的查询方式。ide

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

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

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

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

下面实现一个简单的散列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
排序