【Practical Java】實踐10:不要依賴equals()的預設實現
實踐9 闡釋了何時使用==操作符以及何時使用equals()。如果你對後者的實現方式不聞不問,則在呼叫它時或許無法獲得你想要的結果。舉個例子,假設你正在為某個高爾夫器材批發店撰寫軟體,其中一個任務是計算庫存中的同類球數量。你可能已經為高爾夫球撰寫了如下的class:
package fp;
public class Golfball
{
private String brand;//品牌
private String make;//型號
private int compression;//彈性
public Golfball(String br, String mk, int comp)
{
brand = br;
make = mk;
compression = comp;
}
public String getBrand()
{
return brand;
}
public String getMake()
{
return make;
}
public int getCompression()
{
return compression;
}
}
每一個Golfball 物件都具有品牌(brand)、型號( make)和彈性( compression)三個屬性。兩個Golfball 物件相等意味所有三個屬性都必須相同。進一步假設,每一個Golfball 物件都被儲存於某資料庫中。日後當你訪問資料庫時,必須確定哪些Golfball 物件是同型別的,才能產生正確的計算。下面是一段用以比較Golfball 物件的程式碼:
package fp;
public class Test
{
public static void main(String args[])
{
Golfball gb1 = new Golfball("BrandX","Professional",100);
Golfball gb2 = new Golfball("BrandX","Professional",100);
if(gb1.equals(gb2))
{
System.out.println("ball1 equals ball2");
}
else
{
System.out.println("ball1 does not equal ball2");
}
}
}
輸出如下:
ball1 does not equal ball2
本例中的Golfball 物件並沒有實現自己的equals(),因此呼叫的是java.lang.Object 的equals()。
public boolean equals(Object obj) {
return (this == obj);
}
你想知道的其實是高爾夫球的品牌(brand)、型號(make)和彈性(compression)是否相同。與改善這個問題,Golfball class 必須實現自己的equals()函式,而不能寄望於java.lang.Object 提供的預設實現程式碼。
package fp;
public class Golfball
{
//as before...
public boolean equals(Object obj)
{
if (this == obj)
return true;
if(obj != null && getClass() == obj.getClass())
{
Golfball gb = (Golfball)obj;
if(brand.equals(gb.getBrand()) &&
make.equals(gb.getMake()) &&
compression == gb.getCompression())
return true;
}
return false;
}
}
到目前為止你的設計很出色,高爾夫器材批發店的程式運轉的也很好。可是有一天,某位程式設計師(在閱讀了《Practical Java》實踐31 之後)打算修改Golfball 物件的brand 和make 值域,以StringBuffer 替換String。現在,Golfball class 變成了這樣子:
public class Golfball
{
// private String brand;//品牌
// private String make;//型號
private StringBuffer brand;//品牌
private StringBuffer make;//型號
private int compression;//彈性
public Golfball(StringBuffer br, StringBuffer mk, int comp)
{
brand = br;
make = mk;
compression = comp;
}
public StringBuffer getBrand()
{
return brand;
}
public StringBuffer getMake()
{
return make;
}
看起來這是對class 無傷大雅的修改。你並沒有改變equals(),只是改動Golfball class 的其他部分。Golfball class 僅僅從使用Strinng 轉為使用StringBuffer。但在完成了修改之後,你會驚訝的看到程式又不能正常運作了。它所產生的輸出如下:
ball1 does not equal ball2
Java 的String class 正確實現了一個equals(),但StringBuffer class 根本就沒有實現它。由於這個原因,你一定猜到了,你所呼叫的是java.lang.Object的equals()。這是因為StringBuffer 的父類是java.lang.Object,這就說得通了。我們先前已經討論過,java.lang.Object 的equals()在此情況下不能用。這也正是你先前自行撰寫equals()的原因。
這個問題有數個解決方案:
1. 回到使用string 物件的老路子。
2. 修改Golfball 的equals(),使之先將StringBuffer 物件轉換為String 物件,然後再呼叫equals()。
public boolean equals(Object obj)
{
if (this == obj)
return true;
if(obj != null && getClass() == obj.getClass())
{
Golfball gb = (Golfball)obj;
if(brand.toString().equals(gb.getBrand().toString()) &&
make.toString().equals(gb.getMake().toString()) &&
compression == gb.getCompression())
return true;
}
return false;
}
3. 撰寫一個你自己的StringBuffer class,其中包含equals()。
package fp;
public class MyStringBuffer
{
private StringBuffer sb;
public MyStringBuffer(String str)
{
sb = new StringBuffer(str);
}
public int length()
{
return sb.length();
}
public synchronized char charAt(int index)
{
return sb.charAt(index);
}
public boolean equals(Object obj)
{
if(this == obj)
return true;
if(obj != null && getClass() == obj.getClass())
{
MyStringBuffer msb = (MyStringBuffer)obj;
int len = length();
if(len != msb.length())
return false;
else
{
int index = 0;
while(index < len)
{
if(charAt(index) != msb.charAt(index))
return false;
index++;
}
return true;
}
}
else
return false;
}
}
4. 放棄equals(),撰寫你自己的compare()函式,用它來比較StringBuffer
物件的相等性。
相關文章
- Maven最佳實踐:管理依賴Maven
- 依賴注入?依賴注入是如何實現解耦的?依賴注入解耦
- iOS實現依賴注入iOS依賴注入
- JavaScript依賴注入的實現思路JavaScript依賴注入
- PHP 依賴注入容器實現PHP依賴注入
- 依賴注入實現元件化依賴注入元件化
- 動手實現你的依賴注入依賴注入
- 200行Java程式碼實現依賴注入框架Java依賴注入框架
- 不要依賴Mock庫 - ErwinMock
- go語言依賴注入實現Go依賴注入
- .NET之預設依賴注入依賴注入
- Laravel 中的依賴注入和 IoC 實現Laravel依賴注入
- 關於Golang中的依賴注入實現Golang依賴注入
- Angular 的依賴注入是怎麼實現的?Angular依賴注入
- 用 Dagger 2 實現依賴注入依賴注入
- Guice指南-用Guice實現依賴注入GUI依賴注入
- 【專案實踐】依賴注入用得好,設計模式隨便搞依賴注入設計模式
- 利用反射機制實現依賴注入的原理反射依賴注入
- 用trait實現簡單的依賴注入AI依賴注入
- JavaEE依賴注入CDI的開源實現: WeldJava依賴注入
- DIY 實現 ThinkPHP 核心框架 (十四)利用反射實現依賴注入PHP框架反射依賴注入
- 正確的equals實現
- SQL如何實現查詢節點依賴SQL
- 使用 .NET Core 實現依賴關係注入
- Go中使用Google Wire實現依賴注入Go依賴注入
- ASP.NET WebApi + Autofac 實現依賴注入ASP.NETWebAPI依賴注入
- 【Practical Java】實踐1:引數以by value方式而非by reference方式傳遞Java
- .Net核心依賴項注入:生命週期和最佳實踐
- Spring學習:簡單實現一個依賴注入和迴圈依賴的解決Spring依賴注入
- Asp.Net Mvc使用Autofac實現依賴注入ASP.NETMVC依賴注入
- 求助:需要dto實踐的例項不要在ejb下實現的
- Laravel自動依賴解析的實現,其實是PHP對映解析LaravelPHP
- Angular 依賴注入機制實現原理的深入介紹Angular依賴注入
- Maven 原始碼解析:依賴調解是如何實現的?Maven原始碼
- Minya 分層框架實現的思考(一):依賴轉移框架
- Scala的Cake實現依賴注入是一個謊言依賴注入
- java的類之間的關係:泛化、依賴、關聯、實現、聚合、組合Java
- 重新整理 .net core 實踐篇————依賴注入應用[二]依賴注入