美文网首页
浅谈equals()和hashCode()

浅谈equals()和hashCode()

作者: Sandy_678f | 来源:发表于2018-12-10 14:03 被阅读0次

    equals()
    equals() 的作用是 用来判断两个对象是否相等。

    Object.java中的equals()方法

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

    通过判断两个对象的地址是否相等(即两个引用是否指向同一个对象),来判断两个对象是否相等。

    既然Object.java中定义了equals()方法,这就意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。 使用默认的“equals()”方法,等价于“==”方法。

    通过继承类“是否覆盖了equals()方法”,可将equals()的使用分为两类。
    1)某个类没有覆盖equals()方法,实际上比较两个对象是不是同一个对象,等价于使用“==”方法去比较。
    2)可以覆盖equals()方法,通过其他的方式去比较两个对象是否相等。通常的方法是比较两个对象的值(内容)是否相等。

    String.java中的equals()方法

    public boolean equals(Object var1) {
            if (this == var1) {
                return true;
            } else {
                if (var1 instanceof String) {
                    String var2 = (String)var1;
                    int var3 = this.value.length;
                    if (var3 == var2.value.length) {
                        char[] var4 = this.value;
                        char[] var5 = var2.value;
    
                        for(int var6 = 0; var3-- != 0; ++var6) {
                            if (var4[var6] != var5[var6]) {
                                return false;
                            }
                        }
    
                        return true;
                    }
                }
    
                return false;
            }
    }
    

    java对equals()重写的要求
    1)对称性,a.equals(b)与b.equals(a)的返回结果一致
    2)反射性,a.equals(a)一定是返回true
    3)类推性,a.equals(b),b.equals(c) 则有 a.equals(c)
    4)一致性,只要a与b的内容不发生变化,则a.equals(b)的对比结果不会发生变化
    5)a.equals(null)一定返回false,a.equals(其他类型对象)一定返回false,例如通常使用如下语句判断对象类型:

    (var1 instanceof String)
    

    hashCode()
    hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。

    Object.java中的hashCode()方法

    public native int hashCode();
    

    是一个本地方法,java类中不提供实现体,无final关键字修饰,可以由继承类重写。

    延伸:
    当一个类第一次被使用到时,这个类的字节码会被加载到内存,并且只会加载一次。在这个被加载的字节码的入口维持着一个该类所有方法描述符的list,这些方法描述符包含这样一些信息:方法代码存于何处,它有哪些参数,方法的描述符(public之类)等。
    如果一个方法描述符内有native,这个描述符块将有一个指向该方法的实现的指针。这些实现在一些dll文件内,但是它们会被操作系统加载到java程序的地址空间。当一个带有本地方法的类被加载时,其相关的dll并未被加载,因此指向方法实现的指针并不会被设置。当本地方法被调用之前,这些dll才会被加载,这是通过调用java.system.loadLibrary()实现的。

    既然Object.java中定义了hashCode()方法,这就意味着所有的Java类都实现了hashCode()方法。虽然,每个Java类都包含hashCode() 函数,但是只有在创建某个类的散列表时,hashCode()才有用,其作用是:确定该类的每一个对象在散列表中的位置。创建类的对象,对象数组时hashCode()方法无用。

    散列表指的是Java集合中本质是散列表的类,例如:HashMap,Hashtable,HashSet。

    equals()与 hashCode()
    要理清楚equals()与hashCode()的联系,需要将类的集合区分为散列表集合和非散列表集合来梳理。
    1)如果一个类,不需要存储在散列表集合中,这种情况下直接使用equals()来判断类是否相等,hashCode()无任何作用;
    2)如果一个类,需要存储在散列表集合中(例如:HashSet,HashTable,HashMap),则需要区别equals()和hashCode()的使用。

    先来看情况一:不创建类的散列表集合

    public class differHashCodeAndEqual1 {
    
    
        private static class Person
        {
            private String name;
            private int age;
    
            public Person(String name, int age){
                this.name = name;
                this.age = age;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (obj == null)
                {
                    return false;
                }
    
                if(obj instanceof Person)
                {
                    if(this == obj){
                        return true;
                    }
                    else
                    {
                        return (this.name==((Person) obj).name && this.age ==((Person) obj).age);
                    }
                }
                return false;
            }
        }
    
        public static void main(String[] args) {
    
            Person p1 = new Person("sandy",19);
            Person p2 = new Person("sandy",19);
            Person p3 = new Person("Monica",21);
    
            System.out.println("p1.equals(p2): "+p1.equals(p2)+"  p1(hashCode()): "+p1.hashCode()+"  p2(hashCode()): "+p2.hashCode());
            System.out.println("p1.equals(p3): "+p1.equals(p3)+"  p1(hashCode()): "+p1.hashCode()+"  p3(hashCode()): "+p3.hashCode());
        }
    
    }
    

    输出:

    p1.equals(p2): true  p1(hashCode()): 1163157884  p2(hashCode()): 1956725890
    p1.equals(p3): false  p1(hashCode()): 1163157884  p3(hashCode()): 356573597
    

    学习情况二:创建类的散列表集合,但是没有重写hashCode()方法

    public class differHashCodeAndEqual1 {
    
    
        private static class Person
        {
            private String name;
            private int age;
    
            public Person(String name, int age){
                this.name = name;
                this.age = age;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (obj == null)
                {
                    return false;
                }
    
                if(obj instanceof Person)
                {
                    if(this == obj){
                        return true;
                    }
                    else
                    {
                        return (this.name==((Person) obj).name && this.age ==((Person) obj).age);
                    }
                }
                return false;
            }
    
            @Override
            public String toString() {
                return "name: " + name + " age: "+ age ;
            }
        }
    
        public static void main(String[] args) {
    
            Person p1 = new Person("sandy",19);
            Person p2 = new Person("sandy",19);
            Person p3 = new Person("Monica",21);
    
            HashSet hashSet = new HashSet();
            hashSet.add(p1);
            hashSet.add(p2);
            hashSet.add(p3);
    
            System.out.println("p1.equals(p2): "+p1.equals(p2)+"  p1(hashCode()): "+p1.hashCode()+"  p2(hashCode()): "+p2.hashCode());
            System.out.println("p1.equals(p3): "+p1.equals(p3)+"  p1(hashCode()): "+p1.hashCode()+"  p3(hashCode()): "+p3.hashCode());
    
            System.out.println("hashSet:" + hashSet);
        }
    
    }
    

    输出:

    p1.equals(p2): true  p1(hashCode()): 1163157884  p2(hashCode()): 1956725890
    p1.equals(p3): false  p1(hashCode()): 1163157884  p3(hashCode()): 356573597
    hashSet:[name: sandy age: 19, name: sandy age: 19, name: Monica age: 21]
    

    这时可以看到,p1,p2的equals()结果返回为true,但是hashCode()结果为不同,HashSet的add方法向hashSet中添加了[重复的]元素。

    正确的情况三:创建类的散了表集合,重写equals()方法和hashCode()方法,使得HashSet集合中无重复添加的元素。

    public class differHashCodeAndEqual1 {
    
    
        private static class Person
        {
            private String name;
            private int age;
    
            public Person(String name, int age){
                this.name = name;
                this.age = age;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (obj == null)
                {
                    return false;
                }
    
                if(obj instanceof Person)
                {
                    if(this == obj){
                        return true;
                    }
                    else
                    {
                        return (this.name==((Person) obj).name && this.age ==((Person) obj).age);
                    }
                }
                return false;
            }
    
            @Override
            public int hashCode() {
                int nameHash =  name.toUpperCase().hashCode();
                return nameHash ^ age;
            }
    
            @Override
            public String toString() {
                return "name: " + name + " age: "+ age ;
            }
        }
    
        public static void main(String[] args) {
    
            Person p1 = new Person("sandy",19);
            Person p2 = new Person("sandy",19);
            Person p3 = new Person("Monica",21);
    
            HashSet hashSet = new HashSet();
            hashSet.add(p1);
            hashSet.add(p2);
            hashSet.add(p3);
    
            System.out.println("p1.equals(p2): "+p1.equals(p2)+"  p1(hashCode()): "+p1.hashCode()+"  p2(hashCode()): "+p2.hashCode());
            System.out.println("p1.equals(p3): "+p1.equals(p3)+"  p1(hashCode()): "+p1.hashCode()+"  p3(hashCode()): "+p3.hashCode());
    
            System.out.println("hashSet:" + hashSet);
        }
    
    }
    

    输出:

    p1.equals(p2): true  p1(hashCode()): 78665798  p2(hashCode()): 78665798
    p1.equals(p3): false  p1(hashCode()): 78665798  p3(hashCode()): -2015168530
    hashSet:[name: sandy age: 19, name: Monica age: 21]
    

    结论:
    1)、如果两个对象equals()结果相等,那么它们的hashCode()值一定相同。
    2)、如果两个对象hashCode()相等,它们并不一定equals()相等。

    相关文章

      网友评论

          本文标题:浅谈equals()和hashCode()

          本文链接:https://www.haomeiwen.com/subject/qyfrhqtx.html