[Java 基礎]Object 類

java.lang.Object 是 Java 所有類的直接或間接父類,Java 中每個類都默認繼承 Object 類(即使你沒寫 extends Object)。

Object 中的常用方法:

方法名功能簡介
toString()返回對象的字符串表示
equals(Object)判斷兩個對象是否“邏輯相等”
hashCode()返回哈希值,常用于集合類
getClass()返回此對象的運行時類
clone()克隆對象(實現 Cloneable 時有效)
finalize()對象被 GC 回收前調用(不推薦使用)

toString

我們使用 System.out.println() 打印對象,調用的就是對象的 toString 方法,將對象的 toString 方法返回的結果打印出來。

public class Person {private String name;public Person(String name) {this.name = name;}// 默認輸出是:類名@哈希值// 重寫 toString() 提供可讀性@Overridepublic String toString() {return "Person[name=" + name + "]";}
}

equals

equals 方法是用來比較兩個對象是否邏輯相等,Object 類的 equals 方法直接比較的是兩個對象地址。我們一般需要修改 equals 方法,比如:兩個公民對象,如果身份證 id 是一樣的,從我們的現實生活的經驗中判斷,這兩個人肯定是同一個人,即他們是相等的。

對于基本類型,我們可以直接使用 == 比較他們是不是相等的,如果他們的值是相等的,==返回 true,否則返回 false,對于對象,我們需要使用 equals 方法判斷兩個對象是不是相等的。

重寫 equals 方法的要點,要遵循如下的特性:

  1. 自反性:x.equals(x) 必須返回 true
  2. 對稱性:x.equals(y) 和 y.equals(x) 必須返回相同結果
  3. 傳遞性:如果 x.equals(y)且y.equals(z),則 x.equals(z) 必須為 true
  4. 一致性:多次調用 x.equals(y) 應該返回相同結果
  5. 非空性:x.equals(null) 必須返回 false

重寫 equals() 方法后,必須重寫 hashCode() 方法,以維護 Java 對象的通用約定,并確保基于哈希的集合(如 HashSet、HashMap 和 HashTable)能夠正常工作。Java 的 Object 類對 equals() 和 hashCode() 方法之間有明確的約定:

  • 如果兩個對象根據 equals() 方法相等,那么它們的 hashCode() 方法必須返回相同的值
  • 如果兩個對象的 hashCode() 方法返回相同的值,它們根據 equals() 方法不一定相等(哈希沖突)
  • 哈希表的功能: 哈希表使用 hashCode() 方法來確定對象在表中的位置(桶)。如果 equals() 被重寫但 hashCode() 沒有,則兩個邏輯上相等的對象(equals() 返回 true)可能具有不同的哈希碼。這會導致以下問題:1. 無法找到對象: 當你試圖在 HashSet 中查找一個對象時,HashSet 會使用對象的 hashCode() 來定位它所在的桶。如果 hashCode() 與原始對象的 hashCode() 不同(即使它們邏輯上相等),HashSet 將無法找到該對象,即使它已經存在于集合中。2. 重復元素: HashSet 旨在防止重復元素。如果兩個邏輯上相等的 對象具有不同的哈希碼,HashSet 會將它們視為不同的對象,從而允許將重復元素添加到集合中。3. HashMap 的不一致性: HashMap 也依賴于 hashCode() 和 equals() 來正確存儲和檢索鍵值對。如果鍵的 hashCode() 和 equals() 不一致,HashMap 的行為將變得不可預測。

下面是一個重寫 equals 方法的例子:

public class Person {private String name;public Person(String name) {this.name = name;}// 重寫equals方法@Overridepublic boolean equals(Object obj) {// 1. 檢查是否是同一個對象if (this == obj) {return true;}// 2. 檢查是否為null或類型不同if (obj == null || getClass() != obj.getClass()) {return false;}// 3. 類型轉換Person person = (Person) obj;// 4. 比較關鍵字段return name != null ? name.equals(person.name) : person.name == null;}// 重寫equals時也應該重寫hashCode@Overridepublic int hashCode() {return name != null ? name.hashCode() : 0;}
}
Person p1 = new Person("Tom");
Person p2 = new Person("Tom");// == 比較的是地址
System.out.println(p1 == p2); // false// 默認 equals 也是比較地址
// 可通過重寫實現“內容相等”
System.out.println(p1.equals(p2)); // true(需重寫后)

hashCode

hashCode 方法返回對象的 hashCode 編碼,在上面的 equals 方法中我們講過,要確保兩個對象如果 equals 方法判斷他們是相等的,那么他們的 hashCode 方法返回的哈希碼也必須是相等的。

// 在集合類(如 HashMap、HashSet)中要重寫 hashCode 與 equals 保持一致性
@Override
public int hashCode() {return name.hashCode(); // 簡單寫法
}

getClass

getClass 方法返回的是此 Object 的運行時類。

Person p = new Person("Jerry");
System.out.println(p.getClass().getName()); // 輸出類的全名

clone

按照慣例,如果一個類希望能夠被克隆,它應該重寫Object.clone()方法,并將其訪問修飾符改為public,通常返回它自己的類型(需要進行類型轉換)。在重寫的方法中,通常會先調用super.clone()來獲得一個基本的副本。

Object.clone()的默認行為是執行淺拷貝。 這里涉及到連個概念,淺拷貝(Shallow Copy)與深拷貝(Deep Copy)。

淺拷貝:

  • 對于原始數據類型(int, double, boolean等),直接復制值。
  • 對于引用類型(對象引用),復制的是引用本身,而不是被引用的對象。這意味著原始對象和克隆對象中的引用字段將指向內存中的同一個對象。
  • 后果: 如果原始對象或克隆對象修改了共享引用對象的狀態,這種改變會同時反映在另一個對象中。在大多數情況下,這可能不是期望的行為,因為它打破了克隆對象與原始對象之間的獨立性。

深拷貝:

  • 為了實現深拷貝,你需要在重寫的clone()方法中,對所有引用類型的字段(如果這些字段也是可克隆的)手動調用它們的clone()方法,從而創建這些引用對象的獨立副本。
  • 復雜性: 如果對象包含多層嵌套的引用類型,實現深拷貝可能會變得非常復雜,因為你需要遞歸地克隆所有被引用的對象。
class Address implements Cloneable {String city;String street;public Address(String city, String street) {this.city = city;this.street = street;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone(); // Address類的淺拷貝}@Overridepublic String toString() {return "Address [city=" + city + ", street=" + street + "]";}
}class Student implements Cloneable {String name;int age;Address address; // 引用類型public Student(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}// 淺拷貝的實現@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone(); // 默認是淺拷貝}// 深拷貝的實現(需要手動處理引用類型字段)public Object deepClone() throws CloneNotSupportedException {Student clonedStudent = (Student) super.clone();// 對引用類型字段進行深拷貝clonedStudent.address = (Address) address.clone();return clonedStudent;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";}
}public class CloneDemo {public static void main(String[] args) throws CloneNotSupportedException {Address originalAddress = new Address("New York", "Broadway");Student originalStudent = new Student("Alice", 20, originalAddress);// 淺拷貝示例Student shallowClonedStudent = (Student) originalStudent.clone();System.out.println("Original Student (Shallow): " + originalStudent);System.out.println("Shallow Cloned Student: " + shallowClonedStudent);// 修改淺拷貝后的地址,觀察原始對象的變化shallowClonedStudent.address.city = "Los Angeles";System.out.println("After changing shallowClonedStudent's city:");System.out.println("Original Student (Shallow): " + originalStudent); // Original也會改變System.out.println("Shallow Cloned Student: " + shallowClonedStudent);System.out.println("---");// 深拷貝示例Address originalAddress2 = new Address("London", "Oxford Street");Student originalStudent2 = new Student("Bob", 22, originalAddress2);Student deepClonedStudent = (Student) originalStudent2.deepClone();System.out.println("Original Student (Deep): " + originalStudent2);System.out.println("Deep Cloned Student: " + deepClonedStudent);// 修改深拷貝后的地址,觀察原始對象的變化deepClonedStudent.address.city = "Paris";System.out.println("After changing deepClonedStudent's city:");System.out.println("Original Student (Deep): " + originalStudent2); // Original不會改變System.out.println("Deep Cloned Student: " + deepClonedStudent);}
}

盡管clone()方法提供了對象復制的功能,但它在實際開發中很少被推薦使用,并且存在一些缺點:

  • 破壞封裝性:clone()方法需要訪問對象的內部狀態,這可能違反封裝原則。
  • **Cloneable**接口的不足:Cloneable是一個標記接口,它沒有定義clone()方法。這意味著編譯器無法檢查你是否正確地重寫了clone()方法,或者是否處理了CloneNotSupportedException
  • 不調用構造函數:clone()方法通過直接復制內存來創建對象,不調用任何構造函數。這可能導致一些需要構造函數來正確初始化的邏輯被跳過。
  • 不可變對象問題: 對于包含final字段的對象,clone()方法無法修改這些final字段,因為它們只能在構造函數中初始化。
  • 鏈式克隆的復雜性: 當一個對象包含其他對象的引用時,為了實現深拷貝,你必須確保所有被引用的類也實現了Cloneable并正確地重寫了clone()方法。這會導致一個“病毒式”的Cloneable實現。
  • 異常處理:Object.clone()會拋出受檢查異常CloneNotSupportedException,即使你的類實現了Cloneable,也需要在簽名中聲明或捕獲它。

鑒于這些缺點,通常有更好的替代方案來實現對象復制:

  1. 拷貝構造函數(Copy Constructor):創建一個接收同類型對象作為參數的構造函數,并在其中手動復制字段。 這是最常見和推薦的方式,它提供了更好的控制,允許你選擇是進行淺拷貝還是深拷貝,并且可以處理final字段。
  2. 拷貝工廠方法(Copy Factory Method): 提供一個靜態工廠方法來創建對象的副本。
  3. 序列化/反序列化(Serialization/Deserialization): 通過將對象序列化到字節流(例如內存中的ByteArrayOutputStream),然后從該字節流反序列化回來,可以實現深拷貝。 優點是簡單,自動處理深拷貝。 缺點是性能開銷較大,且所有涉及的類都必須實現Serializable接口。
  4. 第三方庫: 許多現代框架和庫提供了更強大、更靈活的對象映射和復制工具(如Apache Commons Lang的SerializationUtils.clone())。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84207.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84207.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大數據學習(135)-Linux系統性指令

🍋🍋大數據學習🍋🍋 🔥系列專欄: 👑哲學語錄: 用力所能及,改變世界。 💖如果覺得博主的文章還不錯的話,請點贊👍收藏??留言📝支持一…

【Fifty Project - D35】

今日完成記錄 TimePlan完成情況7:00 - 7:40爬坡√8:30 - 11:30Rabbit MQ√17:30 - 18:30羽毛球√ RabbitMQ 消費者端如何保證可靠性? 消息投遞過程出現網絡故障消費者接收到消息但是突然宕機…

P3 QT項目----記事本(3.4)

3.4 文件選擇對話框 QFileDialog 3.4.1 QFileDialog 開發流程 使用 QFileDialog 的基本步驟通常如下: 實例化 :首先,創建一個 QFileDialog 對象的實例。 QFileDialog qFileDialog;設置模式 :根據需要設置對話框的模式&…

學習筆記(26):線性代數-張量的降維求和,簡單示例

學習筆記(26):線性代數-張量的降維求和,簡單示例 1.先理解 “軸(Axis)” 的含義 張量的 “軸” 可以理解為 維度的方向索引 。對于形狀為 (2, 3, 4) 的張量,3 個軸的含義是: 軸 0(axis0&…

健康檔案實訓室:構建全周期健康管理的數據基石

一、健康檔案實訓室建設背景 隨著“健康中國2030”戰略深入推進,健康檔案作為居民健康數據的核心載體,在疾病預防、慢性病管理、醫療決策等領域的價值日益凸顯。在此背景下,健康檔案實訓室建設成為職業院校對接政策要求、培養專業健康管理…

【MATLAB第119期】基于MATLAB的KRR多輸入多輸出全局敏感性分析模型運用(無目標函數,考慮代理模型)

【MATLAB第119期】基于MATLAB的KRR多輸入多輸出全局敏感性分析模型運用(無目標函數,考慮代理模型) 下一期研究SHAP的多輸入多輸出敏感性分析方法 一、SOBOL(無目標函數) (1)針對簡單線性數據…

Linux常用文件目錄命令

瀏覽目錄命令: ls 、pwd目錄操作命令:cd、mkdir、rmdir瀏覽文件命令:cat、more、less、head、tail文件操作命令:cp、rm、mv、find、grep、tar 瀏覽目錄命令 ls ? 命令名稱:ls ? 命令英文原意:list ? …

PIN碼vs密碼,電腦登錄的快捷鍵你用對了嗎?

你是否也遇到過這樣的窘境:信心滿滿地輸入電腦開機密碼,屏幕卻無情地提示“密碼錯誤”。仔細一看,才發現登錄界面悄悄地變成了要求輸入“PIN碼”。這種因為混淆了PIN碼和賬戶密碼而導致的開機失敗,相信不少朋友都碰到過。 PIN碼作…

【大模型科普】AIGC技術發展與應用實踐(一文讀懂AIGC)

【作者主頁】Francek Chen 【專欄介紹】 ? ? ?人工智能與大模型應用 ? ? ? 人工智能(AI)通過算法模擬人類智能,利用機器學習、深度學習等技術驅動醫療、金融等領域的智能化。大模型是千億參數的深度神經網絡(如ChatGPT&…

Spring是如何解決Bean的循環依賴:三級緩存機制

1、什么是 Bean 的循環依賴 在 Spring框架中,Bean 的循環依賴是指多個 Bean 之間?互相持有對方引用?,形成閉環依賴關系的現象。 多個 Bean 的依賴關系構成環形鏈路,例如: 雙向依賴:Bean A 依賴 Bean B,同時 Bean B 也依賴 Bean A(A?B)。鏈條循環: Bean A → Bean…

XXE漏洞知識

目錄 1.XXE簡介與危害 XML概念 XML與HTML的區別 1.pom.xml 主要作用 2.web.xml 3.mybatis 2.XXE概念與危害 案例:文件讀取(需要Apache >5.4版本) 案例:內網探測(雞肋) 案例:執行命…

02-性能方案設計

需求分析與測試設計 根據具體的性能測試需求,確定測試類型,以及壓測的模塊(web/mysql/redis/系統整體)前期要與相關人員充分溝通,初步確定壓測方案及具體的性能指標QA完成性能測試設計后,需產出測試方案文檔發送郵件到項目組&…

STL優先級隊列的比較函數與大堆小堆的關系

STL中的priority_queue&#xff08;優先級隊列&#xff09;通過比較函數來確定元素的優先級順序&#xff0c;從而決定其內部是形成大堆還是小堆。以下是關鍵點總結&#xff1a; 默認行為與大堆&#xff1a; 默認情況下&#xff0c;priority_queue使用std::less<T>作為比較…

React---day11

14.4 react-redux第三方庫 提供connect、thunk之類的函數 以獲取一個banner數據為例子 store&#xff1a; 我們在使用異步的時候理應是要使用中間件的&#xff0c;但是configureStore 已經自動集成了 redux-thunk&#xff0c;注意action里面要返回函數 import { configureS…

OD 算法題 B卷【反轉每對括號間的子串】

文章目錄 反轉每對括號間的子串 反轉每對括號間的子串 給出一個字符串s&#xff0c; 僅含有小寫英文字母和英文括號’(’ ‘)’&#xff1b;按照從括號內到外的順序&#xff0c;逐層反轉每對括號中的字符串&#xff0c;并返回最終的結果&#xff1b;結果中不能包含任何括號&am…

如何做好一份技術文檔?從規劃到實踐的完整指南

如何做好一份技術文檔&#xff1f;從規劃到實踐的完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈量世界&…

css的定位(position)詳解:相對定位 絕對定位 固定定位

在 CSS 中&#xff0c;元素的定位通過 position 屬性控制&#xff0c;共有 5 種定位模式&#xff1a;static&#xff08;靜態定位&#xff09;、relative&#xff08;相對定位&#xff09;、absolute&#xff08;絕對定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…

詳細講解Flutter GetX的使用

Flutter GetX 框架詳解&#xff1a;狀態管理、路由與依賴注入 GetX 是 Flutter 生態中一款強大且輕量級的全功能框架&#xff0c;集成了狀態管理、路由管理和依賴注入三大核心功能。其設計理念是簡潔高效&#xff0c;通過最小的代碼實現最大的功能&#xff0c;特別適合快速開發…

【大模型:知識庫管理】--Dify接入RAGFlow 知識庫

ragflow的官方文檔&#xff1a; HTTP API 接口 |抹布流 --- HTTP API | RAGFlow 接著前文&#xff0c;我們已經創建了知識庫&#xff0c;那么如何才能使用它呢&#xff1f; 當然也是通過網絡API的形式去調用它。本文將講解兩種方式&#xff1a; Dify調用python源碼調用 目錄…

Vue 模板配置項深度解析

Vue 模板配置項深度解析 在 Vue 組件開發中&#xff0c;template 是定義組件視圖結構的核心配置項。作為 Vue 專家&#xff0c;我將全面解析模板的各個方面&#xff0c;幫助你掌握高效構建 Vue 組件的藝術。 一、模板基礎概念 1. 模板的本質 聲明式渲染&#xff1a;描述 UI…