`
tottichen
  • 浏览: 13511 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java中== equals hashcode浅析

阅读更多
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()也就相等了。
以下是测试代码。
 public class Equals_HashCode {
    public static void main(String[] args) {        
         String a = new String("str");
         String b = new String("str");
         System.out.println(a==b);
         System.out.println(a.equals(b));
         System.out.println(a.hashCode());
         System.out.println(b.hashCode());
         // 输出 false true 114225 114225
         class A{
             String str;
             int i;
             public A(String str, int i) {
                 super();
                 this.str = str;
                 this.i = i;
             }
         }
         A aA = new A("str",1);
         A bA = new A("str",1);
         System.out.println(aA==bA);
         System.out.println(aA.equals(bA));
         System.out.println(aA.hashCode());
         System.out.println(bA.hashCode());
         // 输出 false false 6413875 21174459
         class B{
             String str;
             public B(String str){
                 this.str = str;
             }
         }
         B aB = new B("str");
         B bB = new B("str");
         System.out.println(aB==bB);
         System.out.println(aB.equals(bB));
         System.out.println(aB.hashCode());
         System.out.println(bB.hashCode());
         // 输出 false false 827574 17510567
         class C{
             int i;
             public C(int i){
                 this.i = i;
             }
         }
         C aC = new C(1);
         C bC = new C(1);
         System.out.println(aC==bC);
         System.out.println(aC.equals(bC));
         System.out.println(aC.hashCode());
         System.out.println(bC.hashCode());
         //输出 false false 27744459  28737396
    }
 
}
 
分享到:
评论
23 楼 redcoatjk 2011-05-24  
正和我意.写的太好了.
22 楼 cdn_mn_mm 2011-03-26  
代码:
public class HashObject
{
    private String name = null;

    public static int hascode = 0;
   
    private int temp = 0;
   
    public HashObject()
    {
        hascode++;
        if (temp <= 0)
        {
            temp = hascode;
        }
    }
    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
   
    @Override
    public int hashCode()
    {
        return temp;
    }
   
    @Override
    public boolean equals(Object obj)
    {
        return hascode % 2 == 0;
    }

    public static void main(String []args)
    {
        HashObject obj1 = new HashObject();
        obj1.setName("Lilei");
        HashObject obj2 = new HashObject();
        obj2.setName("Hanmeimei");
       
        Map<HashObject,HashObject> test = new HashMap<HashObject, HashObject>();
        test.put(obj1, obj1);
        test.put(obj2, obj2);
        test.get(obj1);
        System.out.println("equals is " + obj2.equals(obj1));
        System.out.println("obj2's hashCode = " + obj2.hashCode());
        System.out.println("obj1's hashCode = " + obj1.hashCode());
        System.out.println(test.get(obj1));
        System.out.println(test.get(obj2));
       
        Set<HashObject> set = new HashSet<HashObject>();
        set.add(obj1);
        set.add(obj2);
        System.out.println(set);
    }
   
    @Override
    public String toString()
    {
        return "HashObject.toString():" + getName() + " HashCode = " + hashCode();
    }
}

运行结果:
equals is true
obj2's hashCode = 2
obj1's hashCode = 1
HashObject.toString():Lilei HashCode = 1
HashObject.toString():Hanmeimei HashCode = 2
[HashObject.toString():Lilei HashCode = 1, HashObject.toString():Hanmeimei HashCode = 2]
21 楼 weict1988 2011-01-21  

下文摘抄自JDK6.0 API
hashCode
public int hashCode()返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
hashCode 的常规协定是:

在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

equals
public boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:

自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值 x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。


20 楼 weict1988 2011-01-21  
“equals()相等的两个对象,hashcode()一定相等; equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。 ”
这句话完全正确!!

“重写equal方法 一定要重写hashcode方法 ”这句话完全正确!!!
JDK的规定,重写equals必须要重写hashCode方法!!

既然你写java程序了,你不遵守JDK中的规定?
19 楼 beipiaoonline 2011-01-19  
yongyuan.jiang 写道
这种浅析很没依据,测试代码也不足以说明观点。

文章苍白无力。

支持
18 楼 likeblood 2010-07-23  
够深的了 看完应该都明白了
虽然入门 但是不得不知
17 楼 liaofeng_xiao 2010-07-23  
这是规范!如果这都怀疑,哪天程序出错了很难找到bug的出处。
例子:equals相等但是hashcode不等(即重写了equals不重写hashcode方法的坏处):
Set<A> set = new HashSet<A>();
set.put(a1);
set.put(a2);

如果a1.equals(a2)返回true,那么我们认为“a1和a2即为同一对象”,把它两放到set中去就只能存下一个对象,因为Set不允许重复的对象。Set存元素时使用对象的hashCode决定存储的位置,这样调用a1和a2的hashCode()方法时两个hashCode值不相等,存储的位置不一样,也就没了覆盖,这时候调用set.size()得到2,而不是1,出现错误。
16 楼 ironsabre 2010-06-08  
obsion 写道
一般来说,常量创建的HashCode是相等,用New往Heap里写是不等的~~


不懂能不能不乱讲?
15 楼 obsion 2010-06-07  
一般来说,常量创建的HashCode是相等,用New往Heap里写是不等的~~
14 楼 zuoge85 2010-06-04  
去看jdk docs  这个约定,你违反了约定出现错误没人管
13 楼 igotti 2010-06-02  
简单的来说hashCode方法的定义域是equals方法定义域的一个子集。
12 楼 banfry 2010-06-02  
ironsabre 写道
banfry 写道
五月天 写道
引用

重写equal方法 一定要重写hashcode方法

也不一定吧?我觉得也只是在处理如HashMap,HashSet等通过哈希储存结构中会使用到hashCode。
当然,在重写equals方法时同时重写hashCode是个好的规范!
我刚才那代码只是想证明:equals方法判断对象相等时,hashCode不一定相等。

对,只是一个规范而已,主要作用是提高对象存在HashMap,HashSet中的查找效率。其它地方用不到


不是查找效率的问题,是如果你equals相等而hashcode不相等时,你在hashMap里会找不到。不是效率问题,是对错问题。

先找hashcode,hashcode不等的,直接认为不等。相等的,再看equals,两者都等,才算等。

11 楼 ironsabre 2010-06-02  
五月天 写道
引用

重写equal方法 一定要重写hashcode方法

也不一定吧?我觉得也只是在处理如HashMap,HashSet等通过哈希储存结构中会使用到hashCode。
当然,在重写equals方法时同时重写hashCode是个好的规范!
我刚才那代码只是想证明:equals方法判断对象相等时,hashCode不一定相等。


规定红灯不能闯,你说这不一定吧,我就是闯了,但我闯的时候四处看了看,很小心的过了马路,最后人没出事情。
然后你得出如下结论是:红灯不一定不闯。
10 楼 ironsabre 2010-06-02  
五月天 写道
引用

equals()相等的两个对象,hashcode()一定相等; equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。

是这样吗?我做了个测试
class Product {
	private int id;
	private String name;
	
	public Product(int id, String name) {
		this.id = id;
		this.name = name;
	}
	
	@Override 
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Product)) {
			return false;
		}
		Product other = (Product)obj;
		if (other.id != this.id) {
			return false;
		}
		return true;
	}
}


public class EqualsTest {
	public static void main(String[] args) {
		Product a = new Product(1, "zcl");
		Product b = new Product(1, "chunlei");

		System.out.println("equals: " + a.equals(b)); 
		System.out.println("a.hashCode:" + a.hashCode()); 
		System.out.println("b.hashCode:" + b.hashCode());
	}
}
/** (output)

D:\My Documents\javacode>javac EqualsTest.java

D:\My Documents\javacode>java EqualsTest
equals: true
a.hashCode:12677476
b.hashCode:33263331

*/

是我理解错了还是楼主讲得有问题?


你都快土死了,你自己没有重写hashCode,当然不等。但这样是不对的。
你把这个对象放到hashMap里,看看能不能找到。
9 楼 ironsabre 2010-06-02  
banfry 写道
五月天 写道
引用

重写equal方法 一定要重写hashcode方法

也不一定吧?我觉得也只是在处理如HashMap,HashSet等通过哈希储存结构中会使用到hashCode。
当然,在重写equals方法时同时重写hashCode是个好的规范!
我刚才那代码只是想证明:equals方法判断对象相等时,hashCode不一定相等。

对,只是一个规范而已,主要作用是提高对象存在HashMap,HashSet中的查找效率。其它地方用不到


不是查找效率的问题,是如果你equals相等而hashcode不相等时,你在hashMap里会找不到。不是效率问题,是对错问题。

先找hashcode,hashcode不等的,直接认为不等。相等的,再看equals,两者都等,才算等。
8 楼 banfry 2010-06-02  
五月天 写道
引用

重写equal方法 一定要重写hashcode方法

也不一定吧?我觉得也只是在处理如HashMap,HashSet等通过哈希储存结构中会使用到hashCode。
当然,在重写equals方法时同时重写hashCode是个好的规范!
我刚才那代码只是想证明:equals方法判断对象相等时,hashCode不一定相等。

对,只是一个规范而已,主要作用是提高对象存在HashMap,HashSet中的查找效率。其它地方用不到
7 楼 axlyoung 2010-06-02  
2. 如果equals认为相等的两个对象,那hashcode一定相等;两个equals认为不相等的对象,hashcode不必需要不等。

hashCode方法到底返回了什么?如果是对象的引用(地址),那么两个equals不相等时,对象不会有相同的引用吧,引用不同,hashCode必然不等啊?!
6 楼 yongyuan.jiang 2010-06-02  
这种浅析很没依据,测试代码也不足以说明观点。

文章苍白无力。
5 楼 beneo 2010-06-01  
tottichen 写道
五月天 写道
引用

重写equal方法 一定要重写hashcode方法

也不一定吧?我觉得也只是在处理如HashMap,HashSet等通过哈希储存结构中会使用到hashCode。
当然,在重写equals方法时同时重写hashCode是个好的规范!
我刚才那代码只是想证明:equals方法判断对象相等时,hashCode不一定相等。

之前没考虑好这个问题,在此表示歉意。《Effective Java》中也提到重写equal方法,规范性地也需要重写hashCode()。
真是知识到用时方狠少呀。


1. 你是不是需要两个object判断相等? 如果如楼上希望的product a product b那样就表示相等的话,在重写一下hashcode就可以了

2. 如果equals认为相等的两个对象,那hashcode一定相等;两个equals认为不相等的对象,hashcode不必需要不等

3. 为什么equals复写的时候必须复写hashcode
你在使用一些collection framework比如,hashtable的时候,当让希望不equals的对象有不同的hash值。
4 楼 tottichen 2010-06-01  
五月天 写道
引用

重写equal方法 一定要重写hashcode方法

也不一定吧?我觉得也只是在处理如HashMap,HashSet等通过哈希储存结构中会使用到hashCode。
当然,在重写equals方法时同时重写hashCode是个好的规范!
我刚才那代码只是想证明:equals方法判断对象相等时,hashCode不一定相等。

之前没考虑好这个问题,在此表示歉意。《Effective Java》中也提到重写equal方法,规范性地也需要重写hashCode()。
真是知识到用时方狠少呀。

相关推荐

    Java中的==和equals区别

    ### Java中的`==`与`equals`方法的区别详解 在Java编程中,比较对象的相等性是一个常见的需求,但很多初学者对于`==`运算符与`equals`方法的区别容易混淆。本文将深入探讨两者之间的差异,以及它们在不同场景下的...

    java中==和equals的区别

    前言 对于开发的程序员小伙伴,...equals:在Object中模式采用==比较,通常会重写 String对象重写了 equals,比较的是变量值 从上面我们笼统的来说明了一下两者的不同,那么接下来我们看看具体的区分 对象类型的比较

    ==和equals的区别

    Java 中的 == 和 equals 方法的区别 在 Java 中,比较值大小有两种方法:== 和 equals,这两个方法的使用场景和比较规则不同,下面我们将详细探讨它们的区别。 基本数据类型和引用数据类型 在 Java 中,有两种...

    ==与equals的比较

    "Java中的==和equals方法比较" 在Java中,`==`和`equals`是两种不同的比较方法,前者比较引用地址,而后者比较对象的实际内容。 首先,让我们来看看`==`运算符的用法。`==`运算符可以用来比较基本数据类型和引用...

    java中equals和==的区别

    Java 中 equals 和 == 的区别 Java 中的 equals 和 == 是两个不同的概念,很多开发者容易混淆它们。理解这两个概念的区别是非常重要的,因为它们对编程的正确性和性能都有很大的影响。 首先,我们需要了解 Java ...

    Java中equals,hashcode和==的区别

    "Java中equals、hashcode和==的区别" Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个...

    Java中==与equals的区别小结

    在Java编程语言中,了解`==`和`equals()`的区别是非常重要的,这涉及到对基本类型和对象的正确比较。下面我们将详细探讨这两个操作符的工作原理及其在不同情况下的使用。 首先,`==`操作符主要用于比较基本类型的...

    java中的==和equals()方法1

    在Java编程语言中,了解如何正确使用`==`和`equals()`方法是非常关键的,因为它们在比较对象和基本类型时有不同的行为。下面将详细解释这两个方法的工作原理、使用场景以及一些常见误区。 首先,`==`运算符主要用于...

    Java重写equals同时需要重写hashCode的代码说明

    Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.

    浅谈java 中equals和==的区别

    以下是关于 `equals()` 和 `==` 在Java中的详细解释。 首先,`==` 是Java中的一个二元运算符,用于比较两个变量的值。对于基本数据类型(如 int、double、char),`==` 直接比较它们的值是否相等。而对于引用类型...

    ==运算符和Equals()方法区别

    在C#语言中,`==`运算符和`Equals()`方法都是用来比较两个对象是否相等,但是它们之间存在着很大的区别。 对于值类型来说,`==`运算符和`Equals()`方法的行为是一致的,都会比较两个对象的值是否相等。例如,在上面...

    java基础之 “==”与“equals”区别详解

    在java中,“==”操作符用于比较两个对象是否相等。对于基本类型来说,“==”比较的是值是否相同;对于引用类型来说,“==”比较的是引用是否相同。 2. equals()方法的作用: equals()方法用于比较两个对象的值是否...

    ==和equals方法究竟有什么区别

    在Java编程语言中,`==`和`equals()`方法是用来比较对象之间关系的两种常见方式,但它们在使用上有着显著的区别。 首先,`==`运算符主要用于比较基本类型(如int、char、byte等)的值是否相等,或者比较引用类型...

    == and equals() 的比较 绝对值得看

    首先,我们要知道在Java中,值类型(如int、char)是存储在内存的栈中,而引用类型(如类实例)的变量实际上存储的是对象在堆中的地址。栈存储变量的直接值,而堆存储对象的实际内容。 `==`运算符用于比较两个变量...

    浅谈java中==以及equals方法的用法

    Java 中的 == 和 equals 方法的用法 Java 中的 == 和 equals 方法是两个常用的比较操作符,然而,它们的用法和作用却大不相同。本文将详细介绍 Java 中 == 和 equals 方法的用法、区别和应用场景。 一、== 操作符...

    简单介绍java中的“==”和equals

    简单介绍java中的“==”和equals

    java中hashcode()和equals()和==的详解

    有许多人学了很长时间的Java,但一直不明白hashCode...首先,想要明白hashCode的作用,你必须要先知道Java中的集合。总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?

    String中==与equals区别验证

    Java中,对象的创建有两种方式:通过字面量(如 `String a = "abc";`)和通过 `new` 关键字(如 `String c = new String("abc");`)。前者通常利用字符串池来提高效率和减少内存消耗,后者则总是在堆上创建新的对象...

    Java中==运算符与equals方法的区别及intern方法详解

    "Java中==运算符与equals方法的区别及intern方法详解" Java中==运算符与equals方法的区别是Java程序设计语言中的一個非常重要的概念,它們兩者都是用來比较字符串是否相等,但是它们的比较方式完全不同。 ==运算符...

    【Java面试题】equals与==的区别

    【Java面试题】equals与==的区别

Global site tag (gtag.js) - Google Analytics