持续学习合集--个人理解hashcode

前言

作为一个长期在处理CRUD和HTML编写的程序员,也是要想办法提升一下,本人选择深入了解java和模仿一些主流框架开始入手。
本次选择hashCode入手,作为object的提供的一个基础方法,hashCode对于hash表数据结构和hash算法有着至关重要的影,响例如hashMap、hashSet等等。

hashCode是什么

从Object的源码注释可以了解到,这个方法返回了对象的hash值,为了支持散列表,例如HashMap等;
这里需要引进一个知识,什么是hash:
http://www.cnblogs.com/jiewei915/archive/2010/08/09/1796042.html
http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html
引用网上两位博友的文章作为对于hash的理解。

这里我们需要浅浅的介绍一下hashCode的一个知识:

可以直接根据hashcode值判断两个对象是否相等吗?
肯定是不可以的,因为不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。
也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;
如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;
如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;
如果两个对象的hashcode值相等,则equals方法得到的结果未知。

两个对象的hashcode值相等,则equals方法得到的结果未知。
以上是转自网上一位博友的论点,基于此上,我们担心会有可能出现hashCode相同的情况。

为什么重写hashCode

大部分重写hashCode,都是发生在重写equals(个人拙见)时发生的。
在Object中hashCode的源码注释上标明:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
  • 机器大法翻译一下:
  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。 从应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。
  • 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须生成不同的整数结果。 但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。

根据官方的注释理解得知:重写了equals就必须要让hashCode取到的值也必须一样。

public class People {
    private String name;
    private int age;

    public People(String name,int age) {
        this.name = name;
        this.age = age;
    }

    public void setAge(int age){
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        return this.name.equals(((People)obj).name) && this.age== ((People)obj).age;
    }

    public static void main(String[] args) {

        People p1 = new People("Jack", 12);
        System.out.println(p1.hashCode());
        People p2 = new People("Jack", 12);
        System.out.println(p2.hashCode());

        HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
        hashMap.put(p1, 1);

        System.out.println(hashMap.get(p2));
    }
}

很明显,两个创建的People是不一样的hashCode,但使用我重写后的equals方法比对后又是一样的结果。
在HashMap添加一个p1对象,使用get(p2)方法使用p2去查找,此时没有重写hashCode则会返回null(但不符合此代码的初衷,相同对象返回相同value)。
在HashMap中的get方法

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

使用的则是hashCode方法去获取相应的value;
如果我们重写相应的hashCode则可以解决这个问题。

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

这样在我们设定的equals逻辑中相同的对象则返回一样的hashCode,在hashMap中能够取到value值。

JDK中常见的重写hashCode

这里举得例子是最重要的一个例子,就是String重写的hashCode。

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;
}
为什么常见的重写hashCode要用到31

这是个涉及数学的讨论范畴,在这里并不去深究,我则直接引用
https://blog.csdn.net/qq_38182963/article/details/78940047
中的一个结论:

“可以看到,使用 31 最主要的还是为了性能。当然用 63 也可以。但是 63 的溢出风险就更大了。那么15 呢?仔细想想也可以。”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值