软件构造 | Equality in ADT and OOP

软件构造 | Equality in ADT and OOP

🧇1 Three ways to regard equality

1.1 Using AF to define the equality

ADT是对数据的抽象, 体现为一组对数据的操作

抽象函数AF:内部表示→抽象表示

基于抽象函数AF定义ADT的等价操作,如果AF映射到同样的结果,则等价

1.2 Using observation to define the equality

​ 站在外部观察者角度:对两个对象调用任何相同的操作,都会得到相同的结果,则认为这 两个对象是等价的。

在这里插入图片描述

1.3 == vs. equals()

== 引用等价性 : 对基本数据类型,使用==判定相等

equals() 对象等价性 : 对对象类型,使用equals()

在自定义ADT时,需要根据对“等价”的要求, 决定是否重写Object的equals()

1.4 Implementing equals()

The equals() method is defined by Object , and its default implementation looks like this:

在这里插入图片描述

Note:在Object中实现的默认equals()是在判断引用等价性,这通常不是程序员所期望的,因此,需要重写。

public classDuration {
    ...
    // Problematic definition of equals()
    public boolean equals(Duration that) {
		return this.getLength() == that.getLength();
    }
}

错误声明equal:实现的是重载而不是重写。

在这里插入图片描述

正确声明

在这里插入图片描述

在 Java 中,equals() 方法是用于比较两个对象是否相等的方法。在 Java 中,所有的类都继承自 Object 类,而 Object 类中的 equals() 方法默认实现是比较两个对象的引用是否相同(即比较内存地址)。因此,当需要在自定义类中比较对象内容时,通常需要重写 equals() 方法。

下面是一个示例,展示了如何重写 equals() 方法来比较自定义类中的对象内容:

class Person {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true; // 如果是同一个对象,直接返回true
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false; // 如果对象为null或者是不同类的实例,直接返回false
        }
        Person person = (Person) obj; // 强制转换为Person类
        return age == person.age && name.equals(person.name); // 比较name和age是否相等
    }

    // 省略 getter 和 setter 方法
}

public class Example {
    public static void main(String[] args) {
        Person person1 = new Person("Alice", 30);
        Person person2 = new Person("Alice", 30);

        System.out.println(person1.equals(person2)); // 输出true,因为内容相同
    }
}

在上面的示例中,Person 类重写了 equals() 方法,根据对象的 nameage 属性来比较两个 Person 对象是否相等。在 equals() 方法中,首先比较对象引用是否相同,然后再比较类和属性是否相同。

需要注意的是,在重写 equals() 方法时,通常需要同时重写 hashCode() 方法,以确保两个方法的一致性。这样可以保证对象在放入基于散列的集合(如 HashMapHashSet)时能够正确地根据对象内容对其进行存储和检索。

🍕 2The Object contract(对象合同)

  1. 等价关系:自反、传递、对称。
  2. 除非对象被修改了,否则调用多次equals应是同样的结果。
  3. “相等”的对象,其hashCode()的结果必须一 致。

Note:用“是否为等价关系”检验你的equals()是否正确

2.1 Hash Tables

在这里插入图片描述

Object ’s default hashCode() implementation is consistent with its default equals()

在这里插入图片描述

键值对中的 key被映射为hashcode,对应到数组的index, hashcode决定了数据被存 储到数组的哪个位置

2.2 Overriding hashCode()

在 Java 中,每个对象都有一个 hashCode,它是对象的哈希码,用于确定对象在哈希表等数据结构中的存储位置。hashCode 的作用是为了更高效地进行对象的存储和检索,特别是在使用基于散列的集合(如 HashMapHashSet)时非常重要。

hashCode 方法的设计要求是:

  1. 如果两个对象通过 equals() 方法相等,则它们的 hashCode 必须相等。
  2. 如果两个对象的 hashCode 相等,它们并不一定通过 equals() 方法相等。

在实现类中重写 hashCode 方法时,通常需要保证满足上述两个要求。通常情况下,可以利用对象的属性来生成 hashCode 值,这样可以确保同样属性的对象具有相同的 hashCode

最简单方法:让所有对象的hashCode为同一 常量,符合contract,但降低了hashTable效率

通过 equals计算中用到的所有信息的hashCode组合出新的hashCode

在 Java 中,当两个对象通过 equals() 方法相等且具有相同的 hashCode 值时,如果将这两个对象放入基于散列的集合(如 HashMapHashSet)中,只会存储一个对象。这是因为散列集合在存储对象时会先根据 hashCode 值确定对象在内部数据结构中的存储位置,然后再通过 equals() 方法来判断具体位置是否已经存在相同的对象。

具体来说,当向散列集合中添加一个对象时,首先会计算该对象的 hashCode 值,然后根据 hashCode 值找到对象在内部存储结构中的位置。如果在该位置处已经有一个对象存在,并且这个对象与新添加的对象通过 equals() 方法比较相等(即返回 true),那么新添加的对象不会被存储,以保证集合中不会存在重复的对象。

下面是一个简单示例,演示了两个相等的对象具有相同 hashCode 值时,只存储一个对象的情况:

import java.util.HashMap;
import java.util.Map;

class Person {
    private String name;
    private int age;

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

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

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof Person)) {
            return false;
        }
        Person other = (Person) obj;
        return this.name.equals(other.name) && this.age == other.age;
    }
}

public class Example {
    public static void main(String[] args) {
        Map<Person, String> personMap = new HashMap<>();

        Person person1 = new Person("Alice", 30);
        Person person2 = new Person("Alice", 30);

        personMap.put(person1, "Value 1");
        personMap.put(person2, "Value 2");

        System.out.println(personMap.size()); // 输出 1,因为两个对象相等且具有相同的 hashCode
    }
}

在上面的示例中,Person 类重写了 equals()hashCode() 方法,确保在两个对象具有相同属性值时返回 true 并且具有相同的哈希码。当将这两个相等的对象放入 HashMap 中时,只会存储一个对象,因为它们具有相同的 hashCode 值。因此,最终输出的大小是 1

Always override hashCode() when you override equals()

除非你能保证你的ADT不会被放入到Hash类型的集合类中

🍿 3引用的概念

在 Java 中,引用是指向对象的指针或句柄。在 Java 中,所有对象都是通过引用来操作的,而不是直接访问对象本身。当您创建一个对象时,实际上是在堆内存中为该对象分配了空间,并返回一个引用,这个引用指向堆中的对象。Java 的引用是一种高级抽象概念,开发人员无法直接控制对象所在的内存位置,只能通过引用去访问和操作对象。

与此相对应,C 语言中的指针是直接指向内存地址的变量。在 C 中,通过指针可以直接访问或修改内存地址中的数据。指针在 C 语言中被广泛用于实现动态内存分配、访问数组元素、操作数据结构等。

下面是一个简单的示例来对比 Java 中的引用和 C 中的指针:

在 Java 中:

public class Example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = str1;
        
        System.out.println(str1); // Hello
        System.out.println(str2); // Hello
        
        str2 = "World";
        
        System.out.println(str1); // Hello
        System.out.println(str2); // World
    }
}

在这个示例中,str1str2 都是对象的引用,它们最初都指向同一个字符串对象"Hello"。当我们修改 str2 的值时,它指向了一个新的字符串对象"World",但str1 仍然指向原来的字符串对象"Hello"。

在 C 中:

#include <stdio.h>

int main() {
    int var = 10;
    int* ptr = &var;
    
    printf("Original value: %d\n", var); // 10
    printf("Value through pointer: %d\n", *ptr); // 10
    
    *ptr = 20;
    
    printf("Updated value: %d\n", var); // 20
    printf("Value through pointer: %d\n", *ptr); // 20
    
    return 0;
}

在这个示例中,ptr 是一个指向 var 变量的指针。通过 *ptr 可以访问或修改 var 的值。在这段代码中,我们通过指针修改了 var 的值,而不是通过变量名 var 直接修改。

综上所述,Java 中的引用是指向对象的抽象概念,开发者无法直接操作对象的内存地址,只能通过引用访问对象;而 C 中的指针直接指向内存地址,开发者可以直接控制和操作内存地址中的数据。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何确保远程桌面安全

在数字化快速发展的今天&#xff0c;远程桌面技术广泛应用于企业办公、技术支持以及个人使用等领域。然而&#xff0c;随之而来的安全问题也不容忽视。白名单技术作为一种重要的安全防护手段&#xff0c;在确保远程桌面安全方面发挥着至关重要的作用。 一、白名单技术概述 白名…

[Qt] Qt Creator 以及 Qt 在线安装教程

一、Qt Creator 下载及安装 1、从以下镜像源下载安装包常规安装即可 Qt Creator 也可以在第二步Qt 在线安装时一次性勾选安装&#xff0c;见后文 Qt Creator 中科大源下载地址 二、Qt 在线安装 1、根据所在平台选择对应的安装器下载 Qt 在线安装器下载 2、可能的安装报错…

[华为北向网管NCE开发教程(6)消息订阅

1.作用 之前介绍的都是我们向网管NCE发起请求获取数据&#xff0c;消息订阅则反过来&#xff0c;是网管NCE系统给我们推送信息。其原理和MQ&#xff0c;JMS这些差不多&#xff0c;这里不过多累述。 2.场景 所支持订阅的场景有如下&#xff0c;以告警通知为例&#xff0c;当我…

建筑工程软件Revit中复杂大模型如何实现Web端轻量化?| HOOPS技术应用

建筑信息模型&#xff08; BIM&#xff09;技术在建筑工程中扮演着越来越重要的角色&#xff0c;而Autodesk Revit作为主流的BIM软件&#xff0c;被广泛应用于设计、施工和管理。然而&#xff0c;Revit生成的复杂大模型常常由于数据量庞大而难以直接在Web端展示和操作。这时&am…

linux日志管理之journalctl命令

一、日志查询 1.输出所有日志或按相关要求输出 输出所有日志 #journalctl查看实时日志 #journalctl -f查看最后n行 #journalctl -n 10不分页显示 #journalctl --no-pager适合阅读模式 #journalctl -p 3 -o json-pretty 查看内核日志 #journalctl -k 2.按服务查询 #journal…

植物大战僵尸杂交版最新pvzHE_v2.1.0含游戏窗口放大工具

植物大战僵尸杂交版是由B站”潜艇伟伟迷”UP主制作的一款同人策略塔防游戏&#xff0c;也叫pvzHE&#xff0c;该游戏由《植物大战僵尸》原版魔改而来&#xff0c;引入了创新的杂交合成系统&#xff0c;让玩家可以将不同植物进行杂交&#xff0c;创造出具有全新能力和外观的植物…

【低级错误笔记】debug的步入按钮为灰色

访问login方法没有加RestController 难怪点击登录的时候总是显示404资源错误 看到闪过一秒的无法访问/employee/login路径才发现这个思路……………………………………………………………………………………………………………………………………太无语了 拖拖拉拉从6.3到今天…

Digital Video Repair3.7.1.0 --一款免费的视频文件修复工具,供大家学习研究参考

下载地址&#xff1a; https://download.csdn.net/download/weixin_43097956/89431959

领夹麦克风哪个品牌音质最好?轻揭无线麦克风哪个品牌性价比高!

​随着短视频热潮的兴起&#xff0c;越来越多的人倾向于用vlog记录日常生活&#xff0c;同时借助短视频和直播平台开辟了副业。在这一过程中&#xff0c;麦克风在近两年内迅速发展&#xff0c;从最初的简单收音功能演变为拥有多样款式和功能&#xff0c;以满足视频创作的需求。…

用 微 / 积分思想妙解关于等比数列的和

同理&#xff0c;也是微积分思想&#xff1a; 求 (\sum_{k1}^n q^k) 的和&#xff1a; 我们知道几何级数的求和公式&#xff1a; ∑ k 0 n q k 1 − q n 1 1 − q (对于 q ≠ 1 ) \sum_{k0}^n q^k \frac{1-q^{n1}}{1-q} \quad \text{(对于 } q \neq 1\text{)} k0∑n​qk…

算法02 递归算法及其相关问题【C++实现】

递归 在编程中&#xff0c;我们把函数直接或者间接调用自身的过程叫做递归。 递归处理问题的过程是&#xff1a;通常把一个大型的复杂问题&#xff0c;转变成一个与原问题类似的&#xff0c;规模更小的问题来进行求解。 递归的三大要素 函数的参数。在用递归解决问题时&…

如何了解基金的估值

一、优秀的估值产品 钉大在《定投十年 财务自由》和《指数基金投资指南》中不止一次提到过要「结合估值来投资」&#xff0c;为此&#xff0c;他每个交易日他的公众号「银行螺丝钉」中都会发布他编制的基金估值表&#xff0c;最新的一期已经是第2281期了。 这是钉大昨天&#x…

一文快速认识环形光源——CCS光源

机器视觉系统中&#xff0c;光源起着重要作用&#xff0c;不同类型的光源应用也不同&#xff0c;选择合适的光源成像效果非常明显。今天我们一起来看看CCS光源——工业用环形光源LDR2系列。 LDR2系列是标准的环形光源&#xff0c;通过采用柔性基板&#xff0c;可创造任意角度。…

CPRI协议的理解——CPRI中的扰码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 CPRI协议的理解——CPRI中的扰码 前言8B10B线路编码下的扰码发送端接收 64B66B线路编码下的扰码带有终止控制字符的控制块格式带有起始控制字符的控制块格式数据块格式 前言 …

9种编程语言的对比分析

在当今的软件开发领域&#xff0c;编程语言扮演着至关重要的角色。不同的编程语言各有其特点和适用场景&#xff0c;选择合适的编程语言能够提高开发效率和软件质量。本文将对十种常见的编程语言进行对比分析&#xff0c;帮助读者了解它们的优缺点和适用场景。 Java 特点&…

中小企业使用CRM系统的优势有哪些

中小企业如何在竞争激烈的市场中脱颖而出&#xff1f;除了优秀的产品和服务&#xff0c;一个高效的管理工具也是必不可少的。而客户关系管理&#xff08;CRM&#xff09;系统正是这样一个能帮助企业提升客户体验、优化内部管理流程的重要工具。接下来&#xff0c;让我们一起探讨…

freemarker 使用

首次使用freemarker遇到的全是坑,还好,各种问题,最终都解决了。芹菜加油 import com.lowagie.text.pdf.BaseFont; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.Byte…

喜讯 | 全视通获得珠海市第七届“市长杯”工业设计大赛三等奖

近日&#xff0c;在珠海市举行的第七届“市长杯”工业设计大赛颁奖典礼上&#xff0c;珠海全视通信息技术有限公司&#xff08;以下简称“全视通”&#xff09;凭借创新的“医护对讲一体终端机”产品&#xff0c;历经激烈的竞争和严格的评选流程&#xff0c;包括大赛宣传发动、…

python-docx-template 的 Replace docx pictures 占位图片名称从哪来?

python-docx-template 的 Replace docx pictures 占位图片名称从哪来&#xff1f; 在 Word 中看占位图片名称用代码输出输出结果找对应图片 使用 replace_pic参考资料 在 Word 中看占位图片名称 右键图片 》查看可选文字 用代码输出 from docxtpl import DocxTemplate# 初始化…

二刷算法训练营Day30 | 回溯算法(6/6)

目录 详细布置&#xff1a; 1. 回溯总结 2. 332. 重新安排行程 3. 51. N 皇后 4. 37. 解数独 详细布置&#xff1a; 1. 回溯总结 回溯是递归的副产品&#xff0c;只要有递归就会有回溯&#xff0c;所以回溯法也经常和二叉树遍历&#xff0c;深度优先搜索混在一起&#x…