说明:

关于本博客使用的书籍,源代码Gitee仓库 和 其他的相关问题,请查看本专栏置顶文章:《Effective Java》第0条:写在前面,用一年时间来深度解读《Effective Java》这本书

正文:

原文P15:有时可能需要编写只包含静态方法和静态域的类。

比如一些公共的常量类(如下代码,电商平台货物的状态),这些类我们不需要实例化他们的对象,直接调用静态成员变量或者方法即可。所以可以通过私有化构造器,“强化不可实例化的能力”

// GoodsStatus类
public class GoodsStatus {private GoodsStatus() {}public static final String PENDING_PAYMENT = "待付款";public static final String TO_BE_SHIPPED = "待发货";public static final String SHIPPED = "已发货";public static final String RECEIVED = "已收货";// 退货public static String returnGoods(String goodStatus) {// 只有已收货的情况下可以退货return RECEIVED.equals(goodStatus) ? "退货成功" : "退货失败";}
}

原文P15:我们可以利用这种类,以java.lang.Math或者java.util.Arrays的方式,把基本类型的值或者数组类型上的相关方法组织起来。我们也可以通过java.util.Collections的方式,把实现特定接口的对象上的静态方法,包括工厂方法(详见第1条)组织起来。

java.lang.Math类 和 java.util.Arrays类,就像上例一样,只包含静态方法和静态域(请大家自行查看源码),用来处理数学计算(三角函数,对数,开根号等) 和 处理数组(排序,对比,复制等)的一些操作。

java.util.Collections类,则是服务于所有实现了Collection接口的类,其中包括类似于EmptyList、EmptyMap、SingletonSet等等,一些工厂方法。还包括size、isEmpty、sort等等,一系列的工具类方法。

原文P15:从Java8开始,也可以把这些方法放进接口中,假定这是你自己编写的接口可以进行修改

比如上面的例子,电商平台货物的状态,也可以通过接口来写,而且更加方便,我也更加推荐大家使用这种方式来写公共的常量类,因为接口里的常量默认都是public static final的,不用再去写了,如下代码

// GoodsStatus2 接口
public interface GoodsStatus2 {// 可以省略 public static finalString PENDING_PAYMENT = "待付款";String TO_BE_SHIPPED = "待发货";String SHIPPED = "已发货";String RECEIVED = "已收货";// 退货,可以省略public,因为默认就是public的static String returnGoods(String goodStatus) {// 只有已收货的情况下可以退货return RECEIVED.equals(goodStatus) ? "退货成功" : "退货失败";}
}

原文P15:还可以利用这种类把fina类上的方法组织起来,因为不能把它们放在子类中

当我们需要将多个final类(无法被继承)的方法组织起来统一管理时,可以使用单例类作为 "工具整合器",集中封装这些final类的功能,提供统一的访问入口。这种方式适合整合多个独立的工具类,简化调用逻辑。

// MyDateUtils final类
final class MyDateUtils {// 私有构造器,禁止实例化private MyDateUtils() {}// 格式化日期public static String formatDate(LocalDate date) {return date.format(DateTimeFormatter.ISO_LOCAL_DATE);}// 解析日期字符串public static LocalDate parseDate(String dateStr) {return LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);}
}// MyStringUtils final类
final class MyStringUtils {// 私有构造器,禁止实例化private MyStringUtils() {}// 检查字符串是否为空public static boolean isEmpty(String str) {return str == null || str.trim().isEmpty();}// 反转字符串public static String reverse(String str) {if (isEmpty(str)) return str;return new StringBuilder(str).reverse().toString();}
}// 单例模式将上述两个工具类组合
public class ToolkitSingleton {// 单例实例private static final ToolkitSingleton INSTANCE = new ToolkitSingleton();// 私有构造器private ToolkitSingleton() {}// 获取单例public static ToolkitSingleton getInstance() {return INSTANCE;}// 整合DateUtils的方法public String formatDate(LocalDate date) {return MyDateUtils.formatDate(date); // 调用final类的静态方法}public LocalDate parseDate(String dateStr) {return MyDateUtils.parseDate(dateStr);}// 整合StringUtils的方法public boolean isEmpty(String str) {return MyStringUtils.isEmpty(str);}public String reverseString(String str) {return MyStringUtils.reverse(str);}// 甚至可以组合多个final类的功能,形成新功能// 转换并格式化时间public String reverseFormattedDate(String dateStr) {if (isEmpty(dateStr)) return "";LocalDate date = parseDate(dateStr);String formatted = formatDate(date);return reverseString(formatted);}
}// Main 类
// 获取单例
ToolkitSingleton toolkit = ToolkitSingleton.getInstance();
// 使用整合后的日期功能
LocalDate date = LocalDate.of(2024, 8, 19);
System.out.println("格式化日期:" + toolkit.formatDate(date));
// 使用整合后的字符串功能
String str = "hello";
System.out.println("反转字符串:" + toolkit.reverseString(str));
// 使用组合功能
System.out.println("反转格式化日期:" + toolkit.reverseFormattedDate("2024-08-19"));

原文P15:这样的工具类(utilityclass)不希望被实例化,因为实例化对它没有任何意义。然而在缺少显式构造器的情况下,编译器会自动提供一个公有的、无参的缺省构造器(defaulconstructor)。

所以我们要私有化构造器,来防止这样的工具类被实例化。

那么除私有化构造器之外,使用抽象类可不可以防止工具类被实例化呢?

原文P15:企图通过将类做成抽象类来强制该类不可被实例化是行不通的。该类可以被子类化,并且该子类也可以被实例化。这样做甚至会误导用户,以为这种类是专门为了继承而设计的(详见第19条)。

也就是说,首先抽象类不能防止工具类被实例化,因为继承它的子类可以被实例化。其次,抽象类还会被误解为是一个专门用来被继承的类,实际上我们的目的并不是需要它被继承。所以,不能用抽象类。

原文P16:由于显式的构造器是私有的,所以不可以在该类的外部访问它。AssertionError不是必需的,但是它可以避免不小心在类的内部调用构造器。它保证该类在任何情况下都不会被实例化。这种习惯用法有点违背直觉,好像构造器就是专门设计成不能被调用一样。因此,明智的做法就是在代码中增加一条注释,如下面代码所示。

// UtilityClass类
// Noninstantiable utility class(不可实例化的工具类)
public class UtilityClass {// Suppress default constructor for noninstantiability(抑制默认构造器)// 私有化构造器,防止被实例化private UtilityClass() {// 主要防止反射破坏单例模式throw new AssertionError();}// ......
}

throw new AssertionError(); 在这里的作用主要是防止反射破坏单例,看过第3条的同学应该有印象。

那么最后,这种用法有没有弊端呢?

原文P16:这种习惯用法也有副作用,它使得一个类不能被子类化。所有的构造器都必须显式或隐式地调用超类(superclass)构造器,在这种情形下,子类就没有可访问的超类构造器可调用了

也就是说,弊端就是被私有化构造器的类,不能被继承了,相当于是违背了Java的三大思想中的一个,不过没关系,我们之所以这么用,目的也不是为了让子类继承,更多的是需要一个工具来帮我们做事情,所以,该怎么用就怎么用吧!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20.Linux进程信号(一)

信号: 产生->保存->处理一、预备知识信号vs信号量->没有任何关系什么叫做信号?中断我们正在做的事情,是一种事件的异步通知机制。同步和异步理解:同步指事件发生具有一定的顺序性(如命名管道中服务端读方式打开会阻塞&am…

【C++】Vector核心实现:类设计到迭代器陷阱

vector 模拟实现代码的核心下面从类设计、核心接口、内存安全、常见陷阱、测试场景5 个维度,提炼需重点掌握的知识点,覆盖面试高频考点与实践易错点:一、类结构与成员变量(基础框架)vector 的核心是通过三个迭代器&…

并发编程指南 内存模型

文章目录5.1 内存模型5.1.1 对象和内存位置5.1.2 对象、内存位置和并发5.1.3 修改顺序5.1 内存模型 内存模型:一方面是内存布局,另一方面是并发。并发的基本结构很重要,特别是低层原子操作。因为C所有的对象都和内存位置有关,所以…

血缘元数据采集开放标准:OpenLineage Integrations Compatibility Tests Structure

OpenLineage 是一个用于元数据和血缘采集的开放标准,专为在作业运行时动态采集数据而设计。它通过统一的命名策略定义了由作业(Job)、运行实例(Run)和数据集(Dataset) 组成的通用模型&#xff0…

执行一条select语句期间发生了什么?

首先是连接器的工作,嗯,与客户端进行TCP三次握手建立连接,校验客户端的用户名和密码,如果用户名和密码都对了,那么就会检查该用户的权限,之后执行的所有SQL语句都是基于该权限接着客户端就可以向数据库发送…

element el-select 默认选中数组的第一个对象

背景&#xff1a;在使用element组件的时候&#xff0c;我们期望默认选中第一个数值。这里我们默认下拉列表绑定的lable是中文文字&#xff0c;value绑定的是数值。效果展示&#xff1a;核心代码&#xff1a;<template><el-select v-model"selectValue" plac…

【论文阅读】LightThinker: Thinking Step-by-Step Compression (EMNLP 2025)

论文题目&#xff1a;LightThinker: Thinking Step-by-Step Compression 论文来源&#xff1a;EMNLP 2025&#xff0c;CCF B 论文作者&#xff1a; 论文链接&#xff1a;https://arxiv.org/abs/2502.15589 论文源码&#xff1a;https://github.com/zjunlp/LightThinker 一、…

ABAQUS多尺度纤维增强混凝土二维建模

本案例是通过ABAQUS对论文Study on the tensile and compressive mechanical properties of multi-scale fiber-reinforced concrete: Laboratory test and mesoscopic numerical simulation&#xff08;https://doi.org/10.1016/j.jobe.2024.108852&#xff09;中纤维增强混凝…

C++ ---- 模板的半特化与函数模板的偏特化

在 C 中&#xff0c;模板提供了一种强大的泛型编程方式&#xff0c;使得我们能够编写类型无关的代码。然而&#xff0c;在实际使用中&#xff0c;有时我们需要根据具体的类型或类型组合对模板进行定制&#xff0c;这时就需要用到模板的特化。本文将介绍半模板特化和函数模板的偏…

为何 React JSX 循环需要使用 key

key 是 React 用于识别列表中哪些子元素被改变、添加或删除的唯一标识符 它帮助 React 更高效、更准确地更新和重新渲染列表 1、核心原因&#xff1a;Diff算法与性能优化 React 的核心思想之一是通过虚拟 DOM (Virtual DOM) 来减少对真实 DOM 的直接操作&#xff0c;从而提升性…

Jetson AGX Orin平台R36.3.0版本1080P25fps MIPI相机图像采集行缺失调试记录

1.前言 主板:AGX Orin 官方开发套件 开发版本: R36.3.0版本 相机参数如下: 相机硬件接口: 2. 梳理大致开发流程 核对线序/定制相机转接板 编写camera driver驱动 编写camera dts配置文件 调camera参数/测试出图 前期基本流程就不多介绍了直接讲正题 3. 问题描述 …

力扣hot100:螺旋矩阵(边界压缩,方向模拟)(54)

在解决螺旋矩阵问题时&#xff0c;我们需要按照顺时针螺旋顺序遍历矩阵&#xff0c;并返回所有元素。本文将分享两种高效的解决方案&#xff1a;边界收缩法和方向模拟法。题目描述边界收缩法边界收缩法通过定义四个边界&#xff08;上、下、左、右&#xff09;来模拟螺旋遍历的…

[嵌入式embed][Qt]Qt5.12+Opencv4.x+Cmake4.x_用Qt编译linux-Opencv库 测试

[嵌入式embed][Qt]Qt5.12Opencv4.xCmake4.x_用Qt编译linux-Opencv库 & 测试前文:准备环境安装qt-opencv必备库git-clone opencv库编译opencv库特殊:opencv编译的include,编译出来后多嵌套了一层文件夹,手工处理下改为include/opencv2测试demo新建项目QOpencv3.promain.cpp百…

百度智能云「智能集锦」自动生成短剧解说,三步实现专业级素材生产

备受剪辑压力困扰的各位自媒体老板、MCN 同学们、投放平台大佬们&#xff0c;解放双手和大脑的好机会它来了&#xff01; 在这个数字化飞速发展的时代&#xff0c;智能技术正以前所未有的速度改变着我们的生活与工作方式。百度智能云&#xff0c;作为智能科技的引领者&#xf…

FPGA笔试面试常考问题及答案汇总

经历了无数的笔试面试之后&#xff0c;不知道大家有没有发现FPGA的笔试面试还是有很多共通之处和规律可循的。所以一定要掌握笔试面试常考的问题。FPGA设计方向&#xff08;部分题目&#xff09;1. 什么是同步逻辑和异步逻辑&#xff1f;同步逻辑 是指在同一个时钟信号的控制下…

从0开始的github学生认证并使用copilot教程(超详细!)

目录 一.注册github账号 1.1、仅仅是注册 1.2、完善你的profile 二、Github 学生认证 邮箱 学校名称 How do you plan to use Github? Upload Proof 学校具体信息 一.注册github账号 1.1、仅仅是注册 1.用如QQ邮箱的第三方邮箱注册github 再添加.edu结尾的教育邮箱&…

自动驾驶叉车与 WMS 集成技术方案:数据交互、协议适配与系统对接实现

自动驾驶叉车与仓库管理系统&#xff08;WMS&#xff09;是现代物流自动化的核心。当这两项技术协同工作时&#xff0c;仓库将实现前所未有的效率、准确性和可扩展性。以下是利用其集成实现最佳效果的方法。 为何集成至关重要 仓库管理在当今运营中扮演着至关重要的角色&…

“企业版维基百科”Confluence

“企业版维基百科”Confluence Confluence 是一款由澳大利亚公司 Atlassian 开发的企业级团队协作与知识管理软件。您可以把它理解为一个功能非常强大的 “企业版维基百科” 或 “团队知识库”。 它的核心目标是帮助团队在一个统一的平台上创建、共享、组织和讨论项目文档、会议…

QT去除显示的红色和黄色下划线的办法

在使用 Qt Creator 开发项目时,有时候会遇到这样的情况: 代码明明没有错误,但编辑器里却出现了红色或黄色的下划线提示,甚至让人误以为代码有问题。其实,这通常是 Qt Creator 的代码模型没有及时更新 导致的,而不是项目本身的错误。 为什么会出现红色和黄色下划线? 红…

域内的权限提升

CVE-2020-1472域内有一个服务&#xff1a;MS-NRPC&#xff08;建立与域控安全通道&#xff09;&#xff0c;可利用此漏洞获取域管访问权限。检测这个漏洞能不能打&#xff0c;能打之后&#xff0c;将域控的机器hash置空&#xff0c;密码为空&#xff0c;那么你就可以通过空的ha…