Java中的HashMap浅析

发表于:2014-7-21 09:35

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:神一样的存在    来源:51Testing软件测试网采编

    在Java的集合框架中,HashSet,HashMap是用的比较多的一种,顺序结构的ArrayList、LinkedList这种也比较多,而像那几个线程同步的容器就用的比较少,像Vector和HashTable,因为这两个线程同步的容器已经不被JDK推荐使用了,这是个比较老式的线程安全的容器,JDK比较推荐的是采用Collections里面的关于线程同步的方法。
    问题来源:
    1.为什么要有HashMap?
    《Thinking In Java》里面有一个自己采用二维数组实现的保存key-value的demo,书上也说到性能问题,因为从数据结构的顺序结构的观点来看,常规的线性存储,你弱需要找到其中的某个元素,就需要遍历这个链表或者数组,而遍历的同时需要让链表中的每一个元素都和目标元素做比较,相等才返回,Java里面用equals或者==。这对性能是毁灭性的伤害。
    2.HashMap的优势是什么?
    Hash算法就是根据某个算法将一系列目标对象转换成地址,当要获取某个元素的时候,只需要将目标对象做相应的运算获得地址,直接获取。
    3.Java中的Hash?
    事实上Java的数据无非就三种,基本类型,引用类型(类似C里面的指针类型)和数组,有些地方说是2种类型,只有引用类型和数组。通过这三种数据类型可以构建出任何数据结构。在Java中,ArrayList这种底层就是用Objec数组来构建的,而HashMap也是用数组来构建,只不过数据数组的数据类型是一个叫做Entry的内部类来保存key、value、hash(不是hashCode)和next(也就是链表的下一个元素)。其实HashSet也是HashMap,只不过比较特殊,没有使用Entry的value而只用了key而已。看看HashSet的构造方法:
    public HashSet() {
    map = new HashMap<E,Object>();
    }
    所以从这个意义上来讲就没必要讨论HashSet了,他只不过是特殊的HashMap而已。
    HashMap详解:
    基调:由于通过hash算法产生的逻辑地址可能导致冲突,所以对于一个长度为length的数组,里面存放小于length个数据元素的时候就有可能出现冲突的现象,因为比如说要在长度为16的数组中存放字符串(也就是一个空的HashMap默认的长度),每个字符串通过调用自身的hashCode()方法会得到该字符串的hashCode,然后通过HashMap的这两个方法会算出在数组中的位置,也就是下面的 i。
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    任意字符串的hashCode通过上面2个方法都会得到一个i,这个i就是在数组中的位置,这里比较巧妙的设计就是indexFor(hash,table.length)这个方法:
    static int indexFor(int h, int length) {
    return h & (length-1);
    }
    这个方法里面的任意h与(length-1)做位运算之后得到的值始终都是在length之内的,也就是在数组table之内,因为拿任意一个数来和另一个数来做与运算,结果肯定是小于等于较小的哪一个数,我以前第一次看到这就比较震惊,为什么那些人能想出这么巧妙的计算在table中的位置的方法。与此同时,既然字符串调用hashCode()会得到一个值,那么就会出现不相同的字符串调用hashCode方法之后得到的值是一样的,这种可能性是存在的,而且几乎肯定是存在的。这时候就需要在数组的某个位置增加一个链表结构,用户存储相同的hashCode的字符串,而这个时候HashMap的size同样也会自增1,尽管这2个字符串只有一个存在于数组中。HashMap中的size变量有两个作用,第一是通过调用size()方法来返回map的长度,
    public int size() {
    return size;
    }
    第二个作用相当重要,就是解决hash算法的核心力量,解决冲突。在HashMap的构造方法中可以看出,hashmap的长度和底层数组table都是capacity,但是还有一个变量叫做threshold,极限值,阈值的意思,默认情况的构造方法:
    public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    table = new Entry[DEFAULT_INITIAL_CAPACITY];
    init();
    }
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号