Java中hashcode的计算方式

Posted 小妖云汐

tags:

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

String计算hashCode的方式

/**
  * hashcode的计算方式为,以31为权重,举例“java”字符串的计算
  * j 的 ASCII码 为 106
  * a 的 ASCII码 为 97
  * v 的 ASCII码 为 118
  * 字符串 va 的 hashcode为 118 * 31 + 97
  * 字符串 java 的 hashcode为 106 * 31 * 31 * 31  + 97 * 31 * 31 + 118 * 31 + 97
*/
System.out.println(Integer.valueOf('j')); //ASCII码:106
System.out.println(Integer.valueOf('a')); //ASCII码:97
System.out.println(Integer.valueOf('v')); //ASCII码:118
System.out.println(Integer.valueOf('a')); //ASCII码:97
int hashcode = 106 * 31 * 31 * 31  + 97 * 31 * 31 + 118 * 31 + 97;
System.out.println("hashCode计算的值:" + hashcode);   //3254818
System.out.println("Objects hashCode:" + Objects.hashCode("java") ); //3254818
System.out.println("String hashCode:" + "java".hashCode()); //3254818
//Objects.hash在上面的计算方式基础上额外增加了31
System.out.println("Objects hash:" + (3254818 + 31));  //3254849
System.out.println("Objects hash:" + Objects.hash("java") ); //3254849

Objects.hash实际上是由Arrays.hashCode(values)运算得出的,计算过程如下:

hashcode有什么用?
    当过多对象进行比较时,需要调用n次equals逐个进行比较,会大大降低效率
    但是不同的对象可能会生成相同的hashcode值,所以不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等
    如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。

Entity重写hashCode方法

  • 为什么要重写equals方法?
    如果不重写entity的equals方法,默认调用equals,比较的结果并不准确。
public class Users 
    private int id;
    private String name;

    public Users(int id,String name)
        this.id = id;
        this.name = name;
    

    public static void main(String[] args) 
        Users user1 = new Users(1,"小妖");
        Users user2 = new Users(1,"小妖");
        System.out.println(user1.equals(user2)); //打印结果:false
    

在没有重写equals的情况下,默认调用的是Object的equals,和使用“==”比较的结果一样

  • 对于值对象,==比较的是两个对象的值
  • 对于引用对象,==比较的是两个对象的地址
public boolean equals(Object obj) 
   return (this == obj);

而重写equals方法之后,可以根据entity本身的属性来判断,该实体类是否相等

public class Users 
    private int id;
    private String name;

    public Users(int id,String name)
        this.id = id;
        this.name = name;
    

    @Override
    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Users users = (Users) o;
        return id == users.id &&
                Objects.equals(name, users.name);
    

	@Override
    public int hashCode() 
        return Objects.hash(id, name);
    
  
    public static void main(String[] args) 
        Users user1 = new Users(1,"小妖");
        Users user2 = new Users(1,"小妖");
        System.out.println(user1.equals(user2)); //打印结果:true
    

  • 为什么要重写hashCode方法?
    重写equal方法时,一定要重写hashCode方法!保证相同的对象返回相同的hash值,不同的对象返回不同的hash值。
    如果不重写hashCode方法,调用的是Object中的hashCode方法
public native int hashCode();

重写后的hashcode方法会基于entity的属性计算值

	@Override
    public int hashCode() 
        return Objects.hash(id, name);
    

Entity的hashcode方法主要用于将entity放入HashMap、HashSet等集合框架中。
    两个对象相等,hashcode一定相等
    两个对象不等,hashcode不一定不等
    hashcode相等,两个对象不一定相等
    hashcode不等,两个对象一定不等

HashMap中计算hashCode的应用

  • hashMap中hashCode的计算
  • hashMap的大致存取过程

put操作:
    当调用put(key,value)方法的时候,会先对键key调用key.hashcode()方法,根据方法返回的hashcode来找到bucket的位置来存Entry对象。
    根据hashcode找到对应的bucket之后,通过equals()方法在对应的链表逐一对比,检查这个链表里有没存在相同的key对象。如果有,则用新的value取代旧的value。如果没有,在链表的尾部加上这个新的Entry对象。

get操作:
    当调用get(key)的时候,会调用key的hashcode方法获得hashcode。根据hashcode获取相应的bucket。
    由于一个bucket对应的链表中可能存有多个Entry,这个时候会调用key的equals方法来找到对应的Entry

以上是关于Java中hashcode的计算方式的主要内容,如果未能解决你的问题,请参考以下文章

Java中hashcode的计算方式

Java中hashcode的计算方式

如何在 Java 中计算枚举的哈希码,以及将枚举 hashCodes 组合为 HashMap 的键

Java 中 String 字符串的 hashCode 计算原理

Java Hashtable 如何根据 hashcode 计算元素的放置位置? [复制]

Object.hashCode() 算法