2. Object中equals和toStirng 源码分析

news2024/10/7 9:17:15

文章目录

  • 1.equals方法
  • 2.重写equals方法为何一定要重写hashCode方法?
    • 2.1 反例演示
  • 3.toString方法
  • 4. 整型转二进制

我们都知道Object是所有类的父类,那么它里面的一些方法你是否真的理解了呢?
下面我们就以源码为基础来学习这些看似简单的方法吧!!

1.equals方法

我们都知道String中的equals是比较两个字符串对象内容是否相同,但你知道吗,String中的equals其实是对Object中的equals方法的重写,那么Object类中equals本来的面目是什么呢?
请看下面代码:

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

从源码看很明显,他其实是判断两个对象的引用是不是同一个。

2.重写equals方法为何一定要重写hashCode方法?

这个主要是有些处理逻辑需要用到hashCode方法生成的值作为判断两个对象是否相等的依据。

在通常的认知中,对hashCode的定义是:
如果两个对象的HashCode相等,则这两个对象不一定相等,如果两个对象的HashCode不相等,那么这两个对象一定不相等。
反过来说,就是如果两个对象相等,他们的HashCode一定相等,如果两个对象不相等,他们的HashCode可能相等。

为了遵循这个机制,我们需要重写。

2.1 反例演示

假如我们新建一个类,对equals进行了重写,但是没有对hashCode进行重写:

public class HashCodeStudy {
    int i;
    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        try {
            if(this.i== obj.getClass().getField("i").getInt(obj)){
                return true;
            }
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) {
        HashCodeStudy obj1 = new HashCodeStudy();
        obj1.i = 1;
        HashCodeStudy obj2 = new HashCodeStudy();
        obj2.i = 1;
        System.out.println("obj1和obj2的内容是否相等?");
        System.out.println(obj1.equals(obj1));
        System.out.println("obj1和obj2的hashCode是否相等?");
        System.out.println(obj1.hashCode()==obj2.hashCode());
    }
}

在这里插入图片描述
我们可以看到,当我们没有对hashCode进行重写时,就会发生两个对象内容相等,但是他们hashCode不相等的情况。这就导致我们不能用HashCode判断两个对象是否相等。

从另一个角度上看:
我们不能仅仅通过对象的hashCode去判断两个对象是否相等,还需要根据equals去比较内容。

例如HashMap的putVal中存在这样一段逻辑:

if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;

它用来判断两个对象是否相等,可以看到只有在他们hashCode相等时才会进入内容的比较,如果我们不重写hashCode方法,如果两个内容相等的对象的内存地址不同,产生的hashCode是不一样的,就无法通过这段逻辑去判断两个对象是否相等。
所以为了我们能正常使用集合对对象进行处理,在重写equlas后,想通过equals机制比较对象时,需要重写hashCode方法。

3.toString方法

我们看一下源码

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

我们先来调用下,看到底打印出什么信息:

public static void main(String[] args) {
    Object obj = new Object();
    System.out.println(obj.toString());
}

在这里插入图片描述

从结果来看我们知道前面的java.lang.Object打印的是getClass().getName()的结果,就是这个类的名称,以@为一个分隔符,后面的一串数字是Integer.toHexString(hashCode())的结果,
前面的getClass().getName()我们容易理解,就是打印出这个类的完整的类名。
那后面的Integer.toHexString(hashCode());呢?我们先看看hashCode()这个方法:

public native int hashCode();

它是个本地方法,用于生产一个hash码,然后以生产的hash码作为参数来执行Integer类中的toHexString 静态方法,

//这个方法其实就是讲十进制的数转化为16进制的数的字符串表示
public static String toHexString(int i) {
    return toUnsignedString0(i, 4);
}

然后以hash码和4作为参数执行toUnsignedString方法返回它执行完成后的结果,这个方法其实就是讲十进制的数转化为16进制的数。
所以后面的一串数字其实就是生产的hash码的16进制的字符串表示。
我们可以进入toUnsignedString方法看看:
这个方法的作用是将整数转换成无符号数。

/**
 * Convert the integer to an unsigned number.
 */
private static String toUnsignedString0(int val, int shift) {
    // assert shift > 0 && shift <=5 : "Illegal shift value";
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];

    formatUnsignedInt(val, shift, buf, 0, chars);

    // Use special constructor which takes over "buf".
    return new String(buf, true);
}

下面我们来分析下这个方法的执行逻辑:
首先定义一个局部变量mag,他的值是本不变类中常量SIZE(32)和numberOfLeadingZeros(val)的和:(val就是hash码)

public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}

这个方法用于返回指定int值的二补二进制表示中最高(“最左”)位之前的零位数。
然后定义一个局部变量chars,它的值是前面算出来的mag和4通过后面的式子计算出来的值。
然后定义一个char数组buf,其大小就是chars。

然后以hash码,4,buf,0,chars作为参数执行formatUnsignedInt方法:
这个方法用于将一个长字符(视为无符号)格式化到字符缓冲区中

 static int formatUnsignedInt(int val, 
 int shift, char[] buf,  int offset, int len) {
    int charPos = len;
    int radix = 1 << shift;
    int mask = radix - 1;
    do {
        buf[offset + --charPos] = Integer.digits[val & mask];
        val >>>= shift;
    } while (val != 0 && charPos > 0);

    return charPos;
}

所以这个方法主要会给buf进行赋值。
最后返回以buf为内容的字符串对象打印出来也就是hash码的16进制表示。

4. 整型转二进制

说到整型转16进制,下面我们来了解下整型如何转二进制:

public static void main(String[] args) {
    byte a = -100;
    byte b = 100;
    //算法1
    String bri = Integer.toBinaryString((a & 0xFF) + 0x100).substring(1);
    //算法2,负数的二进制为正数的反码+1
    String bri1 = Integer.toBinaryString(~b+1);
    System.out.println(bri1.substring(bri1.length()-8));
    System.out.println(bri);
}

对于正数,我们可以直接调用Integer.toBinaryString(int n),但是对于负数,它得出的结果是错误的。
那么我们如何去得到一个负数的二进制表示呢? 实际上我们只要知道负数的二进制存储形式是:
对应正数的反码+1 , 然后根据这个规则进行计算即可。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌浏览器无法使用翻译功能的解决方案,谷歌浏览器无法翻译怎么办?谷歌浏览器右键翻译失效了?

如果你发现网站别的方案无效&#xff0c;请参考我的方案&#xff0c; 绝对有效&#xff01; 2022年起&#xff0c;突然发现谷歌浏览器的翻译功能无法使用了&#xff0c;既然发现问题&#xff0c;就要解决问题&#xff0c;按照下面的步骤一步一步来操作 首先下载最新版谷歌浏览…

[附源码]java毕业设计校园出入管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【Lua基础 第4章】Lua的流程控制、#的作用、table的创建方式、table表常用方法、函数、多返回值、可变长参数

文章目录&#x1f4a8;更多相关知识&#x1f447;一、Lua 的流程控制&#x1f538;if语句&#x1f31f;代码演示&#x1f538;if...else 语句&#x1f31f;代码演示&#x1f538;if...elseif...else 语句二、#的作用三、table的创建方式四、table表的常用方法使用&#x1f539;…

标记肽Suc-AAPI-pNA、72682-77-0

标记肽Suc-AAPI-对硝基苯胺编号: 184433 中文名称: 标记肽Suc-AAPI-对硝基苯胺 英文名: Suc-Ala-Ala-Pro-Ile-pNA CAS号: 72682-77-0 单字母: Suc-AAPI-pNA 三字母: Suc-Ala-Ala-Pro-Ile-pNA 氨基酸个数: 4 分子式: C27H38O9N6 平均分子量: 590.63 精确分子量: 590.27 等电点(P…

使用MobaXterm tunneling访问集群(服务器)jupyter notebook

应用场景 想要在本地计算机C上使用高性能服务器上的计算节点运行jupyter notebook相关的代码。 高性能服务器上通常只有一个公网ip用于账户登陆管理&#xff0c;但有多个计算节点&#xff0c;需要使用公网IP通过SSH方式登入管理节点A&#xff0c;并使用SSH二次登陆计算节点B&…

CKKS同态加密方案初步学习

如论文标题所示&#xff0c;CKKS允许复数和实数运算&#xff0c;是一个近似精度计算的方案&#xff0c;也就是解密出来的明文和加密之前的明文不会完全一致。也就是采用丢失部分精度来换取较高的效率。 CKKS的核心是把加密噪声视为近似计算误差的一部分&#xff0c;也就是解密出…

Python项目一:pygname

1.安装pip install pygame 2.加载模块初始化&#xff1a;开始 import sys import pygamepygame.init() #初始化3.创建窗口 3.1pygame .display模块 作用&#xff1a;创建游戏窗口 常见的内置方法&#xff1a; 方法作用 pygame。display.init() 初始化display模块p…

C++11标准模板(STL)- 算法(std::partial_sort)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 排序一个范围的前 N 个元素…

阿里巴巴最新总结「百亿级别并发设计手册」GitHub收获70K标星

随着淘宝购物节和抖音直播平台带货的火热&#xff0c;大批促销活动涌现&#xff0c;「秒杀」这个词也越来越频繁地出现在我们的生活里。 除了那些头部的电商公司&#xff0c;某多、某东&#xff0c;还有各种街、某会、某品等&#xff0c;甚至是一些老牌的传统企业&#xff0c;…

Android持久化技术,好内存不如烂存储

Android持久化技术&#xff0c;好内存不如烂存储前言六、Android持久化技术&#xff0c;好内存不如烂存储6.1 持久化技术介绍6.2 简单文件存储方案6.3 SharedPreferences存储方案6.3.1 获取SharedPreferences对象的三种方式6.3.2 使用SharedPreferences对象存储和读取数据6.4 S…

Model Fusion of Heterogeneous Neural Networks via Cross-Layer Alignment论文阅读

论文地址点这里 一. 介绍 本文是针对异构的网络融合技术&#xff0c;是基于上一篇OTFusion的论文进行的工作&#xff0c;解决了神经元关联问题。当所有的网络都具有相同的架构时&#xff0c;OTFusion比普通平均算法有明显的改进。与其他基于平均的模型融合方法相比&#xff0…

如何制作一个实时在线显示评论

通过循环容器及数据表功能&#xff0c;制作一个发送评论实时显示的功能 效果展示 具体步骤 制作评论背景 制作评论样式 制作一个发送评论输入框 制作一个发送按钮 创建评论数据表 添加获取评论事件 创建发送评论触发器 数据绑定与设置 步骤分解 制作评论背景 拖拽 循环容器 到…

Go基础学习【2】

文章目录一&#xff1a;数组二&#xff1a;map集合三&#xff1a;包四&#xff1a;结构体一&#xff1a;数组 1.命名 var arrAge [5]int{1,2,3,4,5} var arrAge […]int{1,2,4,5,6} var arrAge [5]string{3:“sfd”,5:“asdf”} 2.传递 通过传递数组的指针 和 使用数组的切片…

[go学习笔记.第十六章.TCP编程] 2.项目-海量用户即时通讯系统

一.项目介绍 1.项目开发流程 需求分析->设计阶段->编码实现->测试阶段->实施阶段 2.需求分析 (1).用户注册 (2).用户登录 (3).显示在线用户列表 (4).群聊(广播) (5).点对点聊天 (6).离线留言 3.示意图 4.项目开发前技术准备 项目要保存用户信息和消息数据,因此需…

【Vue】vue项目用qrcodejs2生成带log的二维码图片,vue生成二维码图片中间带log,自定义log

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录系列文章目录前言一、安装qrcodejs2二、在页面中使用1.引入…

英国Paper写作思路和精髓如何了解?

第一学期即将结束&#xff0c;为了能帮助更多英国留学生顺利完成Paper&#xff0c;增加对英国Paper写作的理解&#xff0c;取得高分。本文小编为大家分享英国Paper写作的思路和精髓&#xff0c;帮助自己修改提升Paper质量。 The first semester is coming to an end.In order t…

flutter AnimatedSwitcher 动画切换过渡组件 跑马灯动画封装

flutter AnimatedSwitcher 动画切换过渡组件前言一、AnimatedSwitcher 简介二、AnimatedSwitcher 的简单使用三、AnimatedSwitcher 自定义跑马灯动画四、SlideTransitionX 的封装总结前言 本篇文章将记录 AnimatedSwitcher 过渡组件&#xff0c;这个组件动画是一个新的小部件来…

制作一个简单HTML宠物猫网页(HTML+CSS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

在 Spring Boot中配置日志

Spring Boot 在引擎盖下使用Apache Commons Logging。但是&#xff0c;它允许您选择所需的日志记录库。让我们来看看使用 Spring Boot 时的一些配置和最佳实践。 目录 概述简单日志记录示例配置日志记录 更改日志级别将日志写入文件在 Spring 引导中更改日志记录模式对日志条…

基于小波域的隐马尔可夫树模型的图像去噪方法的matlab实现代码

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 为适应图像的空域非平稳变化, 提出了一种基于小波域分类隐马尔可夫树(CHMT)模型的图像去噪方法.该模型中,图像在每一尺度每一子带的小波系数均被分成C组以突出其空域非平稳变化 的特征,这…