《Effective Java》第4條:通過私有構造器強化不可實例化的能力

說明:

關于本博客使用的書籍,源代碼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…