【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap

参考的优秀文章:

《Java编程思想》第四版

《Effective Java》第二版

Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对。

> hashcode()和equals()

hashcode()和equals()即用于识别对象的身份。

在HashMap或类似的实现中,查找一个对象,是通过hashcode()返回的散列值映射到一个范围内的下标,在通过equals()比较此下标连接的链表是否存在相同的对象。

简单来说,hashcode()用于参考、快速定位(缩减范围),真正是否等于是依赖equals()。

默认的hashcode()和equals()

如何对象没有覆盖这两个方法,那么就是继承Object对象的。

在Object中,hashcode()是使用对象的地址计算散列值;equals()只比较对象的地址。

必要的时候,我们需要覆盖这两个方法。

覆盖这两个方法有什么原则呢?

equals()的覆盖,主要是基于此对象的业务。

而hashcode()的覆盖原则,详情可参见《Effective Java》的“覆盖equals时总要覆盖hashcode”一节。

有几个比较重要的原则:

1、两个equals相等的对象,其hashcode是相等的。

2、两个equals不等的对象,其hashcode有可能是相等的。

3、好的hashcode()应产生分布均匀的散列码。

基于第3点,《Effective Java》有具体的建议。

1、定义变量result为非零的数。

2、用公式result = 31 * result + c,其中c是类中各个域的散列值。

用Eclipse生成的hashcode()与此原则类似,我们可以看看:

public class User {

    private Integer id;
    private String name;
    private boolean flag = false;
    private long phoneNumber;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (flag ? 1231 : 1237);
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + (int) (phoneNumber ^ (phoneNumber >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (flag != other.flag)
            return false;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (phoneNumber != other.phoneNumber)
            return false;
        return true;
    }

}

> 常用的Map实现

Map接口有几个常用的实现类,HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap。其中HashMap最常用。

HashMap,基于散列表实现,查找速度快(依赖hashcode()和equals()),存放元素无序。

TreeMap,基于红黑树实现,存放有序(依赖Compareable)。

LinkedHashMap,基于散列表、双向链表实现。如HashMap的查找速度,遍历时有序(默认为插入顺序,可通过构造方法设置“最近最少使用(Least Recently Used)顺序”)。

ConcurrentHashMap,线程安全的HashMap,用于替代HashTable(线程安全,但基于整个对象的锁实现的,效率不高),而ConcurrentHashMap是采用分段加锁的方式实现,提升了效率。

代码演示LinkedHashMap的两种排序:

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapTester {

    public static void main(String[] args) {

        System.out.println("LinkedHashMap 根据插入顺序排列:");
        Map<String, String> map = new LinkedHashMap<String, String>();
        for (Integer i = 0; i < 5; i++) {
            map.put("k" + i.toString(), "v" + i.toString());
        }

        for (Integer i = 10; i > 5; i--) {
            map.put("k" + i.toString(), "v" + i.toString());
        }

        System.out.println(map);
        map.get("k10");
        System.out.println(map);

        System.out.println("LinkedHashMap 根据最近最少使用(Least Recently Used)顺序排列:");
        map = new LinkedHashMap<String, String>(16, 0.75f, true); // 没有了其他构造方法设置其排序为true了。初始容量、加载因子使用默认的16和0.75。
        for (Integer i = 0; i < 5; i++) {
            map.put("k" + i.toString(), "v" + i.toString());
        }

        for (Integer i = 10; i > 5; i--) {
            map.put("k" + i.toString(), "v" + i.toString());
        }

        System.out.println(map);
        map.get("k10");
        System.out.println(map);
    }

}

日志,注意看使用“K10”后“K10”的位置:

LinkedHashMap 根据插入顺序排列:
{k0=v0, k1=v1, k2=v2, k3=v3, k4=v4, k10=v10, k9=v9, k8=v8, k7=v7, k6=v6}
{k0=v0, k1=v1, k2=v2, k3=v3, k4=v4, k10=v10, k9=v9, k8=v8, k7=v7, k6=v6}
LinkedHashMap 根据最近最少使用(Least Recently Used)顺序排列:
{k0=v0, k1=v1, k2=v2, k3=v3, k4=v4, k10=v10, k9=v9, k8=v8, k7=v7, k6=v6}
{k0=v0, k1=v1, k2=v2, k3=v3, k4=v4, k9=v9, k8=v8, k7=v7, k6=v6, k10=v10}

时间: 2024-09-29 05:00:00

【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap的相关文章

HashMap TreeMap LinkedHashMap

HashMap 键是Student值 是String 的案例 键是Student, 如果不重写,则键肯定不一致, 所以需要重写键对象的hashcode() equals() LinkedHashMap 底层是链表,怎么存怎么取 TreeMap 键如果是自定义对象,则该对象必须有比较的功能 public class demon7_hashmapHashMap { /* * 嵌套HashMap * 键是学生 值是学生归属地 * 有多个班级 键是班级 值是班级号 */ public static vo

黑马程序员——java——Map集合的子类HashMap的简单操作方法

Map集合的子类HashMap的简单操作方法 import java.util.HashMap; import java.util.Iterator; public class HashMapDemos { public static void%r0main(String[] args) { // HashMap<Studenti,String> hm = new HashMap<Studenti,String>(); hm.put(new Studenti("kk&qu

HashTable HashMap TreeMap LinkedHashMap 区别

参考:http://blog.csdn.net/xiaodifa995455120/article/details/7277441 http://www.apkbus.com/forum.php?mod=viewthread&tid=52426 Hashmap 是一个 最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度.HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个

java:Map借口及其子类HashMap五,identityHashMap子类

了解:identityHashMap子类 一般情况下,标准的Map,是不会有重复的key值得value的,相同的key是被覆盖的.HashMap IdentityHashMap是个例外,他允许Key值重复,只有当两个对象用"=="来判断时,才能判断他相等. Map<String, Integer> map = new IdentityHashMap<String,Integer>(); map.put(new String("zhangsan"

java map 遍历

版权声明:本文为博主原创文章,未经博主允许不得转载. 在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都实现了Map接口,以下方法适用于任何map实现(HashMap, TreeMap, LinkedHashMap, Hashtable, 等等) 方法一 在for-each循环中使用entries来遍历 这是最常见的并且在大多数情况下也是最可取的遍

Java集合详解6:TreeMap和红黑树

Java集合详解6:TreeMap和红黑树 初识TreeMap 之前的文章讲解了两种Map,分别是HashMap与LinkedHashMap,它们保证了以O(1)的时间复杂度进行增.删.改.查,从存储角度考虑,这两种数据结构是非常优秀的.另外,LinkedHashMap还额外地保证了Map的遍历顺序可以与put顺序一致,解决了HashMap本身无序的问题. 尽管如此,HashMap与LinkedHashMap还是有自己的局限性----它们不具备统计性能,或者说它们的统计性能时间复杂度并不是很好才

[Java] 多个Map的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)

比较Java原生的 3种Map的效率. 1.  TreeMap 2.  HashMap 3.  ConcurrentSkipListMap 结果: 模拟150W以内海量数据的插入和查找,通过增加和查找两方面的性能测试,结果如下: Map类型 插入 查找(在100W数据量中)   10W 50W 100W 150W 0-1W 0-25W 0-50W Concurrent SkipListMap 62 ms 227 ms 433 ms 689ms 7 ms 80 ms 119 ms HashMap

【JAVA】六 JAVA Map 一 HashMap

[JAVA]六 JAVA Map 一 HashMap JDK API java.util Interface Map Type Parameters: K - the type of keys maintained by this map V - the type of mapped values All Known Subinterfaces: Bindings, ConcurrentMap<K,V>, ConcurrentNavigableMap<K,V>, LogicalMe

深入理解 hash 函数、HashMap、LinkedHashMap、TreeMap 【上】

前言 Map 是非常常用的一种数据接口.在 Java 中,提供了成熟的 Map 实现. 图 1 最主要的实现类有 Hashtable.HashMap.LinkedHashMap和 TreeMap.在 HashTable 的子类中,还有 Properties的实现.Properties 是专门读取配置文件的类,我们会在稍后介绍.这里首先值得关注的是 HashMap 和 HashTable 两套不同的实现,两者都实现了 Map 接口.从表面上看,并没有多大差别,但是在内部实现上却有些微小的细节. 首