你真的搞明白了 Dart 中兩個對象相等的邏輯了嗎?

前言

通常來說我們不會去實現類的自定義的相等判斷,這個時候構建的任何對象因為值不同或 hash code不同,使用==判斷的時候都是返回 false 的。而在某些場合狭归,如果我們想要直接使用==來判斷自定義類是否相等的話,則需要同時覆蓋==操作符和 hashCode 方法文判。在使用自定義的對象相等性實現時过椎,編碼需要注意哪些事情,本篇來為你總結相關內容戏仓。

對象相等判斷

我們先來看 Java 語言中很經典的一道面試題疚宇,即下面的代碼控制臺輸出結果是什么。

Integer a=127;
Integer b=127;
System.out.println(a==b);

Integer c=128;
Integer d=128;
System.out.println(c==d);

結果第一個打印的是 true赏殃,第二個打印的是 false敷待。這是因為 Java 中的-128至127范圍的整數對象使用了緩存,在這范圍之外的都是新構建的對象了仁热。那么 Dart 中榜揖,類似的情況是什么樣的?


  int a = 127;
  int b = 127;
  print(a == b);

  int c = 128;
  int d = 128;
  print(c == d);

結果返回都是 true股耽,這是因為 Dart 支持操作符重載根盒,判斷兩個對象相等實際是使用的是==操作符和 hash code判斷的钳幅。intdouble 都繼承自數值類num物蝙。對于這個類型來說,hash code 就是數值本身敢艰,而==操作符實際使用的是 compareTo 方法進行判斷的诬乞,因此只要兩個數值類的值相等(特殊值除外,比如 double.nan钠导,double.infinity)震嫉,那么使用==比較符操作時就是相等的。

對于字符串類型來說也是一樣牡属,字符串的只要字符序列是一致的票堵,那么 hash code就也是一致的。但是逮栅,對于 unicode 而言悴势,如果使用的編碼不同窗宇,那么 hash code 是不相等的。因此特纤,在 Dart 中军俊,比較字符串相等不需要使用類似 Java 的 equals 方法,直接使用==操作符就可以了捧存。

這其實也就給了我們另一種靈活性粪躬,比如我們想要兩個同一類型的對象相等時,可以覆寫==操作符和 hashCode 方法昔穴,來實現我們某些用途镰官。例如 Widget 是否要刷新,再比如我們在 Redux 中講到的吗货,由于每次 Redux 都會返回一個新的 State 對象朋魔,如果在實際數據沒變的情況下要減少刷新,那么也可以這么操作卿操。

有了上面的認識警检,我們來看在自定義對象相等判斷時的注意事項。

如果覆蓋==操作符的話害淤,務必同時覆蓋 hashCode 方法

默認的 hashCode 方法會產生一個唯一的 hash 值——這意味著正常情況下扇雕,只有兩個對象是統(tǒng)一對象時,他們的兩個哈希值才會相等窥摄。當我們要覆蓋==操作符時镶奉,意味著我們對這個類的對象相等的判斷有其他的定義。對象相等的原則必須滿足二者同時具有相同的哈希值崭放。因此哨苛,如果你不覆蓋 hashCode 方法,意味著在某些場合會失效币砂,比如 Map 以及其他基于哈希值判斷的集合建峭,即便兩個集合里面的元素滿足相等條件,但因為相等元素的哈希值不同决摧,導致兩個集合無法滿足相等判斷亿蒸。

==操作符應該滿足數學意義上的相等規(guī)則

數學上,相等需要滿足三個規(guī)則:

  • 反身性:即a == a 應該始終返回 true掌桩。
  • 對稱性:若a == b 那么 b == a 也應該為 true边锁。
  • 傳遞性:若a == bb == c,那么a == c 也應該為 true波岛。

這意味著我們的 hashCode 方法或==操作符方法不能有基于條件來過濾對象的某些屬性相等判斷茅坛。比如跳過對象屬性為 null 的情況,就可能導致啥給你們的三個規(guī)則中的某一條失效则拷。

對于可變類贡蓖,應該避免自定義相等判斷

什么是可變類祟剔?就是對象的屬性在運行過程中可能改變的類。因為摩梧,考慮上面的數學意義的相等規(guī)則物延,那么自定義相等在生成哈希值時,應當將對象的所有屬性都考慮在內仅父。而如果這些屬性在運行過程中會被改變的話叛薯,那就意味著這個對象的哈希值是會變的。這其實違反了反身性原則(同一個對象笙纤,前后的哈希值不相等耗溜,這就好比你的女友換了個發(fā)型后你就認不出來一樣,是要被打的)省容,通時對于基于哈希值的集合來說抖拴,沒法預料這種變化,這會導致集合的相等判斷出錯腥椒。

不要將==操作符的參數應用于可為空的對象

在Dart 中阿宅,null 只會與其自身相等,因此只有當被比較的對象不為空時才應該調用==操作符進行相等判斷笼蛛。

// 正確示例
class Person {
  final String name;
  // ···

  bool operator ==(Object other) => other is Person && name == other.name;
}

//錯誤示例
class Person {
  final String name;
  // ···

  bool operator ==(Object? other) =>
      other != null && other is Person && name == other.name;
}

注意:在 Dart 推出 null safety 版本以前洒放,對象是允許為 null 的。即便是這樣滨砍,Dart也不會使用 null 調用自定義的==方法進行相等判斷(可以理解為 Dart 直接處理為 false 了)往湿。因此,在非 null safety 版本(< 2.12版本)惋戏,我們無需在==方法內處理 null领追。

總結

本篇介紹了 Dart 中對象相等的機制,以及自定義類對象相等判斷的注意事項响逢。大部分情況下绒窑,我們不會需要自己覆蓋對象相等判斷,但是在某些場合需要用到的時候龄句,請遵循這些建議回论,以避免出現莫名其妙的問題散罕。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末分歇,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子欧漱,更是在濱河造成了極大的恐慌职抡,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件误甚,死亡現場離奇詭異缚甩,居然都是意外死亡谱净,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門擅威,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壕探,“玉大人,你說我怎么就攤上這事郊丛±钋耄” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵厉熟,是天一觀的道長导盅。 經常有香客問我,道長揍瑟,這世上最難降的妖魔是什么白翻? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮绢片,結果婚禮上滤馍,老公的妹妹穿的比我還像新娘。我一直安慰自己底循,他們只是感情好纪蜒,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著此叠,像睡著了一般纯续。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灭袁,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天猬错,我揣著相機與錄音,去河邊找鬼茸歧。 笑死倦炒,一個胖子當著我的面吹牛,可吹牛的內容都是我干的软瞎。 我是一名探鬼主播逢唤,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼涤浇!你這毒婦竟也來了鳖藕?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤只锭,失蹤者是張志新(化名)和其女友劉穎著恩,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡喉誊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年邀摆,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伍茄。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡栋盹,死狀恐怖,靈堂內的尸體忽然破棺而出敷矫,到底是詐尸還是另有隱情贞盯,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布沪饺,位于F島的核電站躏敢,受9級特大地震影響,放射性物質發(fā)生泄漏整葡。R本人自食惡果不足惜件余,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望遭居。 院中可真熱鬧啼器,春花似錦、人聲如沸俱萍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枪蘑。三九已至损谦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岳颇,已是汗流浹背照捡。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留话侧,地道東北人栗精。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瞻鹏,于是被迫代替她去往敵國和親悲立。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容