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方法的设计需要满足下面几个特性:

  1. 自反性:对于所有的非null,a=a
  2. 对称性:a=b,则b=a
  3. 传递性:a=b,b=c,则a=c
  4. 一致性:对于没有被修改的ab,如果a=b,则一直a=b
  5. 非空性:对于任何非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,需要遵循下面的原则:

  1. 在程序期间,同一个对象调用hashCode,返回的是一个数
  2. 如果x.equals(y)返回true,那么它们的hashCode肯定也相等
  3. 如果x.equals(y)返回false,那么它们的hashCode有可能相等,也有可能不相等。

换句话说,判断两个对象是否相等:

  1. 如果他们的hashCode不相等,那么它们肯定不想等;如果相同,还得对比equals
  2. 如果两个对象的equals方法不同,那么对象就不同;否则,对象相同

程序猿的日常——Java基础之equals与hashCode的更多相关文章

  1. 程序猿的日常——Java基础之抽象类与接口、枚举、泛型

    再次回顾这些基础内容,发现自己理解的又多了一点.对于一些之前很模糊的概念,渐渐的清晰起来. 抽象类与接口 抽象类通常是描述一些对象的通用方法和属性,并且默认实现一些功能,它不能被实例化.接口仅仅是描述 ...

  2. 程序猿的日常——Java基础之clone、序列化、字符串、数组

    其实Java还有很多其他的基础知识,在日常工作技术撕逼中也是经常被讨论的问题. 深克隆与浅克隆 在Java中创建对象有两种方式: 一种是new操作符,它创建了一个新的对象,并把对应的各个字段初始化成默 ...

  3. 程序猿的日常——Java中的集合列表

    列表对于日常开发来说实在是太常见了,以至于很多开发者习惯性的用到数组,就来一个ArrayList,根本不做过多的思考.其实列表里面还是有很多玩法的,有时候玩不好,搞出来bug还得定位半天.所以这里就再 ...

  4. Java基础之equals() 和 hashCode()

    equals()是Object中的一个方法: public boolean equals(Object obj) { return (this == obj); } 在Object中equals()方 ...

  5. Java基础系列-equals方法和hashCode方法

    原创文章,转载请标注出处:<Java基础系列-equals方法和hashCode方法> 概述         equals方法和hashCode方法都是有Object类定义的. publi ...

  6. Java中的equals和hashCode方法

    本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...

  7. Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)

    Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例  原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...

  8. java中间==、equals和hashCode差额

    java于==.equals().hashCode()和比较两个对象. 关于== ==是easy理解的.java设计java就是要比較两个对象是不是同一个对象. 对于引用变量而言.比較的时候两个引用变 ...

  9. Java中的equals和hashCode方法详解

    Java中的equals和hashCode方法详解  转自 https://www.cnblogs.com/crazylqy/category/655181.html 参考:http://blog.c ...

随机推荐

  1. HDFS高可用性及其分布式系统思想基础

    源自单点失效问题,也就是当NameNode不可用的时候,用什么办法可以平滑过渡? 最直接的办法是再添加一个备用的NN,这就产生了Active NameNode和Standby NameNode的设计思 ...

  2. 抓包之网络分析器- Wiresshark

    https://www.wireshark.org/ Wireshark(前称Ethereal)是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wi ...

  3. chrome,opera..通过file协议浏览html代码时,发送的ajax请求本地文件,会报跨域错误

    XMLHttpRequest cannot loadfile:///E:/webs/extJS/ext-3.3.0/examples/csdn/combobox.txt?_dc=14147389739 ...

  4. DevExpress VCL 已死-----关于13.1.4的发布。

    随着DevExpress VCL 13.1.4 的发布,已基本上宣布了devexpress vcl 已经死亡了. 除了一些bug 修正,没有什么新的东西,每年的订阅费又那么贵,而且delphi 现在已 ...

  5. 2018.10.23 NOIP模拟 “新”的家园(缩图+dijksta/spfa)

    传送门 考试70分骗分写挂了=30分=全场最低. 哎今天230垫底了. 这题出的挺好. 对于非关键点直接缩点. 每次把要查的insertinsertinsert进缩好的图里面跑spfa/dijkstr ...

  6. 26. The Greenhouse Effect and Its Consequences 温室效应及其后果

    26. The Greenhouse Effect and Its Consequences 温室效应及其后果 ①The greenhouse effect causes trouble by rai ...

  7. CentOS7中实用的命令总结

    一:软件安装配置方面 这里总结一下对个人很实用的功能 1.查询rpm包的依赖哪些文件:rpm -qpR xx.rpm,然后rpm会分析此包的文件依赖性 2.查询系统中安装了哪些rpm包:rpm -qa ...

  8. RESTful架构概念

    本文转载自:http://www.ruanyifeng.com/blog/2011/09/restful.html 越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软 ...

  9. swagger core 和 swagger ui 如何关联【窥探】

    几个片段: package io.swagger.jaxrs.listing; import io.swagger.annotations.ApiOperation; import org.apach ...

  10. (并查集)The Suspects --POJ --1611

    链接: http://poj.org/problem?id=1611 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82830#probl ...