jdk 里面的int、string、类、复合类的 HashCode 方法

目录

Integer

核心代码

String

核心代码

举例

重写 equals

结果

重写 hashCode 方法

结果

参考文章


Integer

核心代码

    /**
     * Returns a hash code for this {@code Integer}.
     *
     * @return  a hash code value for this object, equal to the
     *          primitive {@code int} value represented by this
     *          {@code Integer} object.
     */
    @Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

    /**
     * Returns a hash code for a {@code int} value; compatible with
     * {@code Integer.hashCode()}.
     *
     * @param value the value to hash
     * @since 1.8
     *
     * @return a hash code value for a {@code int} value.
     */
    public static int hashCode(int value) {
        return value;
    }

本质就是返回原值

 

String

核心代码

    /**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    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];   // 31 * 高位到低位
            }
            hash = h;
        }
        return h;
    }

以字符串"123"为例:

字符'1'的ascii码是49

hashCode = (49*31 + 50)*31 + 51

或者这样看:

hashCode=('1' * 31 + '2' ) * 31 + '3'

可见实际可以看作是一种权重的算法,在前面的字符的权重大。

这样有个明显的好处,就是前缀相同的字符串的hash值都落在邻近的区间。

好处有两点:

1.可以节省内存,因为hash值在相邻,这样hash的数组可以比较小。比如当用HashMap,以String为key时。

2.hash值相邻,如果存放在容器,比好HashSet,HashMap中时,实际存放的内存的位置也相邻,则存取的效率也高。(程序局部性原理)

以31为倍数,原因了31的二进制全是1,则可以有效地离散数据。

"123".equals("123") // 结果是 true

 

 

举例

hashCode 应该是类的地址

   static class Person {
       String name;
       int age;
       public Person(String name, int age) {
           this.name = name;
           this.age = age;
       }
   }

 

HashMapTest.Person person2 = new HashMapTest.Person("name2", 22);
HashMapTest.Person person3 = new HashMapTest.Person("name2", 22);
person2.equals(person3)  // 如果没有重写 equals 方法以及 hashCode 方法,结果是 false,比较的是地址,与 "==" 效果一样
  											// person2 和 person3 放入到 HashSet 里面是两个对象

 

重写 equals

    static class Person {
        String name;
        int age;

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

        @Override public boolean equals(Object obj) {
            // 同一对象,返回 true
            if (this == obj) return true;
            // 不同类,返回 false
            if (!(obj instanceof Person))
                return false;
            Person person = (Person) obj;
            return person.name == name && person.age == age;
        }
    }
 System.out.println(person2.hashCode());
 System.out.println(person3.hashCode());
 if(person2.equals(person3)) {
     System.out.println("equals");
 }

 HashMap<HashMapTest.Person, Integer> hashMap = new HashMap<>();
 hashMap.put(person2, 2);
 System.out.println(hashMap.get(person3));

 

结果

equals 但是 hashCode 不一样,因为 hashCode 应该还是地址,放入到 HashMap 里面是找不到的

image.png

 

重写 hashCode 方法

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

 

结果

equals 并且 hashCode 一样

image.png

 

 

 

 

参考文章

Java中String的hash函数分析

Java自定义类中重写equals方法

自定义类如何重写hashCode方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值