自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從Scala看canEqual與正確的的equals實現(xiàn)

開發(fā) 后端
Java中的Equals實現(xiàn),在Effective Java的描述中,是無法保證其完全正確的。不過根據(jù)Scala創(chuàng)始人的一篇文章,canEqual方法是可以解決這個問題的。這在Scala語言中得到了實現(xiàn)。

Equals實現(xiàn)在Java中有著很多的問題(詳見《所有的Equals方法實現(xiàn)都是錯誤的》),不過這些問題并非令人完全喪氣。下面通過Scala作者的一篇文章中探討equals實現(xiàn)以及canEqual的使用。

在 Effective Java 中,Joshua Bloch 提到,如果一個可實例化的類定義了 equals 方法。另有一個子類繼承它,也定義了額外一些屬性,并且 equals 方法中需要使用這些新定義的屬性進行相等性判斷。那么就不可能保證 equals 語義的正確。

相信看過 Effective Java 的人當年讀到這里時都會覺得喪氣。就好像完美的世界突然有了一個無法縫合的裂口。先不要完全喪失興趣,看看下面的文章:

How to Write an Equality Method in Java (51CTO曾翻譯此文為《所有的Equals方法實現(xiàn)都是錯誤的》)

這篇主要由 Scala 的作者 Martin Odersky 執(zhí)筆的文章中提到了一個有意思的方法。每個類在定義 equals 時,首先先判斷 canEqual 能不能校驗通過。canEqual 的作用就是限定:只有當被比較的對象是當前對象的子類或同類時才能通過。

  1. class Point {  
  2.  
  3.   // 屬性定義  
  4.   ...  
  5.  
  6.   boolean canEqual(Object other) {  
  7.     return (other instanceof Point);  
  8.   }  
  9.     
  10.   @Override boolean equals(Object other) {  
  11.     if (other instanceof Point) {  
  12.       Point that = (Point) other;  
  13.       if (that.canEqual(this) && ...) return true 
  14.     }  
  15.     return false;   
  16.   }  
  17.     
  18. }  
  19.  

子類的定義與父類相似。

也就是說,在這樣的約定下,如果拿一個父類實例和子類實例用 equals 比較肯定會返回 false。關于這篇文章,有興趣的話可以看看相應的討論。

討論主要集中在文章里的方法是否違背了 Liskov Substitution Principle (LSP),以及如果違背了那么這個問題有多嚴重上??催^下面的分析后大家也許會覺得這種討論沒有太多意義。

我個人推薦這種 canEqual 方法。我說“方法”而不說“解決方案”是因為我覺得 Odersky 所描述的 equals 實現(xiàn)與 Bloch 本來所期望的 equals 邏輯模型并不一致。想像 Odersky 文章中的例子。有一個類 - 點(Point),及其子類 - 有色點(ColoredPoint)。如果一個有色點實例,其坐標與一個普遍點坐標一樣,又因為有色點“是”點,所以這兩點應該“相等”。大家都期望這樣一個結論是成立的,所以當看到 Bloch 的結論時會覺得面向對象有其固有的自相矛盾之處。但是這樣一個結論卻并不是天然成立的。一個沒有顏色的點與一個有顏色的點能相等嗎?有人會說,如果 ColoredPoint 里面的 color 屬性是一個枚舉,而且那個子類被實例化成 Color.UNSPECIFIED(未指定的顏色),那么這兩個點邏輯上就應該相等了吧。我認為,如果 ColoredPoint.color 可以有這樣一個屬性值的話,那么 Point 類就應該被定義為抽象類。Point 類此時實例化沒有意義。換句話說,如果 Point 類可以實例化,且其子類 ColoredPoint 也可以有一個“未指定的顏色”,而且兩者都定義了 equals,那么出現(xiàn)這種情況我認為是設計失敗。

再看看 LSP。LSP 說,任何可以使用父類實例的地方都可以使用子類實例代替。這里并不違反 LSP,因為如果一個地方可以這樣調(diào)用:

  1. Point p = new Point();  
  2. if (p.equals(...)) {  
  3.   ...  
  4. }  
  5.  

那么使用子類一樣可以調(diào)用 equals。只不過,equals 在傳入相同的參數(shù)時返回的結果可能會不一樣。但是 LSP 并不約束必須返回一樣的結果。而這正是多態(tài)的特征。

回到 Bloch 的論點上?,F(xiàn)在贊同我的人可能會覺得 Bloch 的論點有問題。其實他說得很嚴謹,沒有一絲問題。他的論點的前提是:可實例化的父類。也就是說無法針對非抽象類寫出滿足大家傳統(tǒng)期望的子類。只不過,另人失望地,他在提出這個結論后沒有給出對應的方法。相對來說,Odersky 理清了 Bloch 的邏輯模型。所以,在 Odersky 所發(fā)明的 Scala 中,canEqual 這個方法也被作為官方推薦的 equals實現(xiàn)方法。

【編輯推薦】

  1. Java:所有的equals方法實現(xiàn)都是錯誤的?
  2. Java語言中深入研究Java equals方法
  3. Java是平臺而非產(chǎn)品:可添加型概念需改變
  4. Java中的堆內(nèi)存與棧內(nèi)存分配淺析
  5. Scala編程語言
責任編輯:yangsai 來源: JavaEye博客
相關推薦

2009-09-22 09:42:24

Scala的核心

2009-12-09 09:15:47

從Java走進ScalTwitter API

2021-06-26 07:04:24

Epoll服務器機制

2009-06-15 15:33:13

ScalaTwitter

2009-02-04 17:32:03

ibmdwJavaScala

2017-04-05 20:00:32

ChromeObjectJS代碼

2021-05-06 10:33:30

C++Napiv8

2024-03-07 13:30:44

Java對象true

2009-06-16 17:54:38

Scala類語法語義

2009-04-28 18:32:54

2009-07-06 15:55:50

2020-03-09 15:40:27

RSACDevSecOps懸鏡安全

2014-04-22 09:51:24

LongAdderAtomicLong

2021-07-07 23:38:05

內(nèi)核IOLinux

2009-08-21 16:17:25

ScalaTwitter API

2009-09-28 11:01:39

從Java走進Scal

2013-08-27 18:31:33

恒天然SPC軟件

2009-08-13 10:35:05

Scala數(shù)組排序

2015-06-15 18:44:15

Apple Watch微游戲

2021-06-18 06:02:24

內(nèi)核文件傳遞
點贊
收藏

51CTO技術棧公眾號