java中==和equals和hashCode的区别

首先对这三种操作符分别进行解释说明。

1. ==

==可以操作两种数据,一种是数值类型,一种是引用类型。

  1. 数值类型
    顾名思义,对数值类型使用“==”就是对两个数据的值进行比较,即使这两个数据是不同的类型,只要他们的值相等,“==”的结果就是相等的。
public static void main(String[] args) {
        System.out.println(97 == 'a');     //true
        System.out.println(97 == 97.0000);   //true
    }
  1. 引用类型
    对引用类型的比较,并不是比较其值,而是比较其引用的对象在内存中的地址是否相同。
public static void main(String[] args) {
        String a = new String("aaaaaa");
        String b = new String("aaaaaa");
        System.out.println(a == b);    //false
    }

因为a与b是两个不同的对象,他们在内存中的地址也不相同,所以结果为false。

  1. 小结
  • 对于两个数值类型使用“==”,就是对其值进行比较,即使其类型不同也没有关系。
  • 对于两个引用类型而言,比较的是其引用的对象在内存中的位置,如果位置相同则为true。即这两个引用类型引用的是同一个对象。

2. equals

equals是Object的实例方法,用于比较其content是否相同。
首先对于默认的Object的equals方法而言,其源码为:

public boolean equals(Object obj) {
    return (this == obj);
  }

从中可以看出来,其效果与使用“==”是相同的,即为比较两个对象在内存中的地址是否相同。
然而对于继承Object的类来说,它们重写了equals方法。以String类为例:

public static void main(String[] args) {
        String a = new String("aaaaaa");
        String b = new String("aaaaaa");
        System.out.println(a.equals(b));    //true
    }

如果按照Object类中的equals方法来进行比较的话,应该是true才对,但实际结果为false,这就是因为String重写了equals方法:

public boolean equals(Object anObject) {
        if (this == anObject) {      //对象在内存中地址相同时返回true
            return true;
        }
        if (anObject instanceof String) {        //对象是否为String
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {      //对String中的char进行比较
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

从上述源码看出,String的equals实现首先是使用“==”进行比较,如果是同一个对象则返回true,如果不是相同的对象,则判断是否是同一类型,相同的话则对String的值(即组成String的char)进行比较。java中所有内置类的equals方法均是这样实现的,例如Integer等

3. hashCode

hashCode在Object类中的实现是将对象在内存中的地址转化为一个int类型。
然而在实际应用中,Object的子类会对这个方法进行重写,以满足各自的需求,下面还是以String类为例。
我们有一个统计世界上所有人名的需求,将其放入一个set中,而set是不能够有重复数据的,那我们怎么判断新加入的数据是否和set中已有的数据相同呢?可能有人会说使用重写的equals方法,但是假如set中已经有几十万的数据了,那每添加一次数据,就要和之前存在的几十万数据进行equals比较,这就太浪费时间和计算资源了。
这个时候就需要hashCode的帮助了,hashCode能够通过一个特定的算法对每一个对象得到一个特定的值,这个值重复的概率很低。
因此我们对每一个加入到set中的数据都求出其hashCode,然后把这个hashCode作为其在set中的位置。这样基本上每一个不同的数据都能够找到其在set中的位置,而且因为相同的对象使用hashCode方法得到的值是一样的,这就保证set中不会存在相同的数据了。
hashCode的源码如下所示:

/**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * 
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * 
* using {@code int} arithmetic, where {@code s[i]} is the * ith character of the string, {@code n} is the length of * the string, and {@code ^} indicates exponentiation. * (The hash value of the empty string is zero.) * * @return a hash code value for this object. */ 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; }

从中可以看出,该值是使用s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]这个算法得到的,而这个算法所需要的数据,如val[i], value.length等均是equals方法实现中所需要的数据,可以这样说hashCode方法就是使用equals方法中的数据进行特定的算法运算后得到的值
这样一来,hashCode与equals方法的关系就很明显了,在添加数据到set这种拥有不重复数据的集合中时,使用equals方法需要进行大量的计算,而hashCode就是帮助处理这种情况的。因为其内部实现使用了相同的数据,只是算法不同,所以:

  1. equals方法返回“true”,其hashCode方法返回的值也是相同的。
  2. equals方法返回“false”,其hashCode方法返回的值不一定不同,因为其内部实现的算法不能够保证输入值不同,输出值也不同。例如1 + 1 = 2 , 0 + 2 = 2。
  3. hashCode返回的值不同,其equals方法返回的一定是“false”

4. 总结

  • hashcode是系统用来快速检索对象而使用
  • equals方法本意是用来判断引用的对象是否一致
  • 重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性。

你可能感兴趣的:(java中==和equals和hashCode的区别)