《Effective Java》第二章 對於所有物件都通用的方法
接下來繼續講第二章,第8-12條。
第8條:覆蓋equals時請遵守通用約定
equals 時Object類的一個非final方法,一般是表示類的例項物件是否相同,也就是物件的地址是否相等。
但是某些時候卻要重寫Object.equals方法。即類需要有“邏輯相等”,也就是值類,這都需要重寫equals方法。這樣這個類的例項可以用做Map的key中。有一種值類就不需要重寫equals,就是單例模式的類,至始至終也就一個物件。
在覆蓋equals時需要遵守的幾個約定:自反性、對稱性、傳遞性、一致性、非null。
第9條:覆蓋equals時總要覆蓋hashode
每個重寫類equals方法的類都必須要重寫hashCode方法,不然在改類將不能和基於雜湊的集合【HashMap、HashSet】一起正常使用。物件的根據equals方法判斷時相等的,其hashcode肯定也是相等的。即判斷2個物件是否相等,先比較hashcode是否相等,若相等則在比較equals是否相等。
看下面的一個例子。
package com.example.demo2; import java.util.Objects; public class Student { private int age; private String name; private int grade; public Student(int age, String name, int grade) { this.age = age; this.name = name; this.grade = grade; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Student)) return false; Student student = (Student) o; return age == student.age && grade == student.grade && Objects.equals(name, student.name); } }
當把這個類和HashMap一起使用時
Map<Student,String> stu = new HashMap<>();
stu.put(new Student(12,"jack",99),"Jack");
期望的時stu.get(new Student(12,"jack",99)) 返回的時Jack,但是實際上返回的時null,主要的原因就是沒有重寫hashCode,從而導致2個物件例項有不同的hashcode值。一個好的雜湊函式就是為每個不同的物件產出不同的雜湊碼。
一般一個理想的雜湊函式設計方案:
1、把某個非零的常數值,比如說17,儲存在一個名為result的int型別的變數中
2、對於物件只能夠的每個關鍵字f,完成下面的步驟
a、為該域計算int型別的雜湊碼C
b、按下面的計算公式,result = 31 * result + c
3、返回result
public int hashCode() {
int result = 17;
result = 31 * result + age;
result = 31 * result + Integer.valueOf(name);
result = 31 * result + grade;
return result;
}
但是現在的IDE已經非常的強大了,可以利用快捷鍵自動重寫equals和hashcode方法了,但是其中的原理我們還是需要掌握的。
第10條:始終要覆蓋toString
java.lang.Object也提供了toString方法的一個實現,但是它格式可讀性不好,它包含類的名稱,一個一個“@”符號,接著是haahcode的無符號的十六進位制表示法。雖然遵守toString的約定不如遵守equals、hashcode的約定這麼重要,但是提供好的toString方法可以讓類的使用更加的舒適。
第11條:謹慎地覆蓋clone
按照書中的話來講,能不重寫clone就不要去重寫,因為它帶來的問題太多了。我們暫且不討論這裡面的陷阱有多少,只從對Java基礎知識的掌握程度來說明什麼是clone,以及什麼是“深拷貝”和“淺拷貝”。首先觀察以下程式碼,並思考物件在記憶體中的分配以及引用的變化:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Main {
public static void main(String[] args) throws Exception{
Student stu = new Student("kevin", 23);
Student stu2 = stu;
stu2.setAge(0);
System.out.println(stu.getAge());
}
}
這是一段很簡單的程式碼,Student物件例項stu、stu2在記憶體中的分配及引用分別如下圖所示:所以程式碼中出現修改stu2例項的age欄位時,stu中的age欄位也被修改了,原因很簡單因為它們的引用指向的都是同一個物件例項。
那如果我們想在例項化一個name=”kevin”,age=23的Student例項怎麼辦呢?當然可以再寫一段Student stu2 = new Student(“kevin”, 23);如果再重新構造一個物件例項很複雜,能不能直接複製呢?顯然,使Student實現Cloneable介面並重寫clone方法即可,注意此時的重寫clone方法在裡面僅有一句程式碼即是即呼叫父類的clone方法,而不是自定義實現:
- publicclass Student implements Cloneable{
- private String name;
- privateint age;
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
- publicint getAge() {
- return age;
- }
- publicvoid setAge(int age) {
- this.age = age;
- }
- @Override
- protected Student clone()
- throws CloneNotSupportedException {
- return (Student)super.clone();
- }
- }
- publicclass Main {
- publicstaticvoid main(String[] args) throws Exception{
- Student stu = new Student("kevin", 23);
- Student stu2 = stu.clone();
- stu2.setAge(0);
- System.out.println(stu.getAge());
- }
- }
上面我們僅僅是說明了什麼是clone,接下來我們接著來講解什麼是“深拷貝”和“淺拷貝”。
在上面的例子Student類中,我們新增一個引用型變數Test類:
- publicclass Student implements Cloneable{
- private String name;
- privateint age;
- private Test test;
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
- publicint getAge() {
- return age;
- }
- publicvoid setAge(int age) {
- this.age = age;
- }
- public String getTest() {
- return test;
- }
- publicvoid setTest(Test test) {
- this.test= test;
- }
- @Override
- protected Student clone()
- throws CloneNotSupportedException {
- return (Student)super.clone();
- }
- }
- publicclass Main {
- publicstaticvoid main(String[] args) throws Exception{
- Student stu = new Student("kevin", 23);
- Student stu2 = stu.clone();
- stu2.setAge(0);
- System.out.println(stu.getAge());
- }
- }
- /**
- * 深拷貝
- *
- */
- publicclass Student implements Cloneable{
- private String name;
- privateint age;
- private Test test;
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
-
相關推薦
《Effective Java》第二章 對於所有物件都通用的方法
接下來繼續講第二章,第8-12條。第8條:覆蓋equals時請遵守通用約定equals 時Object類的一個非final方法,一般是表示類的例項物件是否相同,也就是物件的地址是否相等。但是某些時候卻要重寫Object.equals方法。即類需要有“邏輯相等”,也就是值類,這
《Effective Java》:對於所有物件都通用的方法
本系列皆為讀書筆記,“好記性不如爛筆頭”,勤看,也要勤記錄。此篇讀書筆記來自《Effective Java》。儘管Object是一個具體類,但設計它主要是為了擴充套件。它所有的非final方法都有明確的通用規定。任何一個類,在覆蓋這些方法的時候,都有責任去遵守這些通用規定,如
effective java中文版第三章 對於所有物件都通用的方法
道一聲坑爹。。。。上週末剛把這章整理了。。。忘了儲存了。。。迫於強迫症。。。。不得不再寫一遍。。但是也一帶而過。。。。只是為了哥的強迫症 第8條 覆蓋equals時請遵守通用約定 1,自反性 2,對稱性 3,傳遞性 第9條 覆蓋equals時總要覆蓋hashCode(這條重點記住)
effective java-讀書筆記-第三章 對於所有物件都通用的方法
第三章 對於所有物件都通用的方法 所有非final方法(equals、hashCode、toString、clone、finalize)都有明確的通用約定,因為它們被設計成是要被覆蓋的,如果不遵守,基於雜湊的集合(HashMap、HashSet、HashTable)可
《Effective Java》第3章 對於所有物件都通用的方法
Object類預設為所有類的基類,其雖然為一個具體的類,但是它的設計主要是為了擴充套件,而它的所有非final的方法(equals, hashCode, toString, clone和finalize)都有明確的通用約定, 如果在自定義類時要重寫這些方法,需要注意主動遵守
【Effective java 學習】第三章:對於所有物件都通用的方法
第八條:覆蓋equals是請遵守通用約定 滿足下列四個條件之一,就不需要覆蓋equals方法: 類的每個例項本質上都已唯一的。不包括代表值的類,如:Integer,String等,Object提供的equals方法就夠用了 不關心是否提供了“邏輯相等”的測試功能。對
Effective Java讀書筆記 -- 第三章:對於所有物件都通用的方法
儘管Object是一個具體類,但是設計Object類主要是為了擴充套件。它的所有非final方法(equals、hashCode、toString、clone和finalize)都有明確的通用約定,因為它們就是被設計成要被覆蓋的。第八條:覆蓋equals時請遵守通用約定
Effective Java學習筆記(二)對於所有物件都通用的方法
Object是一個具體類,但是設計他主要是為了擴充套件,他所有的非final方法(equals,toString,hashCode,clone,finalize)都是要被覆蓋的,並且任何一個類覆蓋非final方法時都要遵守通用原則,以便其他遵守這些預定的類能夠一同運作,
Effective java筆記-對於所有物件都通用的方法
對於所有物件都通用的方法 第8條 覆蓋equals時請遵守通用約定 滿足以下任何一個條件,可以不覆蓋equals: 類的每個例項本質上都是唯一的。(如Thread) 不關心是否提供了“邏輯相等”的測試功能(如Random) 超類已經覆蓋了equals,從
【讀書筆記】《Effective Java》(2)--對於所有物件都通用的方法
又讀了一章,之前一直覺得Java的體系很完善了,讀了這一章,發現原來Java平臺本身也有一些設計不周到的地方,而且有些地方因為已經成為公開API的一部分還不好改,相信繼續讀下去對Java的瞭解會更深一步的。 昨天下載了VS Code,嘗試了一下,感覺比subl
Effective Java 總結(二) 對於所有物件都通用的方法
在改寫equals的時候請遵守通用約定 不改寫equals方法時,每個例項只與自身相等,如果滿足一下任意一個條件,則不需要改寫equals方法: 一個類的例項本質上都是唯一的 不關心類是否支援“邏輯相等”功能 超類已經改寫了equals方法 類是私有的,並且可以確定
對於所有物件都通用的方法(equals)
1.在改寫equals的時候請遵守通用約定。 1)一個類的每個例項本質上都是惟一的。 2)不關心一個類是否提供了“邏輯相等”的測試功能。 3)超類改寫了equals,從超類繼承過來的行為對於子類也是合適的。public class CaseInsentiveString
對於所有物件都通用的方法
8.覆蓋equals時請遵守通用規定 需要滿足的條件: 類的每個例項本質上都是唯一的。 不關心類是否提供了“邏輯相等(logical equality)”的測試功能。 超類已經覆蓋了equals,從超類繼承過來的行為對於子類也是合適的。 類是私有的或是包級私有的,可以確
9. 【對於所有物件都通用的方法】重寫equals方法時一定也要重寫hashCode方法
本文是《Effective Java》讀書筆記第9條,其中內容可能會結合實際應用情況或參考其他資料進行補充或調整。 在每個覆蓋了equals方法的類中,一定也要覆蓋hasCode方法。否則會導致該類無法結合所有基於雜湊的集合(比如HashMap、HashS
2、對於所有物件都通用的方法
Object的設計主要是為了擴充套件。它的非final方法(equals、hashCode、toString、clone、finalize)都有明確的通用約定(general contract)。任何一個類覆蓋這些方法都有責任遵守這些約定。 覆蓋equal
Java高階系列——使用所有物件的通用方法
一、介紹 通過如何建立和銷燬物件一文,我們已經知道Java是一個面向物件的程式語言,Java類層次結構的頂部是Object類,Java中每個單獨的類都隱式的繼承於該類。因此,所有的類都繼承了在Object類中定義的一系列方法,這其中的一些非常重要的方法如下:
Effective Java:對於所有的物件都通用的方法
Java中所有的類都預設繼承Object類,而Object的設計主要是為了擴充套件。它的所有的非final方法(equals、hashCode、toString、clone和finalize)都有明確的通用約定(general contract),因為它們被設計
<Thinking in java 第二章> 一切都是對象
運算 參數 區分 bigint 高精度 簽名 重載 對象 通過 P23——Java提供了兩個用於高精度計算的類:BIgInteger和BigDecimal,能作用於int和float的操作,也同樣能作用於BigInteger和BigDecimal。只不過必須以方法調用的方式
Effective Java (3rd Editin) 讀書筆記:2 所有物件共有的方法
2 所有物件共有的方法 Item 10:重寫 equals 方法時遵守通用協同 不需要重寫 equals() 方法的情況: 類的每一個例項都認為是不同。比如 Thread 這種代表活躍的實體而不是值 不需要“邏輯相等”的判斷。比如 Pattern 不需要檢查內嵌的正
Effective Java 第二版 中文版 筆記(六)消除過期物件的引用
這部分沒有怎麼理解,但總體的意思就是防止記憶體洩漏 Java的垃圾回收機制: Java中的物件是在堆中分配,物件的建立有2中方式:new或者反射。物件的回收是通過垃圾收集器,JVM的垃圾收集器簡化了程式設計師的工作,但是卻加重了JVM的工作,這是Java程式執行稍慢的