当前位置: 首页 > article >正文

Java技术分享

剖析equals方法

1、对于Object来说,其equals()方法底层实现就是"==",都是比较对象的引用是否相等,下为JDK源码。

Object c = 1;
Object d = 1;
boolean equals = c.equals(d);

public boolean equals(Object obj) {
     return (this == obj);
}

2、在JDK中其他类中通常会重写equals()方法,例如:Integer、String,源码如下。

Integer会先将Integer对象转换成基础类型int值来比较,所以此时就不再是比较两个对象引用,是比较两个对象的值是否相等。

Integer a = 1;
Integer b = 1;
boolean equals = a.equals(b);

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

@Override
public int hashCode() {
    return Integer.hashCode(value); // 由于 Integer 是不可变类,其 hashCode 就是整数值本身。
}

 String和Integer一样,引用比较重写成了值比较了。

String a = "a";
String b = "a";
boolean equals = a.equals(b);

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true; // 引用相同返回 true,引用相同,那么值肯定相同了
    }
    return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value); // equals 为下面的 equals 方法
}

@IntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
    if (value.length == other.length) {
        for (int i = 0; i < value.length; i++) { // 循环每个字符对比,本质是值比较
            if (value[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
    return false;
}

// JDK17
public int hashCode() {
    int h = hash;  // 缓存的 hash 值
    if (h == 0 && !hashIsZero) {
        h = isLatin1() ? StringLatin1.hashCode(value)
                                : StringUTF16.hashCode(value);
        if (h == 0) {
            hashIsZero = true; // 标记 hashCode 为 0 的情况
        } else {
            hash = h; // 缓存 hashCode
        }
    }
    return h;
}

static int hashCode(byte[] value) {
    int h = 0;
    for (int i = 0; i < value.length; i++) {
        h = 31 * h + (value[i] & 0xff);
    }
    return h;
}

static int hashCode(byte[] value) {
    int h = 0;
    for (int i = 0; i < value.length; i += 2) {
        h = 31 * h + getChar(value, i);
    }
    return h;
}

static char getChar(byte[] val, int index) {
    return (char) (((val[index] & 0xff) << 8) | (val[index + 1] & 0xff));
}

 JDK17对String的hashcode()方法与早期版本相比进行了优化,主要是为了更好地适应 String 的内部存储机制的变化以及性能提升。从 JDK9开始,String 使用了一种称为 Compact Strings 的机制。即:String 内部不再总是使用 char[] 存储,而是根据字符内容选择 byte[] 存储。如果所有字符是 Latin-1(单字节字符,0~255),则使用 byte[],以节省内存。如果有非 Latin-1 字符(需要双字节存储),则仍使用 UTF-16 编码。

1、hash:用于缓存计算过的 hashCode,避免重复计算。

2、hashIsZero:标志变量,处理特殊情况:

  • 如果字符串的 hashCode 计算结果为 0,会将 hashIsZero 标记为 true,防止后续重复计算。
  • 区分未计算和计算后结果为 0 的情况。
  • isLatin1():判断字符串是否为 Latin-1 编码。
    • 如果是 Latin-1,则调用 StringLatin1.hashCode(value)
      • Latin-1 的 hashCodeStringLatin1.hashCode): 遍历 byte[] 数组,使用与原始实现相同的算法(31 为乘数)。
    • 否则调用 StringUTF16.hashCode(value)
      • UTF-16 的 hashCodeStringUTF16.hashCode): 遍历 byte[] 数组(每两个字节表示一个 char),计算哈希值。

JDK17的优点

支持 Compact Strings

  • 根据字符编码选择不同的计算方式,提高内存效率和性能。

性能优化

  • 使用 hashIsZero 减少重复计算。
  • 针对 Latin-1 和 UTF-16 分开处理,减少不必要的判断和操作。

兼容性

  • 虽然内部实现发生了变化,但对外部来说行为与早期版本保持一致。

同时上述说了重写equals()方法,还需要重写hashCode 方法。

根据 Object 类的规范:

如果两个对象根据 equals 方法比较是相等的,那么它们的 hashCode 值也必须相等。

原因:

如果只重写了 equals 而没有重写 hashCode,会导致在使用哈希表(如 HashMapHashSet)时出现问题,因为这些集合依赖于对象的 hashCode 值来确定存储位置。


http://www.kler.cn/a/408214.html

相关文章:

  • 瑞佑液晶控制芯片RA6807系列介绍 (三)软件代码详解 Part.10(让PNG图片动起来)完结篇
  • 计算机毕业设计SparkStreaming+Kafka图书推荐系统 豆瓣图书数据分析可视化大屏 豆瓣图书爬虫 知识图谱 图书大数据 大数据毕业设计 机器学习
  • 【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦
  • 利用 GitHub 和 Hexo 搭建个人博客【保姆教程】
  • go的依赖注入究竟是毒药还是解药
  • Go语言进阶依赖管理
  • 运维Tips:Docker或K8s集群拉取Harbor私有容器镜像仓库配置指南
  • 《泰拉瑞亚》PC+手机版安装教程
  • ubuntu 安装 yum 无法定位问题
  • 云计算-华为HCIA-学习笔记
  • 经验笔记:Git 中的远程仓库链接及上下游关系管理
  • mybatis学习(一)
  • Transformer详解及衍生模型GPT|T5|LLaMa
  • 写时复制,读时加载
  • 从零开始学习数据库 day0(基础)
  • JavaEE-线程安全专题
  • Tessy学习笔记—一些零散知识点
  • 昇腾CANN环境下Whisper.cpp安装指南
  • Windows 软件之 FFmpeg
  • Pytorch使用手册-Save and Load the Model(专题八)
  • 亚太杯数学建模竞赛介绍
  • 11.21作业
  • 【jvm】AOT编译器
  • git仓库推送到远端
  • window系统下使用open-webui+ollama部署大模型
  • LCR-003比特位计数