Effective-Java-Chapter3

news2024/12/28 4:02:35

https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/dev/Chapter-3
在这里插入图片描述

准则一 覆盖 equals 方法时应遵守的约定

重写equals 方法需要满足的特性

  • Reflexive: For any non-null reference value x, x.equals(x) must return true.
    反身性:对于任何非空的参考值 x,x.equals(x) 必须返回 true。

  • Symmetric: For any non-null reference values x and y, x.equals(y) must return true if and only if y.equals(x) returns true.
    对称性:对于任何非空参考值 x 和 y,x.equals(y) 必须在且仅当 y.equals(x) 返回 true 时返回 true。

  • Transitive: For any non-null reference values x, y, z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) must return true.
    传递性:对于任何非空的引用值 x, y, z,如果 x.equals(y) 返回 true,y.equals(z) 返回 true,那么 x.equals(z) 必须返回 true。

  • Consistent: For any non-null reference values x and y, multiple invocations of x.equals(y) must consistently return true or consistently return false, provided no information used in equals comparisons is modified.
    一致性:对于任何非空的引用值 x 和 y, x.equals(y) 的多次调用必须一致地返回 true 或一致地返回 false,前提是不修改 equals 中使用的信息。

  • For any non-null reference value x, x.equals(null) must return false.
    对于任何非空引用值 x,x.equals(null) 必须返回 false。

高质量构建 equals 方法的秘诀
  • 使用 == 运算符检查参数是否是对该对象的引用。
  • 使用 instanceof 运算符检查参数是否具有正确的类型。
  • 将参数转换为正确的类型
  • 对于类中的每个「重要」字段,检查参数的字段是否与该对象的相应字段匹配。
    对于类型不是 float 或 double 的基本类型字段,使用 == 运算符进行比较;对于对象引用字段,递归调用 equals 方法;对于 float 字段,使用 static Float.compare(float,float) 方法;对于 double 字段,使用 Double.compare(double, double)。float 和 double 字段的特殊处理是由于 Float.NaN、-0.0f 和类似的双重值的存在而必须的;请参阅 JLS 15.21.1 或 Float.equals 文档。虽然你可以将 float 和 double 字段与静态方法 Float.equals 和 Double.equals 进行比较,这将需要在每个比较上进行自动装箱,这将有较差的性能。对于数组字段,将这些指导原则应用于每个元素。如果数组字段中的每个元素都很重要,那么使用 Arrays.equals 方法之一。

注意:写完 equals 方法后,问自己三个问题:它具备对称性吗?具备传递性吗?具备一致性吗?一般来说有IDE来为我们生成会更好。

准则二 当覆盖 equals 方法时,总要覆盖 hashCode 方法

为什么呢?
因为如果不覆写hashCode ,该类将违反 hashCode 方法的一般约定,这将阻止该类在 HashMap 和 HashSet 等集合中正常运行。

Map<Point, String> map = ImmutableBiMap.of(new Point(0, 0), "Origin", new Point(10, 10), "Point");
String val = map.get(new Point(0, 0));
System.out.println(val);

上面这段代码毫无疑问结果是null,但是这个逻辑上不对呀,在equals中我们坐标点相等说明这两个点就是同一个点,这个原因就是我们没有复写hashCode 导致的,相等的对象必须具有相等的散列码。
如果我们复写hashCode 我们就会发现上面的代码就能够输出Origin

@Override
public int hashCode() {
    return Objects.hash(x, y);
}

对于生成hashCode 有一套流程,也是书中提到的:
初始化哈希码:

  • 初始化一个 int 类型的哈希码变量,通常使用一个非零的质数作为初始值,比如 17 或者 31。
  • 计算字段的哈希值:
    对于类中的每个字段,计算一个哈希值。
    对于基本类型,直接使用其值或转换后的值。
    对于引用类型,调用其 hashCode 方法。
    对于数组,可以使用 Arrays.hashCode 方法。
  • 结合字段哈希值:
    使用某种算法(例如乘法和异或运算)将这些哈希值结合起来。
    通常的做法是使用一个质数(如 31)乘以前一个哈希值,再加上当前字段的哈希值。
  • 返回最终哈希码:
    返回计算出的 int 类型哈希码。

如果一个类是不可变的,并且计算散列码的成本非常高,那么你可以考虑在对象中缓存散列码,而不是在每次请求时重新计算它。如果你认为这种类型的大多数对象都将用作散列键,那么你应该在创建实例时计算散列码。同时需要注意线程安全问题。

// 示例这里没有去解决线程安全问题
@Override
public int hashCode() {
    int result = hashCode;

    if (result == 0) {
        result = Short.hashCode(areaCode);
        result = 31 * result + Short.hashCode(prefix);
        result = 31 * result + Short.hashCode(lineNum);
        hashCode = result;
    }

    return result;
}

注意事项:

  • 不要试图从散列码计算中排除重要字段,以提高性能。
    虽然得到的散列算法可能运行得更快,但其糟糕的质量可能会将散列表的性能降低到无法使用的程度。特别是,散列算法可能会遇到大量实例,这些实例在你选择忽略的不同区域。如果发生这种情况,散列算法将把所有这些实例映射很少一部分散列码,使得原本应该在线性阶 O(n) 运行的程序将在平方阶 O(n^2) 运行。
  • 不要为 hashCode 返回的值提供详细的规范,这样客户端就不能理所应当的依赖它。这(也)给了你更改它的余地。

准则三:始终覆盖 toString 方法

一般来说POJO才会覆盖这些方法,便于我们进行调试,如果对象过大就打印一些摘要信息。同样的对于工具类这种类,也不需要复写toString() 方法,因为这样做没有意义。

准则四:明智地覆盖 clone 方法

  • 首先克隆需要实现Cloneable 不然会抛出异常 CloneNotSupportedException
  • 由于Object 的clone方法是protected的,所以我们只能通过super关键字去调用,但是这样子类型会不对,因此有了以下的实现, 需要注意的是java默认的拷贝方法是浅拷贝:
@Override
protected Point clone() throws CloneNotSupportedException {
    return (Point)super.clone();
}

准则五 考虑实现 Comparable 接口

如果一个类有多个重要字段,那么比较它们的顺序非常关键。从最重要的字段开始,一步步往下。如果比较的结果不是 0(用 0 表示相等),那么就完成了;直接返回结果。
关于比较器书中不推荐下面这种写法,它们依赖于以下事实:如果第一个值小于第二个值,则两个值之间的差为负;如果两个值相等,则为零;如果第一个值大于零,则为正。

static Comparator<Object> hashCodeOrder = new Comparator<>() {
    public int compare(Object o1, Object o2) {
        return o1.hashCode() - o2.hashCode();
    }
};

书中更推荐:

static Comparator<Object> hashCodeOrder = new Comparator<>() {
    public int compare(Object o1, Object o2) {
        return Integer.compare(o1.hashCode(), o2.hashCode());
    }
};
static Comparator<Object> hashCodeOrder = Comparator
    .comparingInt(o -> o.hashCode());

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

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

相关文章

科普文:微服务之Spring Cloud Alibaba分布式事务组件Seata4种分布式事务模式及其选择

https://zhouxx.blog.csdn.net/article/details/140940976 科普文&#xff1a;微服务之Spring Cloud Alibaba分布式事务组件Seata设计方案-CSDN博客 一、概述 Seata是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata提供了AT、…

基于springboot+vue+uniapp的智慧校园管理系统小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

[网鼎杯 2018]Comment

使用环境为https://adworld.xctf.org.cn/challenges&#xff0c;搜索题目[网鼎杯 2018]Comment。 进入环境&#xff0c;发现为一个留言板&#xff0c;点击发帖试试。 尝试发帖 跳转到登录页面&#xff0c;根据提示使用burp进行暴力破解。 发现payload为666时状态码不同。 尝试…

【Flutter 自定义字体】等宽字体等

一般如果涉及自定义字体、等宽字体&#xff0c;我们通常使用到 Google 提供的&#xff1a;https://fonts.google.com/&#xff08;可能需要魔法&#xff09;&#xff0c; 1 如果是等宽字体&#xff0c;搜索关键词 ”mono“ 就会发现有很多&#xff1a; 2 我们可以直接选择第一…

nuScenes数据集及mmdetection3d中的相关处理

1. nuScence数据集简单介绍 数据集官网&#xff1a;https://www.nuscenes.org 论文&#xff1a;https://arxiv.org/abs/1903.11027 官方github页面&#xff1a;GitHub - nutonomy/nuscenes-devkit: The devkit of the nuScenes dataset. 1.1 坐标系的定义 nuScence数据集共…

cpp学习记录06:文件操作与模板

文件操作 对文件操作需要包含头文件<fstream> 文件类型&#xff1a; 文本文件&#xff1a;以文本ASCII码形式储存 二进制文件&#xff1a;以文本的二进制形式储存 操作文件三大类&#xff1a; ofstream&#xff1a;写操作 ifstream&#xff1a;读操作 fstream&…

以知识图谱结构为Prompt框架,帮LLM快速找出因果关系生成更精准内容

因果关系提取一直是LLM领域一个热门的研究方向&#xff0c;正如我上一篇文章中介绍的&#xff0c;我们在制定决策和科学研究时&#xff0c;往往需要LLM具有非常稳健的因果推理能力。幸运的是&#xff0c;恰巧知识图谱结构作为Prompt(“KG Structure as Prompt”&#xff09;能够…

做一个能和你互动玩耍的智能机器人之六-装配

openbot小车&#xff0c;最简单的配件。一个小车支架或者底盘&#xff0c;四个马达&#xff0c;最好是双层的&#xff0c;下层安装马在&#xff0c;上层电池和电源盒&#xff0c;L298N&#xff0c;arduino&#xff0c;手机支架&#xff0c;根据需要配置蓝牙&#xff0c;超声波等…

Arrays、Lambda表达式、Collection集合

1. Arrays 1.1 操作数组的工具类 方法名说明public static String toString(数组)把数组拼接成一个字符串public static int binarySearch(数组,查找的元素)二分查找法查找元素public static int[] copyOf(原数组,新数组长度)拷贝数组public static int[] copyOfRange(原数组…

接口自动化测试mock框架模块实战

前言 mock的介绍 py3已将mock集成到unittest库中&#xff1b; 为的就是更好的进行单元测试&#xff1b; 简单理解&#xff0c;模拟接口返回参数&#xff1b; 通俗易懂&#xff0c;直接修改接口返回参数的值&#xff1b; mock的作用 1、解决依赖问题&#xff0c;达到解耦作用…

基于Spring前后端分离版本的论坛

基于Spring前后端分离版本的论坛系统 PP论坛地址系统设计逻辑交互图数据库设计工程结构概述注册功能实现展示注册交互图参数要求接口规范后端具体实现前端数据集成 接口拦截器实现mybatis生成类与映射文件改造session存储到 redis加盐算法实现部分Bug调试记录项目测试记录Postm…

关于正点原子imx6ull-mini在写触摸驱动时,一直挂载不上驱动,就是没有一些信息反馈

/** 设备树匹配表 */ const struct of_device_id gt9147_of_match_table[] {{.compatible "goodix,gt9147" },{ /* sentinel */ } };const struct of_device_id gt9147_of_match_table[] {{.compatible "goodix&#xff0c;gt9147"},{} }; 找了俩小时…

高频面试题全攻略:从算法到解题技巧

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

基于宝塔面板稳定快速安装 ssl 证书脚本

背景 我通过AI制作了不少关于签发ssl证书的脚本&#xff0c;目的是方便无脑安装&#xff0c;不需要懂代码。 但全都是基于acme.sh这个工具来设计的脚本&#xff0c;而且证书申请有点慢&#xff0c;有时还会申请失败。 然后我发现了certbot, 安装证书可谓神速&#xff01; c…

[米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-04 IP层程序设计

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

全面解析PHP反序列化漏洞:原理、复现与防御

文章目录 概念序列化数据的含义魔术方法魔术方法的使用construct&#xff0c;destructtoStringcallgetsetsleepwakeupissetunsetinvoke 原生态反序列化漏洞概念种类复现 wakeup长度绕过产生原因条件复现 基本题型源码解读 在Web应用安全领域&#xff0c;PHP反序列化漏洞常常被视…

Tomcat 使用和配置文件(详解)

一.tomcat 介绍 1. tomcat 概述 自从JSP发布之后&#xff0c;推出了各式各样的JSP引擎。Apache Group在完成GNUJSP1.0的开发以后&#xff0c;开始考虑在SUN的JSWDK基础上开发一个可以直接提供Web服务的JSP服务器&#xff0c;当然同时也支持 Servlet&#xff0c;这样Tomcat就诞…

MySQL数据库误删恢复--超详细

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

Tensorflow——第三讲神经网络八股

前两讲我们学习了使用tensorflow原生代码搭建神经网络&#xff0c;本讲主要学习使用Tensorflow API&#xff1a;tf.keras搭建神经网络 一、搭建网络八股Sequential 六步法&#xff1a; 1.import&#xff1a;import 相关模块&#xff0c;如 import tensorflow as tf 2.train…

2024年7月30日~2024年8月5日周报

一、前言 上周继续修改论文&#xff0c;并阅读了两篇论文。 本周主要修改论文、完成实验、参加一些组会与论文讨论会&#xff0c;并配置了torch环境。 二、完成情况 2.1 论文符号系统注意事项 数学符号应该有唯一性&#xff0c;不能与其他符号造成误解&#xff1b;W_{\mathr…