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. c++ 中的符号与关键字

    符号按照符号的ASC码数值从小到达排列,关键字按照英文字母排序. & [38] 位运算:取地址:左值引用[指针.引用都是可以做类型转换的] #include <iostream> ...

  2. How to Set Up an Rsync Daemon on Your Linux Server

    Introduction This tutorial will take you through setting up an rsync daemon on your Linux server. Yo ...

  3. distinct group by 去重查询

    select * from dc_restaurants;  31 select DISTINCT (restaurant_name),id from dc_restaurants ; 31 (会按照 ...

  4. 100 floors 2 eggs

    https://github.com/Premiumlab/Python-for-Algorithms--Data-Structures--and-Interviews/blob/master/Moc ...

  5. idea中实体类序列化后生成序列化版本ID的方法

    为什么要添加序列化版本ID了(serialVersionUID)? 通过判断实体类的serialVersionUID来验证版本一致性的.在进行反序列化时,JVM会把传来的字节流中的serialVers ...

  6. python-optparse模块给脚本增加参数选项

    import optparse parser = optparse.OptionParser('[-] Usage %prog '+ '-H <RHOST[s]> -l [-p -F ]' ...

  7. 1) Spring_HelloWorld

    1. Spring Tool Suite™ 方式一:下载对应eclipse版本的文件,离线安装 4.4.2 springsource-tool-suite-3.6.4.RELEASE-e4.4.2-u ...

  8. OpenGl 绘制一个立方体

    OpenGl 绘制一个立方体 为了绘制六个正方形,我们为每个正方形指定四个顶点,最终我们需要指定6*4=24个顶点.但是我们知道,一个立方体其实总共只有八个顶点,要指定24次,就意味着每个顶点其实重复 ...

  9. hdu 5036 概率+bitset

    http://acm.hdu.edu.cn/showproblem.php?pid=5036 n个房间每个房间里面有一把或多把钥匙可以打开其他的门.如果手上没有钥匙可以选择等概率随机选择一个门炸开,求 ...

  10. codeforces 261B Maxim and Restaurant(概率DP)

    B. Maxim and Restaurant time limit per test 2 seconds memory limit per test 256 megabytes input stan ...