equals==和hashCode

Posted Mipha

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了equals==和hashCode相关的知识,希望对你有一定的参考价值。

equals和==

  ==可以用于基本类型和引用类型:当用于基本类型时,比较值是否相同当用于引用类型时,比较的是所指向的对象的地址是否相同。如果有包装类型,则先将包装类型转换为基本类型再比较值是否相等。当两边都为包装类型时,即为对象,比较的是地址。

  “==”和“!=”比较的是地址,指一个new()出来的地址。

  equals不能作用于基本数据类型的变量,如果没有对equals重写,则比较的的是引用类型的变量所指向的对象的地址。String类的equals方法重写了是比较值。

  下面是String的equals的源码:可以看出String是将字符串拆成字符挨个比较。

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof 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) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
}

 

  Integer的equals()方法如下:是Integer的实例且value值也相等的情况下返回true,其他返回false。

public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
}

  两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true。

  基本型和基本封装型进行“==”运算符的比较,基本型封装型会自动拆箱变为基本型后再进行比较。

 

equals和hashCode

  参考博客

  http://doc.orz520.com/a/doc/2014/0527/2019620.html?from=haosou

       http://www.importnew.com/20381.html

equals

  默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。要是类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。

hashCode

  public native int hashCode();

  它是一个本地方法,它的实现与本地机器有关,这里我们暂且认为他返回的是对象存储的物理位置(实际上不是,这里写是便于理解)。

        hashcode方法只有在集合中用到。

  hashCode在扮演的角色为寻域(寻找某个对象在集合中区域位置)。hashCode可以将集合分成若干个区域,每个对象都可以计算出他们的hash码,可以将hash码分组,每个分组对应着某个存储区域,根据一个对象的hash码就可以确定该对象所存储区域,这样就大大减少查询匹配元素的数量,提高了查询效率。

  对于HashMap、HashSet、HashTable而言,它变得异常重要。所以在使用HashMap、HashSet、HashTable时一定要注意hashCode。

  将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则判断对象的equals是否相等。这样处理,当我们存入大量元素时就可以大大减少调用equals()方法的次数,极大地提高了效率。

 

注意

两个对象的值相同(x.equals(y) == true),但是却可有不同的hashCode。

原因:

  如果对象保存在HashSet或HashMap中,他们的equals值相等,那么他们的hashCode值必须相等。

  如果不是保存在HashSet或HashMap中,则与hashCode没有什么关系,这时hashCode值可以不相等,例如ArrayList存储的对象就不用实现hashCode,但是通常都回去实现。

 

Integer类型与int类型的==比较

参考博客:

        http://blog.csdn.net/sgls652709/article/details/49079767

举个例子来说明:

Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2); //true
System.out.println(f3 == f4); //false

  同样都是Integer类型的比较,为什么用100比的结果是true,150比的结果是false。

  给一个Integer赋予一个int类型的时候,会调用Integer的静态方法valueOf。

public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

   valueof()是把int 转化成Integer对象类型;(延伸:intValue()是把Integer对象类型变成int的基础数据类型

  在IntegerCache中cache数组初始化如下,存入了-128 - 127的值。

   从上面我们可以知道给Interger 赋予的int数值在-128 - 127的时候,直接从cache中获取,这些cache引用对Integer对象地址是不变的,但是不在这个范围内的数字,则new Integer(i) 这个地址是新的地址,不可能一样的。

  使用Integer a = 1;Integer a = Integer.valueOf(1); 在值介于-128127直接时,作为基本类型。

  使用Integer a = new Integer(1); 时,无论值是多少,都作为对象。

延伸

  java中还有与Integer类似的是Long,它也有一个缓存,在区间[-128,127]范围内获取缓存的值,而Long与long比较的时候先转换成long类型再做值的比较

  Double类型,它没有缓存,但是当Double与double比较的时候会先转换成double类型,再做值的比较

 

以上是关于equals==和hashCode的主要内容,如果未能解决你的问题,请参考以下文章

面试点:Java 中 hashCode() 和 equals() 的关系

Java的hashCode和equals方法

重写HashCode和equals规范

equals() 和 hashCode()

SpringBoot 重写hashCode方法和equals方法

在TreeSet和TreeMap中使用hashCode()和equals()