String类的hashCode()方法源码分析

Object类中的hashCode()方法: 

  • 同一个对象,hashCode必须相同;如果两个对象的equals相等,那么hashCode也必须要相等!
  • hashCode()方法是native本地方法,是C++代码,hashCode的值,不一定是指向对象的内存地址,具体是什么值,底层依赖于JVM的具体实现,但是,同一个对象的hashCode()必须要唯一,所以hashCode就是唯一标识一个对象的。
  • 在每个覆盖了equals()方法的类中,也必须覆盖hashCode()方法,因为如果不这样做的话,就会违反Object.hashCode()的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap、HashSet和Hashtable

String类中的hashCode()方法:

  • String字符串重写了equals()方法,就必须要同时重写hashCode()方法,目的是确保:equals相等,hashCode也必须要相等。
  • String字符串的equals()和hashCode()方法都是基于字符串内容去计算的,由于字符串内容相同,所以equals()就相同,hashCode()也相同。
  • String类的equals()方法就是将String字符串转为char[]数组,然后while循环遍历比较两个char[]数组的字符是否相等,如果相等返回true,如果有一个不相等,则直接返回false。

String类中的hashCode()方法源码:

String类的hashCode()方法源码分析_第1张图片

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;
}

String的hashCode()计算公式为:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]  =>  乘法散列

使用字符串中当前每个字符的ASCII码值  *  31的(字符串长度 - 1   -2   -3)次幂进行累加

关于hashCode()计算过程中,为什么使用了数字31,主要有以下几个原因:

1. 使用质数计算哈希码,由于质数的特性,它与其它数字相乘之后,计算结果唯一的概率更大,        哈希冲突的概率更小。

2. 使用的质数越大,哈希冲突的概率越小,但是计算的速度也越慢,31是哈希冲突和性能的折中

3. JVM会自动对31进行优化:31 * i == (i << 5) - i

package com.gch.demo;

/**
 * String类重写了hashCode()和equals()方法
 * 由于String类的hashCode()方法和equals()方法是基于变量的字符串的内容去计算
 * 因此只要String类的对象的内容相同,则hashCode()和equals()一定相同
 */
public class StringDemo {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("hello");

        int hashCode1 = s1.hashCode();
        int hashCode2 = s2.hashCode();
        int hashCode3 = s3.hashCode();


        System.out.println(hashCode1); // 99162322
        System.out.println(hashCode2); // 99162322
        System.out.println(hashCode3); // 99162322
    }
}

JDK 8及其之前String底层由char[]数组构成的(就是对字符数组的封装),JDK 9之后,String底层采用的byte[]数组。

String有没有长度限制? 

  • 有长度限制。 

编译期间

根据虚拟机规范:

String类的hashCode()方法源码分析_第2张图片编译期间,字符串的最大长度不能超越65535个字节,即编译期间的String字符串的最大长度为65534个字节,不然就会编译报错。

运行期间

String类的hashCode()方法源码分析_第3张图片运行期间,String的最大长度就要看Integer.MAX_VALUE的值了,即:2^31 - 1个字节。
不管怎样,String的最大长度就不能超过虚拟机当前最大内存设置。 

数组有没有length()方法?String呢? 

  • 数组没有length()方法,但是有length属性,String有length()方法。 
package com.gch.demo;

/**
 * @author GAO
 * @date 2023-12-15
 */
public class LengthDemo {
    public static void main(String[] args) {
        String str = "Java";
        String[] languages = {"Java","Python","PHP"};
        System.out.println(str.length()); // 字符串有length()方法
        System.out.println(languages.length); // 数组有length属性
    }
}

注意:从JDK 7开始,switch是可以用在字符串String上的。

String类是可变的吗?为什么?

String类的hashCode()方法源码分析_第4张图片

Java中的String类设计是不可变的,String类是final类型的,不能被继承,器对应的char字符类型的value[]数组被定义成private final的,说明不能通过外界修改,即不可变~!

你可能感兴趣的:(java,jvm,开发语言)