美文网首页
equals方法和hashCode方法

equals方法和hashCode方法

作者: 多喝水JS | 来源:发表于2018-12-31 13:42 被阅读3次

简介

默认情况下,对象的equal()和hashcode()方法是调用Object类的equals方法和hashcode方法

public booleanequals(Object obj) {
  return (this== obj);
}

public native int hashCode();
public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

从上面代码可以看出Object类的equals()和hashCode()方法效果一样,都是根据对象的hash值来判断两个对象是否相等。hash值如何生成的可以看这里:点击

例子

@Test
    public void testEqualsAndHashCode() {
        User user1 = new User();
        User user2 = new User();
        System.out.println(user1.hashCode());
        System.out.println(user2.hashCode());
        if(user1.equals(user2)) {
            System.out.println("相等");
        }else {
            System.out.println("不相等");
        }
    }
输出:
1144748369
340870931
不相等

因为每个对象生成的哈希值不一样,所以equals方法返回false,
如何实现相等呢?通过重写equals

重写equals

定义一个User对象有多个属性值姓名、年龄、身份证;我们需要两个对象的各项属性值一样的就认为这两个对象是相等的;那么此时我们就需要重写equals方法了;
代码如下:

class User {
    private String name;// 姓名
    private String IdCard;// 身份证
    private int age;// 年龄

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof User) {
            User user = (User) obj;
            if (user.getIdCard().equals(this.IdCard) && user.getName().equals(this.name) && user.getAge() == this.age) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    //省略get和set方法
}

(1)测试equals()

@Test
    public void testEqualsAndHashCode() {
        User user1 = new User();
        user1.setName("dd");
        user1.setAge(18);
        user1.setIdCard("d30");
        User user2 = new User();
        user2.setName("dd");
        user2.setAge(18);
        user2.setIdCard("d30");
        System.out.println("user1.equals(user2)=" + user1.equals(user2));
    }
输出:
user1.equals(user2)=true

因为user1和user2的name和idCard和age都一样,自然equals返回true
(2)把他们存储到set中

Set set =new HashSet();
set.add(user1);
set.add(user2);
System.out.println(set.size());
输出:
2

问题来了明明user1和user2两个对象是equals的那么为什么把他们放到set中会有两个对象(Set特性是不允许重复数据的)?
原因是user1和user2的hashcode 不一样导致的;

重写hashcode()

上面例子可以知道因为我们没有重写父类(Object)的hashcode方法,Object的hashcode方法会通过使用线程局部状态来实现Marsaglia's xor-shift随机数生成(详情看这点击)相应的hashcode;所以每个对象的hash值都不一样。
下面通过重写hashcode()方法,根据user对象内容生成hash值

@Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + IdCard.hashCode();
        result = 31 * result + age;
        return result;
    }

再测试,结果如下:

user1.equals(user2)=true
1

因为user1和user2的name和idCard和age都一样,自然hashcode也一样

总结

上面例子说明了重写equals方法后必须重写hashCode方法

扩展:String的hashCode()计算公式为:s[0]31^(n-1) + s[1]31^(n-2) + … + s[n-1]
关于hashCode()计算过程中,为什么使用了数字31,主要有以下原因(引用这里的结论点击):

1、使用质数计算哈希码,由于质数的特性,它与其他数字相乘之后,计算结果唯一的概率更大,哈希冲突的概率更小。
2、使用的质数越大,哈希冲突的概率越小,但是计算的速度也越慢;31是哈希冲突和性能的折中,实际上是实验观测的结果。
3、JVM会自动对31进行优化:31 * i == (i << 5) – i
具体原因我也不太懂

相关文章

网友评论

      本文标题:equals方法和hashCode方法

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