Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2019-05-13:“equals”与“==”、“hashCode”的区别和使用场景?

Moosphan opened this issue · comments

2019-05-13:“equals”与“==”、“hashCode”的区别和使用场景?

equals 比较的是值和地址,如果没有重写equals方法,其作用与==相同;
在String中重写了equals方法,比较的是值是否相等;
hashCode用于散列数据结构中的hash值计算;
equals两个对象相等,那hashcode一定相等,hashcode相等,不一定是同一个对象;

  • ==
    == 用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据(注意是基本类型)或两个 引用变量是否相等,只能用==操作符。
    假如一个变量指向的数据是对象类型的,例如Objet obj 1= new Object() 那么,这时候涉及了两块内存;变量 obj1 是一个内存,new Object() 是另一个内存(堆内存),此时,变量 obj1 所对应的内存中存储的数值就是对象占用的那块内存(堆内存)的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较;
  • equals
    equals 方法是用于比较两个独立对象的内容是否相同:
    String a=new String("a");
    String b=new String("a");
    两条new语句创建了两个对象,然后用a/b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值(对应对象的首地址)是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。我们看看equal 源码:
     * Note that it is generally necessary to override the {@code hashCode}
     * method whenever this method is overridden, so as to maintain the
     * general contract for the {@code hashCode} method, which states
     * that equal objects must have equal hash codes.
     *
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }
    如果一个类没有重写equals 方法 那么就是调用 objectequals 其实就是 ==
  • hashCode
    因为重写的 equals() 里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个 hash 值进行比较就可以了,效率很高,那么 hashCode() 既然效率这么高为什么还要 equals() 呢?
  • 使用场景
    因为 hashCode() 并不是完全可靠,有时候不同的对象他们生成的 hashcode 也会一样(hash冲突),所以 hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以可以得出:
    equals() 相等的两个对象他们的 hashCode() 肯定相等,也就是用 equals() 对比是绝对可靠的。
    hashCode() 相等的两个对象他们的 equals() 不一定相等,也就是 hashCode() 不是绝对可靠的。
    所有对于需要大量并且快速的对比的话如果都用 equals() 去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用 hashCode() 去对比,如果 hashCode() 不一样,则表示这两个对象肯定不相等(也就是不必再用 equals() 去再对比了),如果 hashCode() 相同,此时再对比他们的 equals(),如果 equals() 也相同,则表示这两个对象是真的相同了
一般情况下 equals比较的是 对象的地址,和 == 一样,但是有很多类重写了equals 方法。比如String 等。

而 hashcode( ) 方法返回一个 int 数,在object 类中的默认实现是 “将该对象的内存地址 转换成一个整数返回”

hashCode 的 常规协定

在java 程序执行期间,在同一对象上调用多次 hashCode 返回的 int 数 必须项目。前提是对象上的equals 方法中所用的信息没有被修改。

如果 equals 比较的两个对象是相等的。那么hashCode 返回的 int 数必定是相等的

当equals 方法被重写时 ,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定。

1,若重写了 equals 方法,则有必要重写hashCode 方法

2,若 equals 比较的结果相等,那么 hashCOde 的结果一定相等。

3,若equals 比较的结果不相等,那么 hashCode 的结果 也有可能相等

4,若 hashCode 返回相同的 int 数,那么equals 不一定相等。

5,若 hashCode 返回不同的 int 数,那么 equals 一定不相等。

6,同一对象 在执行期将 若已经存储在集合中。则不能修改影响hashCode 值得相关信息。否则会导致 内存泄露的问题。

搞懂hashCode

commented

很好

我们一般这么理解
equal比较的是内容
== 比较的存储地址或基本数据类型的数值比较(数学意义)
hashCode 对内存分配的位置确定

使用场景

equal一般比较内容相等 比如字符串相等
==一般比较数值 或者null判断
hashcode我们一般用来判断来两个对象是否相等,但这里需要注意的是 两个对象的hashcode相等,两个对象不一定相等,两个相等的对象hashcode一定相等。

我们为什么要这样判断呢?

因为判断两个对象相等重写equal的重载方法比较多,需要判断 传递性、非空性、自反性、一致性、对称性

如有不对 欢迎指正

commented

关于 ==

== 用于比较变量所对应的内存中所存储的数值是否相同:

  1. 变量为引用类型,== 比较的是 对象存储的内存地址

  2. 变量为基本数据类型,== 比较的是 基本类型的数值大小

关于 equals()

Object.java 中 equals 方法的默认实现:

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

采用默认实现时,equals 和 == 作用相同。

关于 hashCode()

默认的,Object 类的 hashCode()方法返回这个对象存储的内存地址的 hash 值。

小结

默认实现的情况:

  1. 两个对象通过 equals() 比较是相等的,则其 hashCode 也一定相等

  2. 两个对象的 hashCode 相等,则 equals() 不一定相等。-----hash冲突---发生概率很低~~

一般比较两个对象是否相等,先判断其 hashCode,后判断 equals。hashCode 不相等,肯定就不是同一对象。

重写 equals

如果重写 equals() 方法必须要重写 hashCode() 方法。

equals():

equals()是超类Object中的方法
equals()比较的是内容
equals()用来检测两个对象是否相等,即检测两个对象的值是否相等

==

==是操作符
== 比较的对象类型不同,作用不同

对象为引用类型时,==比较的是对象的内存地址
对象为基本数据类型时,==比较的是对象的数值大小

  1. “==”是比较两个对象的内存地址是否相同
  2. equals在未重写的时候和“==”一样
  3. hashcode对象hash标识,一般情况下不同的对象具有不同的hash值
  4. 如果重写了equals,一定要重写hashcode。原因:java底层的大多是键值查找的键都是hashcode,
    如果判断两个对象equal是相等的,并且判断条件没有用到hash值判断。那么可能就会出现把对象加入集合当中,集合还是认为是两个不同的对象,因为hashcode不同,所以要重写。
commented
  • equals
    equals 方法是用于比较两个独立对象的内容是否相同:

    String a=new String("a");
    String b=new String("a");

    两条new语句创建了两个对象,然后用a/b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值(对应对象的首地址)是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。我们看看equal 源码:

     * Note that it is generally necessary to override the {@code hashCode}
     * method whenever this method is overridden, so as to maintain the
     * general contract for the {@code hashCode} method, which states
     * that equal objects must have equal hash codes.
     *
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }

楼主,你这里复制的不是String的equals源码,所以这里你对比的 String a 和b 是否 equals肯定是返回的FALSE。

String 的equals人家重写了,源码在这:

    /**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = length();
            if (n == anotherString.length()) {
                int i = 0;
                while (n-- != 0) {
                    if (charAt(i) != anotherString.charAt(i))
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

在Java中,"equals"、"=="和"hashCode"是用于对象比较和哈希处理的关键方法,它们有不同的作用和使用场景:

"==" 运算符:
    "==" 用于比较两个对象的引用是否相等,即判断两个对象是否指向同一个内存地址。
    当使用 "==" 比较基本数据类型时,比较的是它们的值。
    对于引用类型,比较的是对象的引用,即两个对象是否是同一个实例。
    适用于判断对象是否完全相同,包括引用相等和值相等。

"equals" 方法:
    "equals" 方法用于比较两个对象的内容是否相等,即判断两个对象是否在逻辑上相等。
    "equals" 方法是 Object 类中定义的方法,可以被子类覆盖实现自定义的相等判断逻辑。
    默认情况下,"equals" 方法和 "==" 作用相同,即比较对象的引用是否相等。
    通常需要重写 "equals" 方法来实现自定义的相等比较,比较对象的属性值是否相等。
    适用于比较对象的内容是否相等,常用于集合的元素比较和自定义类的相等性判断。

"hashCode" 方法:
    "hashCode" 方法用于获取对象的哈希码,返回一个整数值。
    哈希码是由对象的内容生成的,相等的对象应该具有相同的哈希码,但相同的哈希码并不意味着对象相等。
    "hashCode" 方法通常与散列表(如 HashMap、HashSet 等)一起使用,用于快速定位和检索对象。
    如果重写了 "equals" 方法,通常也需要同时重写 "hashCode" 方法,以保证相等的对象具有相同的哈希码。
    适用于需要进行快速对象查找和比较的数据结构,如散列表。

使用场景:

使用 "==" 来判断两个对象是否为同一实例,或者比较基本数据类型的值是否相等。
使用 "equals" 方法来比较对象的内容是否相等,特别是在自定义类中需要进行对象相等性判断时。
在使用散列表等数据结构时,重写 "hashCode" 方法以确保对象的正确定位和比较。