程序猿的日常——Java基础之equals与hashCode
equals和hashCode是我们日常开发最常使用的方法,但是因为一般都使用默认的规则,因此也很少会引起关注。不过了解他们的用途和设计的原则,还是会帮助我们更好的设计代码。
equals
equals是java很基础的一个问题,通常都会跟==来做比较。那么看看下面的问题:
int a = 1;
int b = 1;
System.out.println(a==b);//true
Integer a1 = new Integer(1);
Integer a2 = new Integer(1);
System.out.println(a1==a2);//false
System.out.println(a1.equals(a2));//true
这是因为,==比较的是引用,而equals比较的内容,进入到Integer的源码中,就可以看到它其实重写了equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
说到equals,就不得不说如果我们想要自己重写equasl都需要注意哪些地方。首先就是equals方法的设计需要满足下面几个特性:
- 自反性:对于所有的非null,a=a
- 对称性:a=b,则b=a
- 传递性:a=b,b=c,则a=c
- 一致性:对于没有被修改的ab,如果a=b,则一直a=b
- 非空性:对于任何非Null,a!=null
因此推荐最佳的equals设计方法应该是
@Override
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof XX))
return false;
XX xx = (XX)o;
return xx.x.equals(o.x);//TODO
}
另外,还需要注意的是,如果覆盖了equals方法,那么还需要注意它的hashCode.
hashCode
这个hashCode其实是有特定的使用场景的,比如List或者数组就不会用到hashCode,如果是HashMap、HashSet、HashTale,那么hashCode就十分重要了。
这是因为在类似HashSet的集合中,是需要对元素去重,那么如何判断两个元素是相同的呢?如果每次调用equals,那么代价有点大,这是因为如果对象内部的属性很多,equals一般需要对比每一项。所以就是用hashCode作为对比的方法。
下面看看Hashtable中添加一个元素的逻辑:
public synchronized V put(K key, V value) {
// 检查value是否为空
if (value == null) {
throw new NullPointerException();
}
// 确保key没有在table中
Entry<?,?> tab[] = table;
int hash = key.hashCode();//获取key的hash值
// 通过对table的length取余,确定对应的存储位置
int index = (hash & 0x7FFFFFFF) % tab.length;
// 挨个对比是否相同
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
在HashMap和HashSet中比较类似,都是下面的逻辑:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
可以看到它们都使用了HashCode,只不过是方式方法不一样而已。
在不同的对象中hashCode的生成规则也是不一样的,不过最终的目的都是返回一个int值。比如,在Integer中:
public static int hashCode(int value) {
return value;
}
在String中:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
因此设计hashCode,需要遵循下面的原则:
- 在程序期间,同一个对象调用hashCode,返回的是一个数
- 如果x.equals(y)返回true,那么它们的hashCode肯定也相等
- 如果x.equals(y)返回false,那么它们的hashCode有可能相等,也有可能不相等。
换句话说,判断两个对象是否相等:
- 如果他们的hashCode不相等,那么它们肯定不想等;如果相同,还得对比equals
- 如果两个对象的equals方法不同,那么对象就不同;否则,对象相同
程序猿的日常——Java基础之equals与hashCode的更多相关文章
- 程序猿的日常——Java基础之抽象类与接口、枚举、泛型
再次回顾这些基础内容,发现自己理解的又多了一点.对于一些之前很模糊的概念,渐渐的清晰起来. 抽象类与接口 抽象类通常是描述一些对象的通用方法和属性,并且默认实现一些功能,它不能被实例化.接口仅仅是描述 ...
- 程序猿的日常——Java基础之clone、序列化、字符串、数组
其实Java还有很多其他的基础知识,在日常工作技术撕逼中也是经常被讨论的问题. 深克隆与浅克隆 在Java中创建对象有两种方式: 一种是new操作符,它创建了一个新的对象,并把对应的各个字段初始化成默 ...
- 程序猿的日常——Java中的集合列表
列表对于日常开发来说实在是太常见了,以至于很多开发者习惯性的用到数组,就来一个ArrayList,根本不做过多的思考.其实列表里面还是有很多玩法的,有时候玩不好,搞出来bug还得定位半天.所以这里就再 ...
- Java基础之equals() 和 hashCode()
equals()是Object中的一个方法: public boolean equals(Object obj) { return (this == obj); } 在Object中equals()方 ...
- Java基础系列-equals方法和hashCode方法
原创文章,转载请标注出处:<Java基础系列-equals方法和hashCode方法> 概述 equals方法和hashCode方法都是有Object类定义的. publi ...
- Java中的equals和hashCode方法
本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)
Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例 原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...
- java中间==、equals和hashCode差额
java于==.equals().hashCode()和比较两个对象. 关于== ==是easy理解的.java设计java就是要比較两个对象是不是同一个对象. 对于引用变量而言.比較的时候两个引用变 ...
- Java中的equals和hashCode方法详解
Java中的equals和hashCode方法详解 转自 https://www.cnblogs.com/crazylqy/category/655181.html 参考:http://blog.c ...
随机推荐
- 201621123008 《Java程序设计》第五周学习总结
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 关键词:接口,内部类. 1.2 尝试使用思维导图将这些关键词组织起来.注:思维导图一般不需要出现过多的字. 1.3 可选:使用常 ...
- vue-router2.0 初学--动态赋值
A:router路由配置 1 export default new Router({ 2 routes: [ 3 { 4 path: '/home', 5 name: 'Home', 6 compon ...
- Sketch小妙招:在线分享设计
Sketch是很多产品经理.UI.UX设计师常使用的一款的设计工具,但是我在使用Sketch的过程中发现了一个让我困扰的事儿,或者说它缺少了一个我非常需要的服务:在线分享设计.可能很多使用Sketch ...
- scrapy官方安装方法
安装依赖 sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libss ...
- 2018.09.07 loj#10166 数字游戏(数位dp)
传送门 数位dp板子题. f[i][mod]" role="presentation" style="position: relative;"> ...
- APMServ—优秀的PHP集成环境工具
经常折腾wordpress和各种php开发的cms,免不了要在本地测试这些程序,所以选择一款好的php集成环境就至关重要啦.之前在月光博客上看到有一篇“常见的WAMP集成环境”介绍,然后先后试用过XA ...
- AE IRasterCursor 获取栅格图层像素值
在编写使用栅格图层的代码时,常常要获取栅格图层的像素值(PixelValue).如果想获取某一点的像素值,可以使用IRaster2中的getPixelValue方法.但如果想要获得的是图层中的某一块甚 ...
- (转) MVC 中 @help 用法
ASP.NET MVC 3支持一项名为“Razor”的新视图引擎选项(除了继续支持/加强现有的.aspx视图引擎外).当编写一个视图模板时,Razor将所需的字符和击键数减少到最小,并保证一个快速.通 ...
- D3_book 11.3 force
<!-- pie example --> <!DOCTYPE html> <meta charset="utf-8"> <style> ...
- 树和二叉树在java中
树代表一种非线性的数据结构,如果一组数组节点之间存在复杂的一对多关联时,程序就可以考虑使用树来保存这组数据了. 线性表.栈和队列都是线性的数据结构,这种数据结构之内的元素只存在一个对一个的关系.存储, ...