java学习-- equals和hashCode的关系

【JAVA编程】equals相等hashcode必然相等,反之不然

2018年03月28日 10:35:47 天路漫漫 阅读数:1786更多

个人分类: 【JAVA】

1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠。

2.hashCode()相等的两个对象他们的equal()不一定相等,就是hashCode()不是绝对可靠。

hashCode是对象在内存地址通过hash算法得到的哈希码;

比较两个对象是否相等:

1.首先比较hashcode ,如果hashcode相等则进一步比较equals,不相等则两个对象肯定不相等;

2.hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。

equals方法的作用
 
1、默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。

2 、要是类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。

----------

重写hashcode时用31 做因子 ===  31 是2的5次方减一的素数;位移运算效率高,虚拟机对这方面的优化吧

2018年03月28日 10:35:47 天路漫漫 阅读数:1786更多

个人分类: 【JAVA】

1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠。

2.hashCode()相等的两个对象他们的equal()不一定相等,就是hashCode()不是绝对可靠。

hashCode是对象在内存地址通过hash算法得到的哈希码;

比较两个对象是否相等:

1.首先比较hashcode ,如果hashcode相等则进一步比较equals,不相等则两个对象肯定不相等;

2.hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。

equals方法的作用
 
1、默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。

2 、要是类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。

----------

重写hashcode时用31 做因子 ===  31 是2的5次方减一的素数;位移运算效率高,虚拟机对这方面的优化吧

java中hashcode和equals的区别和联系

HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键。 那么Java运行时环境是如何判断HashSet中相同对象、HashMap中相同键的呢?当存储了“相同的东西”之后Java运行时环境又将如何来维护呢? 
在研究这个问题之前,首先说明一下JDK对equals(Object obj)和hashcode()这两个方法的定义和规范: 在Java中任何一个对象都具备equals(Object obj)和hashcode()这两个方法,因为他们是在Object类中定义的。 equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。 hashcode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。 接下来有两个个关于这两个方法的重要规范(我只是抽取了最重要的两个,其实不止两个): 规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。 规范2:如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。 根据这两个规范,可以得到如下推论: 1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。 2、如果两个对象不equals,他们的hashcode有可能相等。 3、如果两个对象hashcode相等,他们不一定equals。 4、如果两个对象hashcode不相等,他们一定不equals。 
这样我们就可以推断Java运行时环境是怎样判断HashSet和HastMap中的两个对象相同或不同了。我的推断是:先判断hashcode是否相等,再判断是否equals。 
测试程序如下:首先我们定义一个类,重写hashCode()和equals(Object obj)方法

Java代码

[java] view plaincopyprint?

  1. class A {
  2. @Override
  3. public boolean equals(Object obj) {
  4. System.out.println("判断equals");
  5. return false;
  6. }
  7. @Override
  8. public int hashCode() {
  9. System.out.println("判断hashcode");
  10. return 1;
  11. }
  12. }

[java] view plaincopyprint?

  1. class A {
  2. @Override
  3. public boolean equals(Object obj) {
  4. System.out.println("判断equals");
  5. return false;
  6. }
  7. @Override
  8. public int hashCode() {
  9. System.out.println("判断hashcode");
  10. return 1;
  11. }
  12. }

然后写一个测试类,代码如下:

Java代码

[java] view plaincopyprint?

  1. public class Test {
  2. public static void main(String[] args) {
  3. Map<A,Object> map = new HashMap<A, Object>();
  4. map.put(new A(), new Object());
  5. map.put(new A(), new Object());
  6. System.out.println(map.size());
  7. }
  8. }

[java] view plaincopyprint?

  1. public class Test {
  2. public static void main(String[] args) {
  3. Map<A,Object> map = new HashMap<A, Object>();
  4. map.put(new A(), new Object());
  5. map.put(new A(), new Object());
  6. System.out.println(map.size());
  7. }
  8. }

运行之后打印结果是: 判断hashcode 判断hashcode 判断equals 2 
可以看出,Java运行时环境会调用new A()这个对象的hashcode()方法。其中: 打印出的第一行“判断hashcode”是第一次map.put(new A(), new Object())所打印出的。 接下来的“判断hashcode”和“判断equals”是第二次map.put(new A(), new Object())所打印出来的。 
那么为什么会是这样一个打印结果呢?我是这样分析的: 1、当第一次map.put(new A(), new Object())的时候,Java运行时环境就会判断这个map里面有没有和现在添加的 new A()对象相同的键,判断方法:调用new A()对象的hashcode()方法,判断map中当前是不是存在和new A()对象相同的HashCode。显然,这时候没有相同的,因为这个map中都还没有东西。所以这时候hashcode不相等,则没有

[java] view plaincopyprint?

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. class A {
  4. @Override
  5. public boolean equals(Object obj) {
  6. System.out.println("判断equals");
  7. return true;
  8. }
  9. @Override
  10. public int hashCode() {
  11. System.out.println("判断hashcode");
  12. return 1;
  13. }
  14. }
  15. public class Test {
  16. public static void main(String[] args) {
  17. Map<A,Object> map = new HashMap<A, Object>();
  18. map.put(new A(), new Object());
  19. map.put(new A(), new Object());
  20. System.out.println(map.size());
  21. }
  22. }

[java] view plaincopyprint?

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. class A {
  4. @Override
  5. public boolean equals(Object obj) {
  6. System.out.println("判断equals");
  7. return true;
  8. }
  9. @Override
  10. public int hashCode() {
  11. System.out.println("判断hashcode");
  12. return 1;
  13. }
  14. }
  15. public class Test {
  16. public static void main(String[] args) {
  17. Map<A,Object> map = new HashMap<A, Object>();
  18. map.put(new A(), new Object());
  19. map.put(new A(), new Object());
  20. System.out.println(map.size());
  21. }
  22. }

必要再调用 equals(Object obj)方法了。参见推论4(如果两个对象hashcode不相等,他们一定不equals) 2、当第二次map.put(new A(), new Object())的时候,Java运行时环境再次判断,这时候发现了map中有两个相同的hashcode(因为我重写了A类的hashcode()方 法永远都返回1),所以有必要调用equals(Object obj)方法进行判断了。参见推论3(如果两个对象hashcode相等,他们不一定equals),然后发现两个对象不equals(因为我重写了equals(Object obj)方法,永远都返回false)。 3、这时候判断结束,判断结果:两次存入的对象不是相同的对象。所以最后打印map的长度的时候显示结果是:2。

改写程序如下:

Java代码

运行之后打印结果是: 判断hashcode 判断hashcode 判断equals 1 
显然这时候map的长度已经变成1了,因为Java运行时环境认为存入了两个相同的对象。原因可根据上述分析方式进行分析。 
以上分析的是HashMap,其实HashSet的底层本身就是通过HashMap来实现的,所以他的判断原理和HashMap是一样的,也是先判断hashcode再判断equals。 
所以:写程序的时候应尽可能的按规范来,不然在不知不觉中就埋下了bug!

1. ‘==‘是用来比较两个变量(基本类型和对象类型)的值是否相等的, 如果两个变量是基本类型的,那很容易,直接比较值就可以了。如果两个变量是对象类型的,那么它还是比较值,只是它比较的是这两个对象在栈中的引用(即地址)。 对象是放在堆中的,栈中存放的是对象的引用(地址)。由此可见‘==‘是对栈中的值进行比较的。如果要比较堆中对象的内容是否相同,那么就要重写equals方法了。 2. Object类中的equals方法就是用‘==‘来比较的,所以如果没有重写equals方法,equals和==是等价的。 通常我们会重写equals方法,让equals比较两个对象的内容,而不是比较对象的引用(地址)因为往往我们觉得比较对象的内容是否相同比比较对象的引用(地址)更有意义。 3. Object类中的hashCode是返回对象在内存中地址转换成的一个int值(可以就当做地址看)。所以如果没有重写hashCode方法,任何对象的hashCode都是不相等的。通常在集合类的时候需要重写hashCode方法和equals方法,因为如果需要给集合类(比如:HashSet)添加对象,那么在添加之前需要查看给集合里是否已经有了该对象,比较好的方式就是用hashCode。 4. 注意的是String、Integer、Boolean、Double等这些类都重写了equals和hashCode方法,这两个方法是根据对象的内容来比较和计算hashCode的。(详细可以查看jdk下的String.java源代码),所以只要对象的基本类型值相同,那么hashcode就一定相同。

5. equals()相等的两个对象,hashcode()一般是相等的,最好在重写equals()方法时,重写hashcode()方法; equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。 反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。在object类中,hashcode()方法是本地方法,返回的是对象的引用(地址值),而object类中的equals()方法比较的也是两个对象的引用(地址值),如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了。

有许多人学了很长时间的Java,但一直不明白hashCode方法的作用,我来解释一下吧。首先,想要明白hashCode的作用,你必须要先知道Java中的集合。  总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。    于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。   这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。   所以,Java对于eqauls方法和hashCode方法是这样规定的:1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同    上面说的对象相同指的是用eqauls方法比较。    你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降

下面是一个重写equals和hashcode的例子:

  • public class Cat
  • {
  • private String name;
  • private String birthday;
  • public Cat()
  • {
  • }
  • public void setName(String name)
  • {
  • this.name = name;
  • }
  • public String getName()
  • {
  • return name;
  • }
  • public void setBirthday(String birthday)
  • {
  • this.birthday = birthday;
  • }
  • public String getBirthday()
  • {
  • return birthday;
  • }
  • //重写equals方法
  • public boolean equals(Object other)
  • {
  • if(this == other)
  • {
  • //如果引用地址相同,即引用的是同一个对象,就返回true
  • return true;
  • }
  • //如果other不是Cat类的实例,返回false
  • if(!(other instanceOf Cat))
  • {
  • return false;
  • }
  • final Cat cat = (Cat)other;
  • //name值不同,返回false
  • if(!getName().equals(cat.getName())
  • return false;
  • //birthday值不同,返回false
  • if(!getBirthday().equals(cat.getBirthday()))
  • return false;
  • return true;
  • }
  • //重写hashCode()方法
  • public int hashCode()
  • {
  • int result = getName().hashCode();
  • result = 29 * result + getBirthday().hashCode();
  • return result;
  • }
  • }

原文地址:https://www.cnblogs.com/gaoBlog/p/10716572.html

时间: 2024-11-08 10:43:23

java学习-- equals和hashCode的关系的相关文章

Java中equals和hashcode的区别?

Java中equals和hashcode方法是在Object对象中的,所以每个对象都有这两个方法,大多数时候我们为了实现特定需求需要重写这两个方法 equals和hashcode方法常用在同一个类中用于比较,尤其是在set集合中比较元素是否重复 equals方法返回true的两个对象,hashcode一定相同 hashcode相同的两个对象,equals方法不一定返回true 原文地址:https://www.cnblogs.com/qf123/p/8671141.html

Java实战equals()与hashCode()

一.equals()方法详解 equals()方法在object类中定义如下: 代码 public boolean equals(Object obj) { return (this == obj); } 很明显是对两个对象的地址值进行的比较(即比较引用是否相同).但是我们知道,String . Math.Integer.Double等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方 法. 比如在String类中如下: 代码 public boolean eq

java中equals,hashcode和==的区别

1.== java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型 byte,short,char,int,long,float,double,boolean   他们之间的比较,应用双等号(==),比较的是他们的值. 2.引用类型(类.接口.数组) 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false. 对象是放在堆中的,栈中存放的是对象的引用(地址).由此可见'=='是对栈中

Java:重写equals()和hashCode()

以下内容总结自<Effective Java>. 1.何时需要重写equals() 当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念). 2.设计equals() [1]使用instanceof操作符检查“实参是否为正确的类型”. [2]对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值. [2.1]对于非float和double类型的原语类型域,使用==比较: [2.2]对于对象引用域,递归调用equals方法: [2.3]对于float域,使用Float.float

Java 重写 equals 与 hashCode 的注意事项

为什么重写 equals 的时候必须重写 hashCode 大家可能从很多教程中了解到: SUN官方的文档中规定"如果重定义equals方法,就必须重定义hashCode方法,以便用户可以将对象插入到散列(哈希)表中" 那么 SUN 公司是出于什么考虑做了这个规定呢? 在集合框架中的HashSet,HashTable和HashMap都使用哈希表的形式存储数据,而hashCode计算出来的哈希码便是它们的身份证.哈希码的存在便可以: 快速定位对象,提高哈希表集合的性能. 只有当哈希表中对

java ==、equals、hashcode有什么区别

1.== 用来比较两个对象的存储空间 2.equals是Object类提供的方法之一,每个java类都继承Object类,所以每一个对象都具有equals方法,所以在没有覆盖equals方法的情况下,equals与==运算一样,比较的是引用 所以要比较两个对象的内容 要重写equals()方法 3.hashCode()方法是区分两个对象是否相等,返回内存中地址转换成的一个int值 一般覆盖equals()也要覆盖hashCode()方法 equals相等 hashcode就相等 .equals不

Java学习之equals和hashcode的关系

两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对? 答:不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同.Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同:(2)如果两个对象的hashCode相同,它们并不一定相同.当然,你未必要按照要求去做,但是如果你违背了上述原则就会

java中equals与hashCode还有tostring方法学习记录

package javas.fristdome01; import org.testng.annotations.Test; class Person { private String name; private int age; Person() { } Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void s

java重载equals和hashCode

class Employee { private int salary; private java.util.Date hireDay; private String name; public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public Date getHireDay() { return hireDay; } public void s