【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}
【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap的更多相关文章
- java:Map借口及其子类HashMap四
java:Map借口及其子类HashMap四 使用非系统对象作为key,使用匿名对象获取数据 在Map中可以使用匿名对象找到一个key对应的value. person: public class Ha ...
- java:Map借口及其子类HashMap五,identityHashMap子类
java:Map借口及其子类HashMap五,identityHashMap子类 了解:identityHashMap子类 一般情况下,标准的Map,是不会有重复的key值得value的,相同的key ...
- java:Map借口及其子类HashMap二
java:Map借口及其子类HashMap二 重点:所有的集合必须依赖Iterator输出 Map<String, Integer> map = new HashMap<String ...
- 【Java入门提高篇】Day28 Java容器类详解(十)LinkedHashMap详解
今天来介绍一下容器类中的另一个哈希表———>LinkedHashMap.这是HashMap的关门弟子,直接继承了HashMap的衣钵,所以拥有HashMap的全部特性,并青出于蓝而胜于蓝,有着一 ...
- Java集合详解6:TreeMap和红黑树
Java集合详解6:TreeMap和红黑树 初识TreeMap 之前的文章讲解了两种Map,分别是HashMap与LinkedHashMap,它们保证了以O(1)的时间复杂度进行增.删.改.查,从存储 ...
- Java 数据类型:集合接口Map:HashTable;HashMap;IdentityHashMap;LinkedHashMap;Properties类读取配置文件;SortedMap接口和TreeMap实现类:【线程安全的ConcurrentHashMap】
Map集合java.util.Map Map用于保存具有映射关系的数据,因此Map集合里保存着两个值,一个是用于保存Map里的key,另外一组值用于保存Map里的value.key和value都可以是 ...
- 接口java.util.Map的四个实现类HashMap Hashtable LinkedHashMap TreeMap
java中HashMap,LinkedHashMap,TreeMap,HashTable的区别 :java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMa ...
- Map,Hashmap,LinkedHashMap,Hashtable,TreeMap
java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap. Map主要用于存储健值对, ...
- JAVA基础学习-集合三-Map、HashMap,TreeMap与常用API
森林森 一份耕耘,一份收获 博客园 首页 新随笔 联系 管理 订阅 随笔- 397 文章- 0 评论- 78 JAVA基础学习day16--集合三-Map.HashMap,TreeMap与常用A ...
随机推荐
- 开源日志技术log4j
老师的总结: 日志:除了能记录异常信息,还可以记录程序正常运行时的关键信息. 使用log4j来进行日志文件记录经典步骤: 001.在项目中创建一个lib文件夹,然后将下载好的jar包copy到该文件夹 ...
- hdu5314 Happy King
树分治. 代码 #pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #incl ...
- paper 35 :交叉验证(CrossValidation)方法思想
交叉验证(CrossValidation)方法思想简介 以下简称交叉验证(Cross Validation)为CV.CV是用来验证分类器的性能一种统计分析方法,基本思想是把在某种意义下将原始数据(da ...
- cocos2dx建立项目
http://www.cocos.com/doc/article/index?type=wiki&url=/doc/cocos-docs-master/manual/framework/nat ...
- 去掉list重复值
/** * 去掉list重复值 */ public List<String> removeDuplicate(List<String> list) { HashSet<S ...
- yii2添加自定义字段
在模型model文件中,添加 public $attributes;即可,$attributes 为要添加的新字段
- Delphi 的各版本定义,用于预编译参数中,避免忘记备忘之
DELPHI的版本宏: VER80 - Delphi 1 VER90 - Delphi 2 VER100 - Delphi 3 VER120 - Delphi 4 VER130 - Delphi 5 ...
- V4L2驱动程序框架架构【转】
本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11728809 1 V4L2简介 video4linux2(V4L2)是Linux内核中关 ...
- 用grunt搭建自动化的web前端开发环境实战教程(详细步骤)
用grunt搭建自动化的web前端开发环境实战教程(详细步骤) jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用!前端自动化, ...
- React笔记_(4)_react语法3
生命周期 很多语言中都讲了关于生命周期.这可是决定生命的周始,有没有存在感的关键啊. 生命周期,有生有死,有始有终,因果轮回,循环往复.(说多了) react中,主要说明的是 一个组件的生命周期.简单 ...