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. ubuntu14.04 Samba服务无法访问 可能没有权限 指定的网络名不再可用的问题

    按常规配置后,在windows资源管理器中登陆samba服务器,看得到分享目录却无法打开,弹出"无法访问.您可能没有权限使用网络资源,请与这台服务器的管理员联系以查明您是否有访问权限.指定的 ...

  2. linux的零碎知识

    一  nfs服务器 1  NFS的介绍:是Network File System的简写,是网络文件系统.用于分散式文件系统的协定,由sun公司开发的,在1984年向外公布的. 2  NFS的功能:是通 ...

  3. 使用Jsoup获取网页内容超时设置

    使用Jsoup获取网页内容超时设置 最近使用Jsoup来抓取网页,并对网页进行解析,发现很好用.在抓取过程中遇到一个问题,有些页面总是报Timeout异常,开始想是不是被抓取网站对IP进行了限制,后来 ...

  4. 将IP地址转化为整数

    $ip = 'IP地址';echo $intip = sprintf('%u',ip2long($ip)); //转换为无符号整型echo long2ip($intip);//将整型转换为ip

  5. CentOS里vim基本操作

    1.关于退出 :wq!  ----强制保存退出 :wq  ---- 保存退出 :x   ----- 作用和:wq 一样 ZZ  ---- 作用和:wq一样,(注意Z是大写的,并且不是在命令模式) :q ...

  6. 【Unity】1.3 Unity3D游戏开发学习路线

    分类:Unity.C#.VS2015 创建日期:2016-03-23 一.基本思路 第1步--了解编辑器 首先了解unity3d的菜单,视图界面.这些是最基本的基础,可以像学word操作一样,大致能明 ...

  7. java 解析txt/html文件

    package util.read; import java.io.BufferedReader;import java.io.FileReader; public class ReadFromFil ...

  8. trsd_extract_EDSD_new

    # -*- coding:utf-8 -*- import re ''' 适应新版本 ''' year='17A'#用户自定义 ss='./data/'#根目录 filename = ss+'EDSD ...

  9. 20155336 2016-2017-2《JAVA程序设计》第六周学习总结

    20155336 2016-2017-2<JAVA程序设计>第六周学习总结 教材学习内容总结 第十章 串流(Stream): 数据有来源及目的地,衔接两者的是串流对象.如果要将数据从来源取 ...

  10. 201709013工作日记--Android消息机制HandlerThread

    1.首先来看一个常规的handler用法: 在主线程中建立一个handler: private Handler mHandler = new Handler() { @Override public ...