程序猿的日常——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 ...
随机推荐
- 局域网2台机器访问mysql服务器
- Django 必会面试题总结
1 列举Http请求中常见的请求方式 HTTP请求的方法: HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式 注意: 1)方法名称是 ...
- 日期 时间选择器(DatePicker和TimePicker)实现用户选择
日期和时间 作者的设计TimePicker时,大小分布不合理,我调整宽度为match-parent高度为wrap-parent就可以了. public class MainActivity exten ...
- java中的类、对象、方法
类=一个种类(class)东西 对象=属于该种类的一个对象/物件(object,台湾翻译为‘物件’)方法=对这个种类的东西都可以进行的操作 比如我有一辆汽车-类 public class car {. ...
- 7系列GTX中的疑惑
1.PCOMMA与MCOMMA指什么? PCOMMA是指RD-部分的数据,MCOMMA是指RD+部分的数据. 2.risk信号作用? risk信号来指示有效的K码. 如果不选择用8b10b来编码,是需 ...
- 使用OpenCV进行相机标定
1. 使用OpenCV进行标定 相机已经有很长一段历史了.但是,伴随着20世纪后期的廉价针孔照相机的问世,它们已经变成我们日常生活的一种常见的存在.不幸的是,这种廉价是由代价的:显著的变形.幸运的是, ...
- (树的直径)LightOJ -- 1094
链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#problem/C 求树的直径,这里只不过给每条边增加一个边长属性,变成 ...
- SoC FPGA开发板的FPGA配置数据下载和固化
小梅哥编写,未经许可,严禁用于任何商业用途 2018年7月2日星期一 soc fpga的烧写和固化方式与传统的纯fpga固化方式即存在形式上的相同,也存在细节上的差异,特整理此文. AC501-So ...
- hdu 2086 A1 = ?(数学题)
转载链接 因为:Ai=(Ai-1+Ai+1)/2 - Ci, A1=(A0 +A2 )/2 - C1; A2=(A1 + A3)/2 - C2 , ... => ...
- oracle中row_number() over()分析函数用法
row_number()over(partition by col1 order by col2)表示根据col1分组,在分组内部根据col2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内 ...